web-dev-qa-db-ja.com

文字列からの日付の挿入:CAST vs CONVERT

Datetime varchar文字列を日付フィールドに変換するには、次の2つの方法を検討してください。

SELECT convert(date, '2012-12-21 21:12:00', 20) -- Only date is needed
SELECT cast('2012-12-21 21:12:00' as date) -- Only date is needed

どちらも私が期待するものを返します:時間を除く日付を日付データ型として返します。

私の質問は次のとおりです。いずれかの方法を実行することの賛否両論はありますか?

7
pmdci

(以前)受け入れられた答え ですそれが間違っていた です悪くて誤解を招くテストでした。比較される2つのクエリは、単純なタイプミスが原因で、それらがリンゴ同士の比較ではなくなるため、同じことを行いません。受け入れられた回答のテストは、CAST操作を優先して不当に偏っています。問題は、CONVERT操作がconvert(date, GETDATE()+num,20)-行ごとにその変更を変換する値-で行われているのに対し、CAST操作は単純なcast(GETDATE() as date)-で行われていることです。すべての行にわたって一貫しており、実行プランで定数として置き換えられる変換する値。実際、XML実行プランを見ると、実際に実行された操作がCONVERT(date,getdate(),0)であることがわかります。

私のテストが示している限り(cast(GETDATE()+num as date)を使用してそれらを等しくした後)、それらとの時間はほとんど同じです(どちらもCONVERTに削減されている場合に意味があります)またはCONVERT勝つ:

SET STATISTICS IO, TIME ON;
    ;with t as (
               select convert(date, GETDATE(),20) as fecha , 0 as num
             union all
             select convert(date, GETDATE()+num,20) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9031 ms,  elapsed time = 9377 ms.



-- VS    

SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE() as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

--2016-08-26
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 8969 ms,  elapsed time = 9302 ms.




SET STATISTICS IO, TIME ON;
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE()+num as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);
SET STATISTICS IO, TIME OFF;

-- 4754-07-23
--Table 'Worktable'. Scan count 2, logical reads 6000008, physical reads 0, read-ahead reads 0

-- SQL Server Execution Times:
--   CPU time = 9438 ms,  elapsed time = 9878 ms.

CASTとCONVERT の主な違いは、CONVERTでは「スタイル」を指定できることです。 「スタイル」では、非文字列を文字列に変換するときにoutputを調整できるだけでなく、input文字列を非文字列に変換するときの形式:

SELECT CONVERT(DATE, '5/10/2016', 101); -- 101 = mm/dd/yyyy
-- 2016-05-10


SELECT CONVERT(DATE, '5/10/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-10-05

次に、functionallyCASTと比較します。

SELECT CAST('13/5/2016' AS DATE);
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 101); -- 101 = mm/dd/yyyy
-- Msg 241, Level 16, State 1, Line 76
-- Conversion failed when converting date and/or time from character string.


SELECT CONVERT(DATE, '13/5/2016', 103); -- 103 = dd/mm/yyyy
-- 2016-05-13

CASTについてもう1つ言及する必要があります。「style」パラメータがないため、渡される日付文字列の形式は、現在のカルチャ(セッションプロパティ)の形式であると見なされます。現在のカルチャは、@@LANGIDおよび@@LANGUAGEシステム変数で示されます。つまり、すぐ上のテストで失敗したCASTステートメントは、異なるカルチャ/言語で成功する可能性があります。次のテストは、この動作と、現在の言語が「フランス語」の場合に同じ日付文字列がCASTでどのように機能するかを示します(sys.syslanguagesdateformat列の値に基づいて、他のいくつかでも機能します)。

IF (@@LANGID <> 0) -- us_english
BEGIN
    PRINT 'Changing LANGUAGE to English...';
    SET LANGUAGE ENGLISH;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;

SELECT @@LANGUAGE, CAST('13/5/2016' AS DATE) AS [Test 1];
-- Msg 241, Level 16, State 1, Line 71
-- Conversion failed when converting date and/or time from character string.
GO

SELECT @@LANGUAGE, CONVERT(DATE, '13/5/2016', 103) AS [Test 2]; -- 103 = dd/mm/yyyy
-- us_english   2016-05-13
GO


IF (@@LANGID <> 2) -- Français
BEGIN
    PRINT 'Changing LANGUAGE to French...';
    SET LANGUAGE FRENCH;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;

SELECT @@LANGUAGE, CAST('13/5/2016' AS DATE) AS [Test 3];
-- 2016-05-13
GO

SELECT @@LANGUAGE, CONVERT(DATE, '13/5/2016', 103) AS [Test 4]; -- 103 = dd/mm/yyyy
-- Français 2016-05-13
GO


-- Reset current language, if necessary.
IF (@@LANGID <> @@DEFAULT_LANGID)
BEGIN
    DECLARE @Language sysname;

    SELECT @Language = sl.[alias]
    FROM   sys.syslanguages sl
    WHERE  sl.[langid] = @@DEFAULT_LANGID;

    PRINT N'Changing LANGUAGE back to default: ' + @Language + N'...';

    SET LANGUAGE @Language;
    SELECT @@LANGUAGE AS [CurrentLanguage], @@LANGID AS [LangID];
END;
10
Solomon Rutzky

両者の「パフォーマンス」の違いは知りません。どうやら "CONVERT"はSQL Server固有で、CASTはANSI標準です。 CONVERTはより多くのオプションを提供すると思います。あなたはここで他の長所/短所を見ることができます( http://searchsqlserver.techtarget.com/tip/The-difference-between-CONVERT-and-CAST-in-SQL-Server

リンクからの直接の引用...

SQL Serverは両方の機能を提供するため、どちらが最適で、どのような状況で使用するかについて混乱が生じる可能性があります。

CONVERTはSQL Serverに固有であり、日付と時刻の値、小数、通貨記号の間で変換するときに、より大きな柔軟性を可能にします。

CASTは2つの関数のよりANSI標準です。つまり、移植性は高いです(つまり、CASTを使用する関数は、他のデータベースアプリケーションでそのまま使用できます)が、あまり強力ではありません。

4
Scott Hodgin

私はこのばかげた比較を試みました。編集後、@ srutzkyが育てたタイプミスがありました。結果は近いです。

    ;with t as (
               select convert(date, GETDATE(),20) as fecha , 0 as num
             union all
             select convert(date, GETDATE()+num,20) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);

-- VS    
    ;with t as (
               select cast(GETDATE() as date) as fecha , 0 as num
             union all
             select cast(GETDATE()+num as date) as fecha, num+1 from t where num<1000000)
    select max(fecha)
      from t
    option (maxrecursion  0);

非常に一貫した結果:

  • 変換:8.6秒
  • キャスト:8.7秒
3
vercelli