不適切なデータ型を使用し続け、あらゆる種類のゴミをテーブルに入れることを可能にする、すばやく簡単で怠惰な方法
SET DATEFORMAT DMY;
SELECT
-- other columns,
[Start Date] = CONVERT(DATETIME, CASE WHEN ISDATE([Start Date]) = 1
THEN [Start Date] END, 103)
FROM
dbo.vw_All_Requests;
さて、この場合NULL
、フォーマットに有効な日付が含まれていない列値に対して返されd/m/y
ます。これらの行を値とともに含めるのではなく除外する場合は、次の句NULL
を追加できます。WHERE
SET DATEFORMAT DMY;
SELECT
-- other columns,
[Start Date] = CONVERT(DATETIME, CASE WHEN ISDATE([Start Date]) = 1
THEN [Start Date] END, 103)
FROM
dbo.vw_All_Requests
WHERE ISDATE([Start Date]) = 1;
これができない理由は…
SELECT CONVERT(DATETIME, [Start Date], 103)
FROM ...
WHERE ISDATE([Start Date]) = 1;
...これは、SQL Server がCONVERT
フィルターの前に試行し、現在発生しているのと同じエラーが発生する可能性があるためです。式 (ほとんどのCASE
場合) を使用すると、その評価順序を制御できます。
もちろん、d/m/y
形式として有効な日付は、必ずしもユーザーが意図したものであるとは限りません。アメリカ人が07/04/2013
7 月 4 日に入国した場合、4 月 7 日と誤って認識することになります。これが、地域形式が好きd/m/y
でm/d/y
、良くない理由です。
不適切なデータ型を使用し続けながら、少し作業を増やすだけで、より多くのガベージがテーブルに入るのを防ぐ、すばやく簡単で怠惰な方法
上記のアドバイスに従って、準拠していないデータを修正または削除し、少なくともチェック制約を追加して、ジャンクがテーブルに入らないようにする必要があります。
ALTER TABLE dbo.SourceTable
ADD CONSTRAINT CK_SillyMaxColumnIsValidDate
CHECK (CONVERT(DATE, [Start Date], 103) >= '0001-01-01');
したがって、次の挿入は失敗または成功します。
-- these succeed:
INSERT dbo.SourceTable([Start Date]) SELECT '01/01/2005';
INSERT dbo.SourceTable([Start Date]) SELECT '25/01/2005';
GO
-- fails:
INSERT dbo.SourceTable([Start Date]) SELECT '01/25/2005';
GO
-- fails:
INSERT dbo.SourceTable([Start Date]) SELECT 'garbage';
失敗により、不適切な挿入が完全に防止d/m/y
され、テーブルへの有効な文字列のみが許可されます。エラーメッセージは次のとおりです。
メッセージ 241、レベル 16、状態 1、行 1
文字列から日付や時刻を変換するときに、変換に失敗しました。
正しい方法
まず、不良データを特定します。
SELECT [Start Date]
FROM dbo.vw_All_Requests
WHERE ISDATE([Start Date]) = 0;
次に、そのデータがどこから来ても、そのデータを修正して、データ型を修正できるようにします。これは、次のタイプのステートメントの組み合わせを意味する場合があります。
-- correct the date for specific bad values
UPDATE dbo.SourceTable
SET [Start Date] = '03/12/2012'
WHERE [Start Date] = 'whatever';
-- remove the value altogether for specific bad values
UPDATE dbo.SourceTable
SET [Start Date] = NULL
WHERE [Start Date] = 'whatever';
-- remove the row altogether for specific bad values
DELETE dbo.SourceTable
WHERE [Start Date] = 'whatever';
-- remove all rows with bad values
SET DATEFORMAT DMY;
DELETE dbo.SourceTable
WHERE ISDATE([Start Date]) = 0;
DATE
次に、ソース テーブルに列を追加します。
ALTER TABLE dbo.SourceTable
ADD StartDate -- no space!
DATE;
次に、その列のデータを更新します。
UPDATE dbo.SourceTable
SET StartDate = CONVERT(DATETIME, [Start Date], 103);
ここで、元の列を削除します (この列を含むインデックスまたはそれを参照する制約を調整する必要がある場合があります)。
ALTER TABLE dbo.SourceTable
DROP COLUMN [Start Date];
これで、新しい列名を変更できます。
EXEC sp_rename N'dbo.SourceTable.StartDate', 'Start Date', 'COLUMN';
またはビューを変更します。
ALTER VIEW dbo.vw_All_Requests
AS
SELECT
...
[Start Date] = StartDate
または、新しいより適切な列名を使用するようにアプリケーションを変更してください。すべてのデータ型パラメーターを変更して適切なデータ型を使用することも忘れないでください。文字列リテラルを渡すときは、d/m/y
. @Kaf のように、私は を好みyyyymmdd
ます。これは決して誤解されることはありませんが、常にyyyy-mm-dd
機能します。DATE
DATETIME
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '2012-03-15');
結果:
Msg 242, Level 16, State 3, Line 2
La conversion d'un type de données varchar en type de données datetime a créé une valeur hors limites.
いくつかの背景
この投稿を読んでください:
最後の注意として
スペースを含む列名または別名を作成するのはやめてください。視覚的な区切りが必要な場合は、アンダースコアを使用してください。これらは両方とも列名のより良い選択であり、意味を決して変更せず、すべての単一の参照の周りに醜い角括弧を必要としません:
Start_Date
StartDate