MedtronicVascSR
asked on
SQL Query Using UNION/EXISTS/INTERSECT To Gather Common Data on Same Tables
Hi,
I've attempted a few possible ways to write this query, but I'm either missing something simple, or it's more complicated than my current SQL skills can handle. In a nutshell the user has an expanded search page where they can select various criteria. I dynamically build the where clause portion of the query to produce the results based on their selections. There are 2 tables (one to many relationship). If they only make one selection the query looks like snippet 1, 2 selections looks like snippet 2, etc. Using the "AND" operator in snippet 2 produces zero results because as you'll see the same column is being referenced for the passed data. Using the "OR" brings back everything, but I want what is common among all of the user's selection.
"UNION" doesn't work (snippet 3) because it brings back everything for each query and I would like what is common among each. I tried using "INTERSECT", but as I understand it it is only functional in the Analysis Services feature of SQL Server (correct me if I'm wrong on this). At least setting it up provoked a syntax error in SQL Server Management Studio. I also tried employing "EXISTS", but I seem to get the same results as with "UNION" when working with multiple selection choices (snippet 4).
Anyway, could someone point me in the right direction? The key element here is that what would traditonal an easy situation is complicated by the fact that I'm working with fields that are not set up as columns but are instead dynamic rows of data (Book2.xls, which is produced by the UNION query. I highlighted the records that I'd like to come back since they contain both selection choices by the user). "Study_Template_Item" would be considered the column if it were a "hard coded" field.
Cheers,
Ty
PS: I'm using SQL Server 2008
I've attempted a few possible ways to write this query, but I'm either missing something simple, or it's more complicated than my current SQL skills can handle. In a nutshell the user has an expanded search page where they can select various criteria. I dynamically build the where clause portion of the query to produce the results based on their selections. There are 2 tables (one to many relationship). If they only make one selection the query looks like snippet 1, 2 selections looks like snippet 2, etc. Using the "AND" operator in snippet 2 produces zero results because as you'll see the same column is being referenced for the passed data. Using the "OR" brings back everything, but I want what is common among all of the user's selection.
"UNION" doesn't work (snippet 3) because it brings back everything for each query and I would like what is common among each. I tried using "INTERSECT", but as I understand it it is only functional in the Analysis Services feature of SQL Server (correct me if I'm wrong on this). At least setting it up provoked a syntax error in SQL Server Management Studio. I also tried employing "EXISTS", but I seem to get the same results as with "UNION" when working with multiple selection choices (snippet 4).
Anyway, could someone point me in the right direction? The key element here is that what would traditonal an easy situation is complicated by the fact that I'm working with fields that are not set up as columns but are instead dynamic rows of data (Book2.xls, which is produced by the UNION query. I highlighted the records that I'd like to come back since they contain both selection choices by the user). "Study_Template_Item" would be considered the column if it were a "hard coded" field.
Cheers,
Ty
PS: I'm using SQL Server 2008
snippet 1
SELECT
PreclinicalStudyMaster.Preclinical_Study_Master_ID, PreclinicalStudyMaster.Preclinical_Study_Master_Code_ID,
PreclinicalStudyItems.Study_Template_Item, PreclinicalStudyItems.Study_Template_Item_Value
FROM PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Preclinical_Study_Master_ID = PreclinicalStudyMaster.Preclinical_Study_Master_ID
WHERE
(PreclinicalStudyItems.Study_Template_Item = 'Device Comments') AND
(PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Device%')
UNION
SELECT
PreclinicalStudyMaster.Preclinical_Study_Master_ID, PreclinicalStudyMaster.Preclinical_Study_Master_Code_ID,
PreclinicalStudyItems.Study_Template_Item, PreclinicalStudyItems.Study_Template_Item_Value
FROM PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Preclinical_Study_Master_ID = PreclinicalStudyMaster.Preclinical_Study_Master_ID
WHERE
(PreclinicalStudyItems.Study_Template_Item = 'Director' AND
PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Dawn%')
ORDER BY PreclinicalStudyMaster.Preclinical_Study_Master_ID
snippet 2
SELECT
PreclinicalStudyMaster.Preclinical_Study_Master_ID,
PreclinicalStudyMaster.Preclinical_Study_Master_Code_ID,
PreclinicalStudyItems.Study_Template_Item,
PreclinicalStudyItems.Study_Template_Item_Value
FROM
PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Preclinical_Study_Master_ID = PreclinicalStudyMaster.Preclinical_Study_Master_ID
WHERE
(PreclinicalStudyItems.Study_Template_Item = 'Device Comments' AND PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Device%')
AND
(PreclinicalStudyItems.Study_Template_Item = Director' AND PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Dawn%')
snippet 4
SELECT
PreclinicalStudyMaster.Preclinical_Study_Master_ID,
PreclinicalStudyMaster.Preclinical_Study_Master_Code_ID,
PreclinicalStudyItems.Study_Template_Item,
PreclinicalStudyItems.Study_Template_Item_Value
FROM
PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Preclinical_Study_Master_ID = PreclinicalStudyMaster.Preclinical_Study_Master_ID
WHERE
(PreclinicalStudyItems.Study_Template_Item = 'Device Comments' AND PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Device%')
snippet 3
SELECT
a.Preclinical_Study_Master_ID, a.Preclinical_Study_Master_Code_ID
FROM PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster AS a ON
PreclinicalStudyItems.Preclinical_Study_Master_ID = a.Preclinical_Study_Master_ID
WHERE EXISTS
(
SELECT * FROM PreclinicalStudyItems AS b
WHERE a.Preclinical_Study_Master_ID = b.Preclinical_Study_Master_ID AND
(PreclinicalStudyItems.Study_Template_Item = 'Device Comments' AND
PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Device%')
)
AND
EXISTS
(
SELECT * FROM PreclinicalStudyItems AS c
WHERE a.Preclinical_Study_Master_ID = c.Preclinical_Study_Master_ID AND
(PreclinicalStudyItems.Study_Template_Item = 'Director' AND
PreclinicalStudyItems.Study_Template_Item_Value LIKE '%Dawn%')
)
Book2.xls
Actually, I do see a problem with my suggestion in that rows will be returned for item='Director' and value like '%Device%', which would not be correct, but would only be a problem if such rows exist. But it is a flaw in principle.
Ok, this:
WHERE
(PreclinicalStudyItems.Stu dy_Templat e_Item = 'Device Comments' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Device%')
AND
(PreclinicalStudyItems.Stu dy_Templat e_Item = Director' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Dawn%')
will return all records where Study_Template_Item is both 'Device Comments' and 'Director' (I'm assuming you're missing a '). Seeing as the same field can't be both values, it will always return 0 records.
(PreclinicalStudyItems.Stu dy_Templat e_Item = 'Device Comments' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Device%')
OR
(PreclinicalStudyItems.Stu dy_Templat e_Item = Director' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Dawn%')
This would return the records where Study_Template_Item is either 'Device Comments' or 'Director' (along with the other conditions, but the logic is the same).
WHERE
(PreclinicalStudyItems.Stu
AND
(PreclinicalStudyItems.Stu
will return all records where Study_Template_Item is both 'Device Comments' and 'Director' (I'm assuming you're missing a '). Seeing as the same field can't be both values, it will always return 0 records.
(PreclinicalStudyItems.Stu
OR
(PreclinicalStudyItems.Stu
This would return the records where Study_Template_Item is either 'Device Comments' or 'Director' (along with the other conditions, but the logic is the same).
To clarify, what you have in snippet 2 would always be empty. But if you replace it with the OR I suggested, it should work. Unless you want some other result returned, in which case you should clarify what you expect to get.
ASKER
Hi,
Yes, my copy paste to this post somehow omitted the single quote around "Director"
Yes, "OR" does bring back everything. However, the result set I would like back are the records that meet both the user's selection requirments, 'Device Comments' that have the phrase "Device" in it as well as 'Director' that has the phrase "Dawn" in it. So instead of getting back the 42 or so records that meets each of the requirements individually there should be 3 records that meet both requirements.
Cheers,
Ty
Yes, my copy paste to this post somehow omitted the single quote around "Director"
Yes, "OR" does bring back everything. However, the result set I would like back are the records that meet both the user's selection requirments, 'Device Comments' that have the phrase "Device" in it as well as 'Director' that has the phrase "Dawn" in it. So instead of getting back the 42 or so records that meets each of the requirements individually there should be 3 records that meet both requirements.
Cheers,
Ty
The answer is to build your SQL statement dynamically.
you can build it dynamically as a string like so :-
declare @strSQL nvarchar(4000)
declare @intCriteria int
Set @strSQL="SELECT
PreclinicalStudyMaster.Pre clinical_S tudy_Maste r_ID, PreclinicalStudyMaster.Pre clinical_S tudy_Maste r_Code_ID,
PreclinicalStudyItems.Stud y_Template _Item, PreclinicalStudyItems.Stud y_Template _Item_Valu e
FROM PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Prec linical_St udy_Master _ID = PreclinicalStudyMaster.Pre clinical_S tudy_Maste r_ID
WHERE "
@strSQL=@strSQL + " (PreclinicalStudyItems.Stu dy_Templat e_Item = 'Device Comments') AND
(PreclinicalStudyItems.Stu dy_Templat e_Item_Val ue LIKE '%Device%') "
Then for each filter criteria you add one of these babys :-
If @intCriteria>1
BEGIN
@strSQL = @strSQL + " OR "
"(PreclinicalStudyItems.St udy_Templa te_Item = 'Director' AND
PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Dawn%')"
END
If @intCriteria>2
BEGIN
@strSQL = @strSQL + " OR "
"(PreclinicalStudyItems.St udy_Templa te_Item = 'Somthing else' AND
PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Ano Value%')"
END
And so on and so forth
Then run the SQL with :-
Exec ( @strSQL)
One thing though you will need to make sure a hacker does not exploit this system as any other SQL can be added to the end like so
@strSQL = @strSQL + "; DELETE FROM PreclinicalStudyMaster "
Bye for now and "Free Gary Mkenna Now!!
you can build it dynamically as a string like so :-
declare @strSQL nvarchar(4000)
declare @intCriteria int
Set @strSQL="SELECT
PreclinicalStudyMaster.Pre
PreclinicalStudyItems.Stud
FROM PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Prec
WHERE "
@strSQL=@strSQL + " (PreclinicalStudyItems.Stu
(PreclinicalStudyItems.Stu
Then for each filter criteria you add one of these babys :-
If @intCriteria>1
BEGIN
@strSQL = @strSQL + " OR "
"(PreclinicalStudyItems.St
PreclinicalStudyItems.Stud
END
If @intCriteria>2
BEGIN
@strSQL = @strSQL + " OR "
"(PreclinicalStudyItems.St
PreclinicalStudyItems.Stud
END
And so on and so forth
Then run the SQL with :-
Exec ( @strSQL)
One thing though you will need to make sure a hacker does not exploit this system as any other SQL can be added to the end like so
@strSQL = @strSQL + "; DELETE FROM PreclinicalStudyMaster "
Bye for now and "Free Gary Mkenna Now!!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Ok, what you need is to build dinamically but slightly different:
WHERE
(PreclinicalStudyItems.Stu dy_Templat e_Item LIKE '%Device Comments%' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Device%')
AND
(PreclinicalStudyItems.Stu dy_Templat e_Item = LIKE '%Director%' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Dawn%')
From what you said, I'm assuming this is what you want. The field will have something like: 'blah blah text Device Comments blah blah more text Director blah text'. If so, this will catch it. Instead of trying for a perfect match with =, you have to use LIKE instead.
WHERE
(PreclinicalStudyItems.Stu
AND
(PreclinicalStudyItems.Stu
From what you said, I'm assuming this is what you want. The field will have something like: 'blah blah text Device Comments blah blah more text Director blah text'. If so, this will catch it. Instead of trying for a perfect match with =, you have to use LIKE instead.
ASKER
Cluskitt, I thought you might have had something there, but unfortunately, nothing comes back.
Cheers,
Ty
Cheers,
Ty
Sorry, my bad... not:
...)
AND
(...
but
...)
OR
(...
...)
AND
(...
but
...)
OR
(...
er... nevermind... not OR. I meant:
WHERE
(PreclinicalStudyItems.Stu dy_Templat e_Item LIKE '%Device Comments%' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Device%')
AND
(PreclinicalStudyItems.Stu dy_Templat e_Item LIKE '%Director%' AND PreclinicalStudyItems.Stud y_Template _Item_Valu e LIKE '%Dawn%')
What this will do is: if Study_Template_Item has both 'Device Comments' and 'Director' AND Study_Template_Item_Value has both 'Device' and 'Dawn', then it will return a record. Note that, if Study_Template_Item has both values, but Study_Template_Item_Value has only onw, then it won't return anything.
WHERE
(PreclinicalStudyItems.Stu
AND
(PreclinicalStudyItems.Stu
What this will do is: if Study_Template_Item has both 'Device Comments' and 'Director' AND Study_Template_Item_Value has both 'Device' and 'Dawn', then it will return a record. Note that, if Study_Template_Item has both values, but Study_Template_Item_Value has only onw, then it won't return anything.
Also, you should debug that the info is there. Try first:
SELECT *
FROM
PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Prec linical_St udy_Master _ID = PreclinicalStudyMaster.Pre clinical_S tudy_Maste r_ID
And check for some cases where it should return after you add the WHERE clause. Then you can try debugging why it doesn't return any records.
SELECT *
FROM
PreclinicalStudyItems INNER JOIN
PreclinicalStudyMaster ON PreclinicalStudyItems.Prec
And check for some cases where it should return after you add the WHERE clause. Then you can try debugging why it doesn't return any records.
The expert is correct as AND is what you need.
ASKER
Cluskitt, the last query you posted looks the same as what you posted 3 postings back.
Yes, I have verified there are records that match the individual queries. My file upload, Book2.xls, shows the output from a UNION query, which would represent 2 individual searches.
NigelBulley, ok, but using "AND" produces no results, and I have verified that I would get back 3 records if we have structured it correctly.
The big challenge here, and we may be going about this the wrong way, is that we're trying to pass mulitple values to the same column, Study_Template_Item and telling it to be more than one thing at a time. I'm not sure how to get around this obstacle. I almost need a subset of the UNION query, or what INTERSECT purports to do.
Cheers,
Ty
Yes, I have verified there are records that match the individual queries. My file upload, Book2.xls, shows the output from a UNION query, which would represent 2 individual searches.
NigelBulley, ok, but using "AND" produces no results, and I have verified that I would get back 3 records if we have structured it correctly.
The big challenge here, and we may be going about this the wrong way, is that we're trying to pass mulitple values to the same column, Study_Template_Item and telling it to be more than one thing at a time. I'm not sure how to get around this obstacle. I almost need a subset of the UNION query, or what INTERSECT purports to do.
Cheers,
Ty
I'm not sure what the original data is like and how it returned those values. Can you post some examples, please? The problem is that we're not really understanding how the data is in the database, so we can select the correct query. If I'm not mistaken, what you want can be done with multiple exists. But you're saying you want what's common, so I'm not sure what's expected.
ASKER
Hi,
I've attached what the data looks like raw from the 2 tables when they are joined in their one to many relationship. Study_Template_Item is the name of the field and Study_Template_Item_Value is what the user has entered for that field name. This is all done via another interface and not the search interface I'm referencing for my question.
I've highlighted what one "Study" record looks like in the database. Remember, columns names are now rows of data.
Hope this adds clarification.
Cheers,
Ty
Book3.xls
I've attached what the data looks like raw from the 2 tables when they are joined in their one to many relationship. Study_Template_Item is the name of the field and Study_Template_Item_Value is what the user has entered for that field name. This is all done via another interface and not the search interface I'm referencing for my question.
I've highlighted what one "Study" record looks like in the database. Remember, columns names are now rows of data.
Hope this adds clarification.
Cheers,
Ty
Book3.xls
ASKER
Hi,
I think I've worked out one solution. Based on the number of selections a user makes on the search criteria interface I can test for the number of matches it makes like the following snippet. The 2 at the end is dynamic based on the number of filters that are dynamically used. Once I get this then I can run my original query to bring back those studies that match the study ID.
Cheers,
Ty
I think I've worked out one solution. Based on the number of selections a user makes on the search criteria interface I can test for the number of matches it makes like the following snippet. The 2 at the end is dynamic based on the number of filters that are dynamically used. Once I get this then I can run my original query to bring back those studies that match the study ID.
Cheers,
Ty
SELECT COUNT(Preclinical_Study_Master_ID), Preclinical_Study_Master_Code_ID
FROM
(
SELECT
A.Preclinical_Study_Master_ID, A.Preclinical_Study_Master_Code_ID,
AA.Study_Template_Item, AA.Study_Template_Item_Value
FROM PreclinicalStudyItems AA INNER JOIN
PreclinicalStudyMaster A ON AA.Preclinical_Study_Master_ID = A.Preclinical_Study_Master_ID
WHERE
(AA.Study_Template_Item = 'Device Comments') AND
(AA.Study_Template_Item_Value LIKE '%Device%')
UNION ALL
SELECT
B.Preclinical_Study_Master_ID, B.Preclinical_Study_Master_Code_ID,
BB.Study_Template_Item, BB.Study_Template_Item_Value
FROM PreclinicalStudyItems BB INNER JOIN
PreclinicalStudyMaster B ON BB.Preclinical_Study_Master_ID = B.Preclinical_Study_Master_ID
WHERE
(BB.Study_Template_Item = 'Director' AND
BB.Study_Template_Item_Value LIKE '%Dawn%')
)
TMP
GROUP BY
Preclinical_Study_Master_Code_ID,
Preclinical_Study_Master_Code_ID
HAVING COUNT(Preclinical_Study_Master_ID) = 2
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I object on one simple thing:
You shouldn't delete this question. If you think your answer is the best solution, then ask for a refund, but add your answer to the database, so other people will know what to do if they have a similar issue in the future.
And no one needs the points anyway :)
You shouldn't delete this question. If you think your answer is the best solution, then ask for a refund, but add your answer to the database, so other people will know what to do if they have a similar issue in the future.
And no one needs the points anyway :)
ASKER
Thanks Cluskitt. I don't believe I deleted anything. I left the checkbox "checked" where it read, "Add question to Knowledge Base".
Cheers,
Ty
Cheers,
Ty
Well, the message said the question was about to be deleted in 4 days. You must have hit that instead. If you can't award your own answer, hit the request attention button on top and ask a mod for it. :)
ASKER
Thanks again Cluskitt. Your alternative works too so I awarded you half the original points. In the end I decided to go with my solution only because it does not require creating and incrementing a dynamic alias for each potential "INNER JOIN" that reflects the number of search filters the user chooses.
Cheers,
Ty
Cheers,
Ty
WHERE (PreclinicalStudyItems.Stu
AND ((PreclinicalStudyItems.St