最初の問題は、日付を文字列列に格納していることです。DATE
またはを使用しないのはなぜDATETIME
ですか? d/m/y 形式を維持するためにこれを行っている場合は、それをやめてください。フォーマットはプレゼンテーション層の責任であり、ストレージに影響を与えるべきではありません。また、なぜ使用しているのNVARCHAR
ですか?Unicode を必要とする日付リテラルでは、どのような記号が予想されますか?
次は、適切な検証が行われておらず、列に不適切なデータが含まれていることです。この不良データは次のように識別できます。
SET DATEFORMAT DMY;
SELECT * FROM dbo.table
WHERE ISDATE(postdate) = 0;
NULL
ここで、クエリが 0 行を返すまで、データが何であるかがわかったら更新するか、それらの行を に設定して、そのデータを修正します。
明らかに D/M/Y 形式ではない 11/13/2013 のようなデータがある可能性があることに注意してください。この場合、有効に見えるが 06/09を入力したユーザーが行ったデータもある可能性があることに注意してください。 /2013 は 6 月 9 日または 9 月 6 日を意味しますか? どうすれば確信できますか?
この問題が明日再び発生するのを防ぐ最も安全な方法は、新しい列を追加し、データを移動し、古い列を削除し、すべてのレイヤーで文字列の使用を停止することです。
ALTER TABLE dbo.table
ADD d DATE;
UPDATE dbo.table
SET d = CONVERT(DATETIME, postdate, 103);
ALTER TABLE dbo.table
DROP COLUMN postdate;
EXEC sp_rename N'dbo.table.d', N'postdate', N'COLUMN';
次のように、このスワッピングをすべて行わなくても、インラインで実行できる場合があります。
SET DATEFORMAT DMY; -- the key you missed in your attempt I think
ALTER TABLE dbo.table ALTER COLUMN postdate DATE;
列自体を修正できない場合は、少なくともこの列にチェック制約と検証を追加して、明日不良データが戻ってこないようにすることを検討してください。例えば:
ALTER TABLE dbo.table
ADD CONSTRAINT prevent_bad_dates
CHECK (CONVERT(DATE, postdate, 103) >= '19000101');
挿入を実行するストアド プロシージャに varchar パラメータを使用すると仮定すると、挿入前の検証:
ALTER PROCEDURE dbo.whatever
@postdate NVARCHAR(10), -- assuming here
@other_params...
AS
BEGIN
SET NOCOUNT ON;
SET DATEFORMAT DMY;
IF ISDATE(@postdate) = 0
BEGIN
RAISERROR('Incorrect format for date: %s.', 11, 1, @postdate);
RETURN;
END
... perform insert...
END
これでも06/09/2013
、ユーザーが入力したのが6 月 9 日か 9 月 6 日かを理解するのに役立ちません。そのため、フリーハンドのアドホック エントリをユーザーから遠ざけて、カレンダー コントロールや日付ピッカーなどを使用するように強制することをお勧めします。そうすれば、フォーマットを完全に制御できます。文字列リテラルを SQL Server に送信する必要がある場合、最も安全な形式はYYYYMMDD
. BETWEEN
また、無制限の範囲の代わりに使用する場合の潜在的な問題に注意する必要があります。次の投稿をお読みください。