web-dev-qa-db-fra.com

Insertion de la date dans la chaîne: CAST vs CONVERT

Considérez les deux façons suivantes pour convertir une chaîne varchar datetime en un champ de date:

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

Les deux renvoient ce que j'attends: la date excluant l'heure, en tant que type de données date.

Ma question est la suivante: y a-t-il des avantages et des inconvénients à faire quoi que ce soit?

7
pmdci

La réponse (anciennement) acceptée estétait incorrect car estétait un test mauvais et trompeur. Les deux requêtes comparées ne font pas la même chose en raison d'une simple faute de frappe qui fait qu'elles ne sont pas une comparaison de pommes à pommes. Le test de la réponse acceptée est injustement biaisé en faveur de l'opération CAST. Le problème est que l'opération CONVERT se fait avec convert(date, GETDATE()+num,20) - une valeur à convertir qui change par ligne - tandis que l'opération CAST se fait avec un simple cast(GETDATE() as date) - une valeur à convertir qui est cohérente sur toutes les lignes et est remplacée dans le plan d'exécution en tant que constante. Et en fait, regarder le plan d'exécution XML montre même que l'opération réelle effectuée est CONVERT(date,getdate(),0) !!

Dans la mesure où mes tests le montrent (après les avoir rendus égaux en utilisant cast(GETDATE()+num as date)), les temps varient avec eux étant essentiellement les mêmes (ce qui est logique s'ils sont tous les deux réduits à être CONVERT de toute façon) ou le CONVERT gagnant:

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.

La principale différence entre CAST et CONVERT est que CONVERT permet de spécifier le "style". Le "style" permet non seulement de personnaliser la sortie lors de la conversion d'une non-chaîne en chaîne, mais permet également de spécifier le entrez le format lors de la conversion d'une chaîne en une non-chaîne:

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

Comparez maintenant cela fonctionnellement avec 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

Une autre chose à mentionner à propos de CAST: parce qu'il n'a pas le paramètre "style", le format de la chaîne de date passée est supposé être celui de la culture actuelle (une propriété de session). La culture actuelle est indiquée par le @@LANGID et @@LANGUAGE variables système. Cela signifie que l'instruction CAST qui a échoué dans le test directement ci-dessus pourrait réussir pour une culture/langue différente. Les tests suivants montrent ce comportement et comment cette même chaîne de date fonctionne avec CAST lorsque la langue actuelle est "français" (et fonctionnerait avec plusieurs autres, en fonction des valeurs de la colonne dateformat dans 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;
10
Solomon Rutzky

Je ne suis au courant d'aucune différence de "performances" entre les deux. Apparemment, "CONVERT" est spécifique au serveur SQL tandis que CAST est conforme à la norme ANSI. Je crois que CONVERT vous offre plus d'options. Vous pouvez voir d'autres avantages/inconvénients ici ( http://searchsqlserver.techtarget.com/tip/The-difference-between-CONVERT-and-CAST-in-SQL-Server )

Citations directes du lien ...

Étant donné que SQL Server fournit les deux fonctions, il peut y avoir une certaine confusion quant à la meilleure solution à utiliser et dans quelles circonstances.

CONVERT est spécifique à SQL Server et permet une plus grande flexibilité lors de la conversion entre les valeurs de date et d'heure, les nombres fractionnaires et les signifiants monétaires.

CAST est la norme plus ANSI des deux fonctions, ce qui signifie que bien qu'il soit plus portable (c'est-à-dire qu'une fonction qui utilise CAST peut être utilisée dans d'autres applications de base de données plus ou moins en l'état), elle est également moins puissante.

4
Scott Hodgin

J'ai essayé cette comparaison stupide. Modifié, il y avait une faute de frappe que @srutzky a apportée. Les résultats sont proches.

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

Résultats très cohérents:

  • Conversion: 8,6 secondes
  • Cast: 8,7 secondes
3
vercelli