0

文字列として保存されている日付をフィルター処理する必要があるデータ セットがあります (ソース列を DateTime に変更することはオプションではありません。このデータは、制御できないサード パーティのソースからのものです)。

日付の 1 つの形式が正しくないため、次のクエリを実行すると 1 つの結果が得られます

select ClientID, StartDate from boarding_appts where isdate(StartDate) = 0

ClientID   StartDate
---------- --------------------
5160       5/6/210 12:00:00

すると、 「式をデータ型日時に変換する算術オーバーフローエラーcast(StartDate as datetime)」が表示されます。これは予想通りでした。単独でフィルタリングすると、すべて正常に動作しますIsDate

select ClientID, cast(StartDate as dateTime) as StartDateCast, datediff(year, cast(StartDate as dateTime), getdate()) as age  from boarding_appts where isdate(StartDate) = 1

ClientID   StartDate               age
---------- ----------------------- ----------
10207      2012-06-09 12:00:00.000 1
2843       2012-06-23 12:00:00.000 1
2843       2012-06-23 12:00:00.000 1
8292       2012-05-11 12:00:00.000 1
7935       2012-04-24 12:00:00.000 1
... (1000's of more rows) ...

これが私の問題です:

レコードを除外して、1 年以上前のレコードのみが表示されるようにしたいのですが、どのようにフィルターを実行しようとしても、これらのクエリのすべてで算術オーバーフロー エラーが発生します。

select ClientID, cast(StartDate as dateTime) as StartDateCast, datediff(year, cast(StartDate as dateTime), getdate()) as age  
from boarding_appts 
where isdate(StartDate) = 1 
    and datediff(year, cast(StartDate as dateTime), getdate()) < 1 --If you comment out this line it works fine

select * 
from (select ClientID, cast(StartDate as dateTime) as StartDateCast, datediff(year, cast(StartDate as dateTime), getdate()) as age  from boarding_appts where isdate(StartDate) = 1) as Filtered
where age < 1 --If you comment out this line it works fine

select * 
from (select ClientID, cast(StartDate as dateTime) as StartDateCast  from boarding_appts where isdate(StartDate) = 1) as Filtered
where datediff(year, StartDateCast, getdate()) < 1 --If you comment out this line it works fine

;with Filtered as
(select ClientID, cast(StartDate as dateTime) as StartDateCast  from boarding_appts where isdate(StartDate) = 1)
select * from Filtered
where datediff(year, StartDateCast, getdate()) < 1 --If you comment out this line it works fine

;with Filtered as
(select ClientID, cast(StartDate as dateTime) as StartDateCast, datediff(year, cast(StartDate as dateTime), getdate()) as age  from boarding_appts where isdate(StartDate) = 1)
select * from Filtered
where age < 1 --If you comment out this line it works fine

これは、SQL Fiddle に関するデータのテスト セットで、ソリューションを試すことができます。これを修正する方法についてのアイデアがありません。私が考えることができる唯一の解決策は、最初に一時テーブルを選択してから選択することでした

select ClientID, StartDate, cast(StartDate as dateTime) as StartDateCast, datediff(year, cast(StartDate as dateTime), getdate()) as age  
into #t
from boarding_appts 
where isdate(StartDate) = 1 

select * from #t where age < 1 --Works.
4

2 に答える 2

4

SQL は宣言型言語です。SQL オプティマイザーはwhere、元の意味を保持している限り、節の一部を自由に再配置できます。そのため、最初に指定してもdatediff前に実行できます。サブクエリや CTE も書き直すことができるため、確実な解決策はありません。isdateisdate

コメントの Aaron Bertrand からの 2 番目の提案:

WHERE   CASE ISDATE(StartDate) 
        WHEN 1 THEN StartDate 
        ELSE '19000101' 
        END >= DATEADD(YEAR, -1, GETDATE());

StartDateの場合、SQL Server がdatetime にキャストする可能性を低くしますISDATE = 0。それが最善の解決策のようです。

この回答コミュニティ wiki にマークを付けました。Aaran Bertrand が回答を投稿した場合は、それを受け入れてください :)

于 2013-05-10T17:12:24.743 に答える