1

nvarchar(MAX)私はフォーマットで日付を占めるいくつかのフィールドを持つテーブルを持っていdd/mm/yyyyます。

私はこのクエリを実行します:

SELECT CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]

そして、私はエラーを受け取ります:

nvarcharデータ型を日時データ型に変換すると、値が範囲外になりました。

奇妙なことに、このクエリを次のように実行すると、次のようになります。

SELECT TOP 40 CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]

それは動作しますが、私はしたくありませんTOP X

私のテーブルには36レコードしか含まれていません。だから悪いデータはないと思います。

20/03/2013
20/03/2013
10/03/2013
10/03/2013
11/03/2013
06/03/2013
06/03/2013
21/03/2013
12/03/2013
03/03/2013
18/03/2013
04/03/2013
28/02/2013
28/02/2013
28/02/2013
28/02/2013
31/01/2013
15/01/2013
23/01/2013
23/01/2013
31/01/2013
23/01/2013
30/01/2013
31/01/2013
24/01/2013
24/01/2013
24/01/2013
24/01/2013
24/01/2013
30/01/2013
23/01/2013
22/01/2013
23/01/2013
23/01/2013
23/01/2013
23/01/2013

誰かがそれを手伝ってくれますか?

4

3 に答える 3

13

不適切なデータ型を使用し続け、あらゆる種類のゴミをテーブルに入れることを可能にする、すばやく簡単で怠惰な方法

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/20137 月 4 日に入国した場合、4 月 7 日と誤って認識することになります。これが、地域形式が好きd/m/ym/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機能します。DATEDATETIME

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
于 2013-03-12T13:33:22.283 に答える
1

文字列型フィールドに日付を保存することはお勧めできません。ただし、現時点で対処する必要がある場合は、isdate()関数を使用してこのクエリを実行し、不良データをチェックして修正することができます。

SELECT [Start Date]
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
WHERE isdate([Start Date]) = 0

また、日付型に変換する前に日付を取得するとよいでしょう。それらがすべてフォーマットである場合、以下のように( )でそれらを取得できます。none culture specific ISO formatdd/mm/yyyyISO format'yyyymmdd'

SQL FIDDLE DEMO

declare @d varchar(max) = '20/03/2013'
select convert(datetime,right(@d,4) + substring(@d,4,2) + left(@d,2))

したがって、実際のクエリは次のようになります。

SELECT CONVERT(datetime,right([Start Date],4) + 
                               substring([Start Date],4,2) + 
                               left([Start Date],2))
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
于 2013-03-12T10:54:55.180 に答える
-4

これはTOP40とは何の関係もありません。つまり、上位40行に問題のあるデータがないということです。

テーブル内のデータが少ない場合は、制限を増やすだけで、エラーが発生している場所を見つけることができます。

元:

SELECT TOP 100 CONVERT(datetime,[Start Date],103)
FROM [YellowCard_NewDesign].[dbo].[vw_All_Requests]
于 2013-03-12T10:23:11.633 に答える