varcharデータ型をdatetimeデータ型に変換すると、範囲外の値が発生しました


8

11月に作成されたすべての行を取得する簡単なクエリを実行しようとしています。

SELECT COUNT(*)
FROM dbo.profile 
WHERE [Created] BETWEEN '2014-11-01 00:00:00.000' 
AND '2014-11-30 23:59:59.997';

SMSSは次を返します:

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

'Created'がdatetimeに設定されているときに、データがvarcharからdatetimeに変換される理由がわかりません。

カラム 「作成済み」が日時であることをサーバーに通知する必要がありますか?そうでない場合、なぜこのvarcharメッセージが表示されるのですか?

編集:データベースの値はでしたYYYY-MM-DD。以下の@SqlZimからの返信は、convert()を使用してSQLにdbの日付の形式を伝え、スペース文字を文字Tで置き換える必要があることを示しています。

select count(*) 
from dbo.profile 
where [created] between convert(datetime,'2014-11-01T00:00:00.000') 
and convert(datetime,'2014-11-30T23:59:59.997');`

回答:


8

私はあなたのプロフィールをチェックしたところ、あなたがイギリスにいることがわかりました。SQLサーバーがdateformat dmyを使用するように設定されている場合、それが問題を説明しています。日時文字列のスペースの代わりに「T」を使用しないと、SQL ServerはそれをISO8601形式として認識しません。

これを試して:

select count(*) 
  from dbo.profile 
  where [created] between convert(datetime,'2014-11-01T00:00:00.000') 
                      and convert(datetime,'2014-11-30T23:59:59.997');

日付や日付時刻を使用してクエリを実行するのは難しい場合があります。

編集:エラーメッセージの範囲外の値を明確にするには、月を30と解釈し、日を11と解釈することになります。


8

'Created'がdatetimeに設定されているときに、データがvarcharからdatetimeに変換される理由がわかりません

Created列との比較のために提供するリテラルは文字列です。これらのリテラルをdatetime列と比較するために、SQL Serverはdatetimeデータ型の優先順位の規則に従って、文字列を型に変換しようとします。文字列の形式に関する明示的な情報がない場合、SQL Serverは、文字列を日時として解釈するための複雑な規則に従います。

私の見解では、これらのタイプの問題を回避する最も簡単な方法は、タイプについて明示することです。SQL Serverは、この目的のためのCAST and CONVERT関数を提供します。文字列と日付/時刻型を操作する場合CONVERTは、文字列形式を明示的に定義するためのスタイルパラメータを提供するため、が推奨されます。

質問では、ODBCの正規(ミリ秒)形式(スタイル121)の文字列を使用します。データ型と文字列スタイルを明示的にすると、次のようになります。

SELECT COUNT(*)
FROM dbo.profile 
WHERE [Created] BETWEEN 
    CONVERT(datetime, '2014-11-01 00:00:00.000', 121)
    AND 
    CONVERT(datetime, '2014-11-30 23:59:59.997', 121);

とはいえ、(アーロンが彼の回答で指摘しているように)代わりにBETWEEN(私は多様性のために以下のスタイル120を使用しています)の代わりに半開の範囲を使用するのには十分な理由があります。

SELECT COUNT(*)
FROM dbo.profile 
WHERE
    [Created] >= CONVERT(datetime, '2014-11-01 00:00:00', 120)
    AND [Created] < CONVERT(datetime, '2014-12-01 00:00:00', 120);

型について明示的にすることは、特に日付と時刻を処理する場合に入るのが非常に良い習慣です。



3

別の方法として、ODBC日時リテラルの使用をお勧めします。それらの名前にもかかわらず、ODBC経由で接続する必要はありません。これらはSQL Serverの通常の変換ルールをバイパスし、常にとして解釈されますdatetime

SELECT COUNT(*)
FROM dbo.profile 
WHERE [Created] BETWEEN 
    {TS '2014-11-01 00:00:00.000'}
    AND 
    {TS '2014-11-30 23:59:59.997'};


サポートされている他のODBCのdatetimeリテラルはありDかつTとしてここに文書 Books Onlineの。どちらもdatetimedateまたはでないtime)を返しますが、構文はコンパクトで明確です。文字列の固定形式は次のとおりです。

ODBC文字列フォーマット

例:

SELECT TOP (1)
    D = {D '2014-12-27'},
    T = {T '14:49:23.789'},
    TS = {TS '2014-12-27 14:49:23.789'};

Tバリアントは、指定された時間を返し、現在の日には社内使用のみによって報告されているように、{fn getdateODBC()}

実行計画


1
ええとCONVERT(DATE, '20141201')、明示的にする必要性が他のすべてをオーバーライドした場合は、おそらく私はただやります。繰り返しになりますが、基になる列が日付/時刻型の場合、これは実際には必要ありません。と解釈されWHERE Active = CONVERT(BIT, 1)ないように言いますか?WHERE Active = 1INT
アーロンバートランド

3
@AaronBertrand実際、私はそれを正確に行うことが知られています:) そして、これが理由の1つの例です
ポールホワイト9

-1

以下のコードは、現在のセッションdateformatを取得し、datetimeに変換するときにエラーを取得します。次に、dateformatをに設定しymd 、最後に、変換(キャスティング)を再度テストして、機能します

-- set the dateformat for the current session
-- if you use this date format you get the following error message:
--Msg 242, Level 16, State 3, Line 9
--The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
set dateformat dmy


-- set the dateformat for the current session
--this one does not give an error message
set dateformat ymd

-- The conversion of a varchar data type 
-- to a datetime data type resulted in an out-of-range value.
select cast('2017-08-13 16:31:31'  as datetime)

-- get the current session date_format
select date_format
from sys.dm_exec_sessions
where session_id = @@spid

-- set the dateformat for the current session
set dateformat ymd

-- this should work
select cast('2017-08-13 16:31:31'  as datetime)



select @@version

Microsoft SQL Server 2016(SP1)(KB3182545)-13.0.4001.0(X64)2016年10月28日18:17:30 Copyright(c)Microsoft Corporation Enterprise Edition:Core-based Licensing(64-bit)on Windows Server 2012 R2 Datacenter 6.3 (ビルド9600:)(ハイパーバイザー)


反対票について説明してください。コードはここで正常に機能しています。
マルチェロミオレッリ2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.