Sailing_12
asked on
Conditional sub-select
I have the original query in the code window below.
If the inner MIN select clause returns null, then I need to substitue the below conditional query instead.
**************************
Conditional query:
SELECT MAX(new_enddate)
FROM new_worklocationbiometrics
WHERE new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype
AND new_worklocationid = ( SELECT new_worklocationid
FROM contact
WHERE contactid = @contactid )
Original query:
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE new_enddate=(
SELECT MIN(new_enddate)
FROM new_worklocationbiometricscreenings
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = ( SELECT new_worklocationid
FROM contact
WHERE contactid = @contactid )
)
AND s.attributename = 'new_biometricscreeningtype'
no like this ...
just the one sub-select , but have a coalesce around the min/max with embedded cases...
.... are you sure that you don't want this sub-query correlated to the outer select?
you appear to be retrieving data for any contact... in the outer select but are looking for matches
against a specific contact in the sub-select....
just the one sub-select , but have a coalesce around the min/max with embedded cases...
.... are you sure that you don't want this sub-query correlated to the outer select?
you appear to be retrieving data for any contact... in the outer select but are looking for matches
against a specific contact in the sub-select....
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
Inner JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE new_enddate=(
SELECT coalesce((MIN(case when new_enddate >= convert(varchar(10),getdate(),120)
then new_enddate
end) ,
(max(case when new_enddate < convert(varchar(10),getdate(),120)
then new_enddate
end)
)
FROM new_worklocationbiometricscreenings
WHERE deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = ( SELECT new_worklocationid
FROM contact
WHERE contactid = @contactid )
)
AND s.attributename = 'new_biometricscreeningtype'
ASKER
I'm getting syntax errors with both of these that I haven't been able to firgure out.
Ultimately what I need to get is:
based on new_enddate of the new_worklocationbiometrics creenings table, the ONE record that either:
1. Has the soonest endate equal or greater than today(), OR that failing,
2. Has the latest endate less than today()
AND matches all the other criteria: deletionstatecode, screeningtype, worklocation.
Ultimately what I need to get is:
based on new_enddate of the new_worklocationbiometrics
1. Has the soonest endate equal or greater than today(), OR that failing,
2. Has the latest endate less than today()
AND matches all the other criteria: deletionstatecode, screeningtype, worklocation.
post the syntax errors....
please explain the actual scenario...
AND matches all the other criteria: deletionstatecode, screeningtype, worklocation.
it is hard to relate the above statement to your original query as what you've posted as an original working
code piece wouldn't seem to provide that ,,, unless your data/business process is doing something else
to ensure that the correct items are being matched....
please explain the actual scenario...
AND matches all the other criteria: deletionstatecode, screeningtype, worklocation.
it is hard to relate the above statement to your original query as what you've posted as an original working
code piece wouldn't seem to provide that ,,, unless your data/business process is doing something else
to ensure that the correct items are being matched....
ASKER
Here are the errors:
Msg 102, Level 15, State 1, Line 9
Incorrect syntax near ','.
Msg 102, Level 15, State 1, Line 20
Incorrect syntax near ')'.
************************** ********** ********** ********** ********** ********** ********** ********** ********** **
The original sub-query is returning the soonest future record (MIN(new_endate)) where:
1. new_endate >= today [line 10]
2. deletionstatecode <> 2 [line 11]
3. new_biometricscreeningtype IN (1,3,4) [line 12]
4. new_worklocationid = worklocationid from client's record in contact table [line 13]
This seems to be working correctly for us.
What we need to add, is when there is no record that matches the above (MIN function returns null), instead get the most recent 'past' record (MAX(new_endate)), that still meets the other conditions - i.e.
1. new_endate < today
2. deletionstatecode <> 2
3. new_biometricscreeningtype IN (1,3,4)
4. new_worklocationid = worklocationid from client's record in contact table
************************** ********** ********** ********** ********** ********** ********** ********** **********
So, the way I see it, the sub-select should either be:
SELECT MIN(new_enddate) as dt
FROM new_worklocationbiometrics creenings
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = @contactid)
<<<< OR >>>>
SELECT MAX(new_enddate)
FROM new_worklocationbiometrics creenings
WHERE new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = @contactid)
Depending on whether or not the first one actually returns a value.
If there is a more concise or efficient way to code this, great... but ultimately I need the startdate, enddate, and translation of the screeningtype (from stringmap) of the one record in that is either the soonest future enddate, or that failing the most recent past enddate and meets the other three conditions, in either case.
Hope this helps clear it up.
Msg 102, Level 15, State 1, Line 9
Incorrect syntax near ','.
Msg 102, Level 15, State 1, Line 20
Incorrect syntax near ')'.
**************************
The original sub-query is returning the soonest future record (MIN(new_endate)) where:
1. new_endate >= today [line 10]
2. deletionstatecode <> 2 [line 11]
3. new_biometricscreeningtype
4. new_worklocationid = worklocationid from client's record in contact table [line 13]
This seems to be working correctly for us.
What we need to add, is when there is no record that matches the above (MIN function returns null), instead get the most recent 'past' record (MAX(new_endate)), that still meets the other conditions - i.e.
1. new_endate < today
2. deletionstatecode <> 2
3. new_biometricscreeningtype
4. new_worklocationid = worklocationid from client's record in contact table
**************************
So, the way I see it, the sub-select should either be:
SELECT MIN(new_enddate) as dt
FROM new_worklocationbiometrics
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = @contactid)
<<<< OR >>>>
SELECT MAX(new_enddate)
FROM new_worklocationbiometrics
WHERE new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = @contactid)
Depending on whether or not the first one actually returns a value.
If there is a more concise or efficient way to code this, great... but ultimately I need the startdate, enddate, and translation of the screeningtype (from stringmap) of the one record in that is either the soonest future enddate, or that failing the most recent past enddate and meets the other three conditions, in either case.
Hope this helps clear it up.
ASKER
This query below actually provides the correct results, but I am not entirely sure it is the best way to go about it.
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE new_enddate=(
SELECT MAX(dt) from
(
SELECT MIN(new_enddate) as dt
FROM new_worklocationbiometricscreenings
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = '" + Request.QueryString["id"] + "' )
UNION
SELECT MAX(new_enddate)
FROM new_worklocationbiometricscreenings
WHERE new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = '" + Request.QueryString["id"] + "')
) x
)
AND s.attributename = 'new_biometricscreeningtype'
Your query appears to be a complicated version of essentially the following -
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE new_enddate=(
SELECT MAX(dt) as dt
FROM new_worklocationbiometricscreenings
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (SELECT new_worklocationid FROM contact WHERE contactid = '" + Request.QueryString["id"] + "' )
)
AND s.attributename = 'new_biometricscreeningtype'
Actually please ignore my post, my interpretation was incorrect!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
reb73 - I think your version will return no records because lines 8 & 9 will never be met - new_enddate cannot be >= AND < today at the same time.
This aside, you've removed the logic that gets only the one earliest future date, and the one most recent past date.
This aside, you've removed the logic that gets only the one earliest future date, and the one most recent past date.
ASKER
Lowfat - that seems to work and is more elegant than my solution. I will put it into our test environment and test it.
The outer query is not contact-specific, it is basically just getting the start and end dates and translating the value of the screeningtype of the screening event we've already identified in the sub-query.
Any given screening event is available to many clients based on their worklocation.
The outer query is not contact-specific, it is basically just getting the start and end dates and translating the value of the screeningtype of the screening event we've already identified in the sub-query.
Any given screening event is available to many clients based on their worklocation.
An alternative way in case you are on SQL Server 2005 or higher -
(Not 100% sure if this is more efficient than lowfatspread's solution, but the CTE picks the two nearest days to current date using a difference in seconds and automatically uses the minimum of these values which I think is what you are looking for. Do try this out and compare the execution plans vis-a-vis the other solution and let us know!)
(Not 100% sure if this is more efficient than lowfatspread's solution, but the CTE picks the two nearest days to current date using a difference in seconds and automatically uses the minimum of these values which I think is what you are looking for. Do try this out and compare the execution plans vis-a-vis the other solution and let us know!)
;WITH CTE (dt, diff)
AS
( SELECT Top 2 dt, abs(datediff(second, getdate(), dt)) as diff
FROM new_worklocationbiometricscreenings
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype IN (1,3,4)
AND new_worklocationid = (1) SELECT new_worklocationid FROM contact WHERE contactid = '" + Request.QueryString["id"] + "' )
order by 2
)
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE s.attributename = 'new_biometricscreeningtype'
and new_enddate=(select min(dt) from cte)
ok should work then ....
you may find that this works better since it "avoids" the NOT EQUALS test in the where clause...
you may find that this works better since it "avoids" the NOT EQUALS test in the where clause...
SELECT s.value, new_startdate, new_enddate
FROM new_worklocationbiometricscreenings w
Inner JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningtype
WHERE new_enddate=(
SELECT coalesce( MIN(case deletionstatecode when 2 then null else case
when new_enddate >= convert(char(8),getdate(),112)
then new_enddate
end end) ,
max(case deletionstatecode when 2 then null else case
when new_enddate < convert(char(8),getdate(),112)
then new_enddate
end end)
)
FROM new_worklocationbiometricscreenings as b
Inner join contact as c
on b.new_worklocationid=c.new_worklocationid
WHERE new_biometricscreeningtype IN (1,3,4)
and c.contactid = @contactid
)
AND s.attributename = 'new_biometricscreeningtype'
FROM new_worklocationbiometrics
JOIN stringmap s
ON s.attributevalue = w.new_biometricscreeningty
WHERE new_enddate=isnull (
(
SELECT MIN(new_enddate)
FROM new_worklocationbiometrics
WHERE new_enddate >= CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype
AND new_worklocationid = ( SELECT new_worklocationid
FROM contact
WHERE contactid = @contactid )
),
SELECT MAX(new_enddate)
FROM new_worklocationbiometrics
WHERE new_enddate < CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(),120), 120)
AND deletionstatecode <> 2
AND new_biometricscreeningtype
AND new_worklocationid = ( SELECT new_worklocationid
FROM contact
WHERE contactid = @contactid )
)
AND s.attributename = 'new_biometricscreeningtyp