2

100万件以上のレコードがある大きなテーブルがあります。残念ながら、テーブルを作成した人は、varchar(50)フィールドに日付を入力することにしました。

簡単な日付比較を行う必要があります-

datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

しかし、それは失敗しますconvert()

Conversion failed when converting datetime from character string.

どうやらその分野には嫌いなものがあり、レコードが多いので見ただけではわかりません。日付フィールド全体を適切にサニタイズして、失敗しないようにするにはどうすればよいconvert()ですか?これが私が今持っているものです:

select count(*)
from MyTable
where
    isdate(lastUpdate) > 0
    and datediff(dd, convert(datetime, lastUpdate, 100), getDate()) < 31

@SQLMenace

この場合、パフォーマンスについては気にしません。これは1回限りのクエリになります。テーブルを日時フィールドに変更することはオプションではありません。

@Jon Limjap

3番目の引数を追加しようとしましたが、違いはありません。


@SQLMenace

問題は、データの保存方法にある可能性が最も高く、安全な形式は2つだけです。ISO YYYYMMDD; ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(スペースなし)

チェックはこれを処理しませんisdate()か?

100%の精度は必要ありません。過去30日間のレコードのほとんどを取得したいだけです。


@SQLMenace

select isdate('20080131') -- returns 1
select isdate('01312008') -- returns 0

@ブライアンシュカーケ

CASEとISDATEをCONVERT()関数内に配置します。

ありがとう!それはそれをしました。

4

10 に答える 10

8

CASEおよびを関数ISDATE内に配置しCONVERT()ます。

SELECT COUNT(*) FROM MyTable
WHERE
    DATEDIFF(dd, CONVERT(DATETIME, CASE IsDate(lastUpdate)
        WHEN 1 THEN lastUpdate
        ELSE '12-30-1899'
    END), GetDate()) < 31

'12-30-1899'選択したデフォルトの日付に置き換えます。

于 2008-08-26T14:27:08.053 に答える
3

カーソルを書き込んで内容をループし、エントリごとにキャストを試みてはどうでしょうか。エラーが発生した場合は、問題レコードの主キーまたはその他の識別詳細を出力してください。これを行うためのセットベースの方法は考えられません。

完全にセットベースではありませんが、100万行のうち3行だけが悪い場合は、多くの時間を節約できます

select * into BadDates
from Yourtable
where isdate(lastUpdate) = 0

select * into GoodDates
from Yourtable
where isdate(lastUpdate) = 1

次に、BadDatesテーブルを見て、それを修正します

于 2008-08-26T14:32:14.000 に答える
2

ISDATE()は、実際に最初に実行された場合に適切にフォーマットされなかった行を処理します。ただし、実行プランを見ると、おそらくDATEDIFF述語が最初に適用されていることがわかります。つまり、痛みの原因です。

SQL Server Management Studioを使用している場合は、 CTRL+Lを押して、特定のクエリの推定実行プランを表示します。

SQLは手続き型言語ではなく、短絡ロジックが機能する可能性があることを忘れないでください。ただし、SQLの適用方法に注意する必要があります。

于 2008-08-26T14:32:32.313 に答える
1

カーソルを書き込んでコンテンツをループし、各エントリのキャストを試みてはどうでしょうか。

エラーが発生した場合は、問題レコードの主キーまたはその他の識別の詳細を出力します。

これを行うためのセットベースの方法は考えられません。

編集-ああ、はい、ISDATE()を忘れました。カーソルを使用するよりも間違いなく優れたアプローチです。SQLMenaceに+1。

于 2008-08-26T14:24:18.870 に答える
0

このようなことをするので、混乱をクリーンアップして列を日時に変更することをお勧めします

WHERE datediff(dd, convert(datetime, lastUpdate), getDate()) < 31

インデックスを使用することはできず、日時列を持っていた場合よりも何倍も遅くなります。

where lastUpdate > getDate() -31

もちろん、時間と秒も考慮する必要があります

于 2008-08-26T14:12:26.980 に答える
0

convert呼び出しでは、このドキュメントで指定されているように、varcharとして格納される日時の形式などの3番目のスタイルパラメーターを指定する必要があります:CASTおよびCONVERT(T-SQL)

于 2008-08-26T14:13:25.277 に答える
0

レコードを印刷します。varchar(50)を使用することを決めた馬鹿にハードコピーを渡して、問題の記録を見つけるように依頼します。

次回は、適切なデータ型を選択するポイントがわかるかもしれません。

于 2008-08-26T14:14:09.737 に答える
0

問題は、データの保存方法にある可能性が最も高く、安全な形式は2つだけです。

ISO YYYYMMDD

ISO 8601 yyyy-mm-dd Thh:mm:ss:mmm(スペースなし)

これらはあなたの言語が何であれ機能します。

それを機能させるには、SET DATEFORMAT YMD(またはデータが保存されているもの)を実行する必要がある場合があります

于 2008-08-26T14:20:01.563 に答える
0

isdate()チェックはこれを処理しませんか?

これを実行して、何が起こるかを確認します

select isdate('20080131')
select isdate('01312008')
于 2008-08-26T14:27:31.343 に答える
0

テーブル/列を変更することは、従来のシステム要件のためにオプションではない可能性があると確信していますが、SQL のより新しいバージョンを使用している場合、日付変換ロジックが組み込まれたビューを作成することを考えたことがありますか?インデックス付きビューを使用することもできますか?

于 2009-03-14T15:11:30.507 に答える