web-dev-qa-db-fra.com

La conversion a échoué lors de la conversion de la date et / ou de l'heure à partir d'une chaîne de caractères

J'ai un problème, car j'ai utilisé cette requête sans problème ... jusqu'à maintenant:

UPDATE T1
SET ORDINAL = DATEDIFF(DAY, T2.Opening_Date, T1.Date)
FROM FactTransactions T1
INNER JOIN DimStore T2 ON T1.cod_store = T2.cod_storeKey

Mais maintenant, cela m'a donné une erreur:

La conversion a échoué lors de la conversion de la date et/ou de l'heure à partir d'une chaîne de caractères

Je ne ai aucune idée de ce qui se passe. Voici les colonnes:

Ordinal(numeric,null)
Opening_date(varchar, not null)
Date(varchar, not null)
cod_store(int,not null)
cod_storekey(PK,int, not null)
4
Miguel

Vous stockez des dates sous forme de chaînes - pourquoi? Opening_Date Et Date doivent être date ou datetime, pas varchar. Mais avant de pouvoir résoudre ce problème, vous devez identifier les lignes à l'origine du problème de conversion:

SELECT cod_store, [Date]
FROM dbo.FactTransactions
WHERE ISDATE([Date]) = 0;

SELECT cod_storekey, Opening_Date
FROM dbo.DimStore
WHERE ISDATE(Opening_Date) = 0;

Et maintenant que vous avez résolu la question et que je sais que vous utilisez 2012 et non 2008 R2, il pourrait être plus propre d'utiliser TRY_CONVERT(), d'autant plus que cela vous permettra d'identifier toutes les lignes où le mois et jour sont transposés incorrectement. Par exemple, en supposant que vous vous attendiez à ce que les dates soient stockées sous forme de chaînes mm/dd/yyyy:

SELECT cod_store, [Date]
FROM dbo.FactTransactions
WHERE TRY_CONVERT(datetime, [Date], 101) = 0;

SELECT cod_storekey, Opening_Date
FROM dbo.DimStore
WHERE TRY_CONVERT(datetime, Opening_Date, 101) = 0;

En plus d'identifier les lignes poubelles où les utilisateurs ont stocké des bêtises comme floob et 9992-13-36 Comme "dates", cela identifiera également les lignes où les utilisateurs ont stocké 13/07/1999 Au lieu de 07/13/1999 (Mais il n'y a aucun moyen de savoir si 05/06/2000 Est censé être le 6 mai ou le 5 juin).

Vous devez maintenant corriger ces lignes avant de pouvoir corriger les tableaux.

ALTER TABLE dbo.DimStore ALTER COLUMN Opening_Date date; -- or datetime;
ALTER TABLE dbo.FactTransactions ALTER COLUMN [Date] date; -- or datetime;

Vous pouvez également envisager de renommer la colonne Date pour qu'elle soit (a) moins vague et (b) pas un mot réservé.

Si vous ne pouvez pas corriger les tables, vous devez modifier votre requête:

UPDATE T1
SET ORDINAL = DATEDIFF(DAY, 
  CASE WHEN ISDATE(T2.Opening_Date) = 1 THEN T2.OpeningDate END,
  CASE WHEN ISDATE(T1.[Date]) = 1 THEN T1.Date END)
FROM dbo.FactTransactions AS T1
INNER JOIN dbo.DimStore AS T2 
  ON T1.cod_store = T2.cod_storeKey
WHERE ISDATE(T2.Opening_Date) = 1
  AND ISDATE(T1.[Date]) = 1;

Et @RLF a également soulevé un grand point; si vous ne pouvez pas corriger le tableau, les colonnes de date peuvent contenir des données qui représentent une date spécifique (par exemple, le 7 septembre) mais être saisies au mauvais format (par exemple sur un système anglais américain, saisies sous forme de chaîne au format britannique, 7/9/2015). Donc, vraiment, vous devez corriger la table et arrêter de stocker ces choses sous forme de chaînes.

Quelques autres documents utiles:

6
Aaron Bertrand

Vous pouvez utiliser Convert avec le style correct afin de convertir varchar(x) dans votre format local en dates appropriées:

DATEDIFF(DAY, convert(date, T2.Opening_Date, 104), convert(date, T1.Date, 104))

Dans cet exemple, je suppose que vous utilisez le style allemand (jj.mm.aaaa). Le style allemand est 104:

Select convert(date, '01.02.2015', 104)

Sortie: 2015-02-01

Vous devez l'adapter à vos paramètres et au format local et remplacer 104 par ce que vous utilisez. Le style principal est:

Style   Standard        Input/Ouput
1       U.S.            1 = mm/dd/yy
101     U.S.            101 = mm/dd/yyyy
2       ANSI            2 = yy.mm.dd
102     ANSI            102 = yyyy.mm.dd
3       British/French  3 = dd/mm/yy
103     British/French  103 = dd/mm/yyyy
4       German          4 = dd.mm.yy
104     German          104 = dd.mm.yyyy
5       Italian         5 = dd-mm-yy
105     Italian         105 = dd-mm-yyyy

Regardez CAST et CONVERT (Transact-SQL)

Si vous avez des dates avec de mauvais formats ou des formats mixtes, vous pouvez également consulter TRY_CONVERT avec une requête telle que:

Select ... 
FROM FactTransactions T1
INNER JOIN DimStore T2 ON T1.cod_store = T2.cod_storeKey
Where try_convert(date, T2.Opening_Date, 104) is null 
or try_convert(date, T1.Date, 104) is null

Il vous donnera une liste de dates au format incorect pour le style 104. Encore une fois, adaptez-le à vos paramètres et remplacez 104. Vous pouvez l'utiliser avant de corriger les mauvais formats et dates.

Mais la question principale et le problème sont: pourquoi utilisez-vous varchar (x). Vous devez utiliser Date ou Datetime 2 si vous pouvez mettre à jour votre table.

5
Julien Vavasseur