web-dev-qa-db-ja.com

SQL Serverは、暗黙的な日時変換の形式をどのように決定しますか?

declare @str_datetime varchar(50)
set @str_datetime='30-04-2012 19:01:45' -- 30th April 2012
declare @dt_datetime datetime
select @dt_datetime=@str_datetime

これにより、次のエラーが発生します。

メッセージ242、レベル16、状態3、行4
varcharデータ型をdatetimeデータ型に変換すると、値が範囲外になりました。

私の質問は、SQL Serverが暗黙的な日時変換に使用する形式をどのように決定するかです。

19
Shwet Jain

これは、オペレーティングシステムの地域設定、現在のユーザーの言語、日付形式の設定など、さまざまな要因に依存します。デフォルトでは、WindowsはUS English、およびユーザーの設定はUS EnglishおよびMDY

しかし、これがどのように変化するかを示すいくつかの例があります。

ユーザーはイギリスの言語設定を使用しています:

-- works:
SET LANGUAGE BRITISH;
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04/13/2012');
GO

(エラー)

メッセージ242、レベル16、状態3、行5
varcharデータ型からdatetimeデータ型への変換により、範囲外の値が発生しました。

ユーザーはFrançaisを使用しています:

-- works:
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04/13/2012');
GO

(エラー)

メッセージ242、レベル16、状態3、行1
La変換d'un type dedonnéesvarchar en type dedonnéesdatetimecrééune valeur hors limites。

ユーザーは再びFrançaisを使用しています:

SET LANGUAGE FRENCH;

-- fails (proving that, contrary to popular belief, YYYY-MM-DD is not always safe):
SELECT CONVERT(DATETIME, '2012-04-30');
GO

(エラー)

メッセージ242、レベル16、状態3、行1
La変換d'un type dedonnéesvarchar en type dedonnéesdatetimecrééune valeur hors limites。

ユーザーがMDYの代わりにDMYを使用しています。

SET LANGUAGE ENGLISH;
SET DATEFORMAT DMY;

-- works:
SELECT CONVERT(DATETIME, '30-04-2012 19:01:45');

-- fails:
SELECT CONVERT(DATETIME, '04-30-2012');
GO

(エラー)

メッセージ242、レベル16、状態3、行2
varcharデータ型からdatetimeデータ型への変換により、範囲外の値が発生しました。

常に最善の策は、ISO標準、非地域、安全、明確な日付形式を使用することです。私が通常お勧めする2つは次のとおりです。

YYYYMMDD                  - for date only.
YYYY-MM-DDTHH:MM:SS[.mmm] - for date + time, and yes that T is important.

これらのどれも失敗しません:

SET DATEFORMAT MDY;
SET LANGUAGE ENGLISH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET LANGUAGE FRENCH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET LANGUAGE BRITISH;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');
SET DATEFORMAT DMY;
SELECT CONVERT(DATETIME, '20120430');
SELECT CONVERT(DATETIME, '2012-04-30T19:01:45');

したがって、ユーザーにフリーテキストの日付形式を入力させる(または信頼できない形式を自分で使用させる)代わりに、入力文字列を制御し、これらの安全な形式のいずれかに準拠することを強くお勧めします。そうすれば、ユーザーがどのような設定を持っているか、または基礎となる地域の設定が何であるかは関係ありません。日付は常に意図した日付として解釈されます。現在、ユーザーがフォームのテキストフィールドに日付を入力できるようにしている場合は、それを停止し、カレンダーコントロールまたは少なくとも選択リストを実装して、SQLServerに返される文字列形式を最終的に制御できるようにします。

いくつかの背景については、Tibor Karasziの "日時データ型の究極のガイド" と私の投稿 "キックする悪い習慣:日付/範囲クエリの誤った処理。" をお読みください。

27
Aaron Bertrand

デフォルトでは、SQLServerの日付形式は米国の日付形式MM/DD/YYです。SQLServerのローカライズバージョンがインストールされていない場合。この設定は、この機能を必要とするアプリケーションが、アプリケーションが使用されるすべてのプラットフォームと場所で同じ形式で日付が使用および挿入されることを保証する方法でデプロイされる場合に適しています。

ただし、場合によっては、日付をDD/MM/YY形式にする必要があります。これは、多くの国/地域が米国のデフォルトのMM/DD/YYではなく、この形式を使用しているためです。これは、世界中に配布されている国際的なアプリケーションにとって特に問題です。

ソース

したがって、あなたがする必要があるのは、事前に日付形式を次のように設定することです。

SET DATEFORMAT dmy
GO

そして、クエリが機能します。

1
Icarus

ログインごと、および/または今後追加されるログインごとに、デフォルトの日付形式を変更することもできます(各セッションで「SETDATEFORMAT」を実行する必要はありません)。

SQL Management Studio /セキュリティ/ログインに移動します。ログインを右クリックし、次に[プロパティ]をクリックします。下部に「デフォルト言語」が表示されます。

将来追加されるログインを確認したい場合は、「適切な」言語を取得してください。サーバールートを右クリックし、[プロパティと詳細]ページを右クリックします。そこには、新しく作成されたログインに使用されるオプション「デフォルト言語」もあります。

1
Matt Roy