问题
I am trying to clean up the where clause statement in the following code:
SELECT
CONVERT(datetime, [UTC_Time_Stamp], 127) AS TimeStamp
FROM
Table
WHERE
CASE
WHEN ISDATE([UTC_Time_Stamp]) = 1
THEN CONVERT(datetime, [UTC_Time_Stamp], 127)
ELSE CAST('1/1/1900' AS datetime)
END > CAST('11/09/2012' AS datetime)
AND
CASE
WHEN ISDATE([UTC_Time_Stamp]) = 1
THEN CONVERT(datetime, [UTC_Time_Stamp], 127)
ELSE CAST('1/1/3000' AS datetime)
END < CAST('11/10/2012' as datetime)
ORDER BY
TimeStamp;
UTC_Time_Stamp is stored as a string and is sometimes null. I was previously running into a conversion error inside my where clause. I fixed the error following advice from this question here, but I feel like there has to be a simpler way to achieve the same result.
回答1:
You need to do the conversion within a case statement. SQL is a descriptive language and does not guarantee the order of processing. So, a where clause does not necessarily happen before other processing, even when it is in a subquery or a CTE. However, SQL does guarantee the order of processing in a case statement (that contains no expressions with aggregation functions).
You can simplify your statement by using a subquery:
select TimeStamp
FROM (select t.*,
Case When ISDATE([UTC_Time_Stamp]) = 1 Then CONVERT(datetime, UTC_Time_Stamp, 127) end) as TimeStamp
from Table t
) t
WHERE coalesce(TimeStamp, cast('1/1/1900' as datetime)) > cast('11/09/2012' as datetime) and
coalesce(TimeStamp, cast('1/1/3000' as datetime)) < cast('11/10/2012' as datetime)
ORDER BY TimeStamp;
This does the conversion to TimeStamp, for valid values. You can then use the variable in the outer query.
I would also encourage you to get used to the ANSI standard format for dates (YYYYMMDD or YYYY-MM-DD) instead of ambiguous formats like '11/10/2012'. It may be clear to you that this means 2012-11-10 . . . or is that 2012-10-11 . . . but the format is ambiguous.
回答2:
I like CTEs for this, or you could also do temp tables, table variables or an inline derived table like @Derek.
Basically, we're going to grab the proper datatype first, and then have a much easier time creating our query:
;with CTE as (
-- Bring back the column as datetime
select case when isdate(UTC_Time_Stamp) = 1 then cast(UTC_Time_Stamp as datetime) end as UTC_Time_Stamp
from [Table]
)
-- Simple select with the proper datatype
select convert(varchar(50), UTC_Time_Stamp, 127) as [TimeStamp]
from CTE
-- May still need gt and lt functionality
where UTC_Time_Stamp between cast('11/09/2012' as datetime) and cast('11/10/2012' as datetime)
It seems like you're using some arbitrarily small and large values for TimeStamp when you have non-dates, which is probably unnecessary given your comparison, so I've removed them.
Note that I am using the datetime datatype in the CTE and for the comparison, only converting it to a string for presentation.
Also note that between is inclusive, so you might need to go back to your separate > and < where clause.
回答3:
It's easier to do something like this (using whatever convert/between clause in the predicate that you see fit):
SELECT CONVERT(datetime, [UTC_Time_Stamp], 127) as TimeStamp
FROM (
select [UTC_Time_Stamp]
from Table
WHERE ISDATE([UTC_Time_Stamp]) = 1
) a
WHERE
convert(datetime, [UTC_Time_Stamp], 127) between '11/9/2012' and '11/10/2012'
ORDER BY TimeStamp;
来源:https://stackoverflow.com/questions/13347582/using-case-statements-with-isdate-in-a-sql-where-clause