Datum aus Zeichenfolge einfügen: CAST vs CONVERT

7

Betrachten Sie die folgenden zwei Möglichkeiten, um eine Datums- / Uhrzeit-Varchar-Zeichenfolge in ein Datumsfeld zu konvertieren:

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

Beide geben zurück, was ich erwarte: Das Datum ohne Uhrzeit als Datumsdatentyp.

Meine Frage ist: Gibt es Vor- und Nachteile, wie auch immer?

pmdci
quelle
Diese Frage kann auf "Was ist der Unterschied zwischen Cast und Convert
jyao

Antworten:

10

Die (früher) akzeptierte Antwort istwar falsch wie es istwar ein schlechter und irreführender Test. Die beiden verglichenen Abfragen machen aufgrund eines einfachen Tippfehlers, der dazu führt, dass sie kein Apfel-zu-Apfel-Vergleich sind, nicht dasselbe. Der Test in der akzeptierten Antwort ist zu Unrecht zugunsten der CASTOperation voreingenommen . Das Problem ist, dass die CONVERTOperation ausgeführt wird convert(date, GETDATE()+num,20)- ein Wert zum Konvertieren, der sich pro Zeile ändert -, während die CASTOperation mit einem einfachen cast(GETDATE() as date)Wert ausgeführt wird - ein Wert zum Konvertieren, der über alle Zeilen hinweg konsistent ist und im Ausführungsplan ersetzt wird als Konstante. Wenn Sie sich den XML-Ausführungsplan ansehen, wird sogar die tatsächlich ausgeführte Operation als CONVERT(date,getdate(),0)!! angezeigt.

Soweit meine Tests zeigen (nachdem sie durch Verwendung gleich gemacht wurden cast(GETDATE()+num as date)), sind die Zeiten, in denen sie variieren, größtenteils gleich (was sinnvoll ist, wenn beide CONVERTsowieso reduziert sind ) oder der CONVERTGewinn:

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.

Der Hauptunterschied zwischen CAST und CONVERT besteht darin, CONVERTdass der "Stil" angegeben werden kann. Der "Stil" ermöglicht nicht nur das Anpassen der Ausgabe beim Konvertieren eines Nicht-Strings in einen String, sondern auch das Festlegen des Eingabeformats beim Konvertieren eines Strings in einen Nicht-String:

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

Vergleichen Sie das nun funktional mit CAST:

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

Eine weitere Sache, die Sie erwähnen sollten CAST: Da der Parameter "style" nicht vorhanden ist, wird angenommen, dass das Format der übergebenen Datumszeichenfolge das der aktuellen Kultur ist (eine Sitzungseigenschaft). Die aktuelle Kultur wird durch die Systemvariablen @@LANGIDund @@LANGUAGEbezeichnet. Dies bedeutet, dass die CASTAussage, die im Test direkt oben fehlgeschlagen ist, für eine andere Kultur / Sprache erfolgreich sein kann. Die folgenden Tests zeigen dieses Verhalten und wie dieselbe Datumszeichenfolge funktioniert, CASTwenn die aktuelle Sprache "Französisch" ist (und mit mehreren anderen funktionieren würde, basierend auf den Werten in der dateformatSpalte in sys.syslanguages):

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;
Solomon Rutzky
quelle
1
Lange überfällig, aber vielen Dank für Ihre Zeit mit dieser gründlichen Antwort. Ich habe dies heute noch einmal besucht, um eine Store-Prozedur zu schreiben, und Ihre Antwort hat mir sehr geholfen! Danke noch einmal!
pmdci
4

Mir sind keine Leistungsunterschiede zwischen den beiden bekannt. Anscheinend ist "CONVERT" SQL Server-spezifisch, während CAST ANSI-Standard ist. Ich glaube, CONVERT bietet Ihnen mehr Möglichkeiten. Weitere Vor- und Nachteile finden Sie hier ( http://searchsqlserver.techtarget.com/tip/The-difference-between-CONVERT-and-CAST-in-SQL-Server ).

Direkte Zitate vom Link ...

Da SQL Server beide Funktionen bietet, kann es zu Unklarheiten darüber kommen, welche unter welchen Umständen am besten zu verwenden ist.

CONVERT ist spezifisch für SQL Server und bietet eine größere Flexibilität bei der Konvertierung zwischen Datums- und Zeitwerten, Bruchzahlen und Währungsbezeichnern.

CAST ist der ANSI-Standard der beiden Funktionen, was bedeutet, dass es zwar portabler ist (dh eine Funktion, die CAST verwendet, kann in anderen Datenbankanwendungen mehr oder weniger unverändert verwendet werden), aber auch weniger leistungsfähig ist.

Scott Hodgin
quelle
2
Da es sich bei den Eingaben nicht um datetime-Variablen / Spalten handelt, sondern um varchar-Zeichenfolgen, würde CONVERT()ich sicherstellen, dass der Stil 20 verwendet wird. CAST(string AS DATE)kann von verschiedenen Einstellungen für Gebietsschema / Sprachverbindung / Datenbank / Instanz abhängen.
Ypercubeᵀᴹ
@ ypercubeᵀᴹ und Scott: Ja, CASTist abhängig von der LANGUAGESitzungseigenschaft. Ich habe meiner Antwort gerade einen Abschnitt (unter der Zeile) hinzugefügt, der dies veranschaulicht.
Solomon Rutzky
3

Ich habe diesen dummen Vergleich versucht. Bearbeitet gab es einen Tippfehler, den @srutzky ansprach. Die Ergebnisse sind nah.

    ;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);

Die Ergebnisse waren sehr konsistent:

  • Konvertieren: 8,6 Sekunden
  • Besetzung: 8,7 Sekunden
vercelli
quelle
Sie konvertieren Datums- / Uhrzeitwerte, nicht Varchar (als Frage).
Ypercubeᵀᴹ
1
@ypercube - Ich war fasziniert von Ihrem Beispiel und wollte ein bisschen mehr spielen. Ich habe Ihr ursprüngliches Beispiel verwendet, um zu sehen, wo CAST der klare Gewinner zu sein schien. Ich habe dann Ihr Beispiel einmal in GetDate () in eine Variable geändert und diese dann in Ihrem Beispiel verwendet. Meine Ergebnisse waren nicht so konsistent und in einigen Fällen kam CONVERT schneller - ich versuche herauszufinden, warum dies der Fall sein würde.
Scott Hodgin
1
@srutzky Du hast recht. Der Test wurde bereits bearbeitet und wiederholt.
Vercelli
1
@srutzky Du warst nicht überkritisch! Ich weiß das wirklich zu schätzen. (+1)
Vercelli
1
@vercelli Ich bin froh, dass es nicht falsch verstanden wurde. Schriftliche Nachrichten wirken oft abweisend / ätzend, deshalb wollte ich klarstellen, dass ich nicht negativ über dich bin :).
Solomon Rutzky