J'essaie d'exécuter une requête simple pour obtenir toutes les lignes créées en novembre:
SELECT COUNT(*)
FROM dbo.profile
WHERE [Created] BETWEEN '2014-11-01 00:00:00.000'
AND '2014-11-30 23:59:59.997';
SMSS renvoie:
La conversion d'un type de données varchar en un type de données datetime a entraîné une valeur hors plage.
Je ne comprends pas pourquoi les données sont converties de varchar en datetime lorsque 'Created' est défini sur datetime:
Dois-je dire au serveur que "Créé" est datetime? Sinon, pourquoi reçois-je ce message varchar?
Edit: La valeur dans la base de données était YYYY-MM-DD
. La réponse de @SqlZim ci-dessous indique que je dois utiliser convert () pour indiquer à sql le format de la date dans la base de données - et pour remplacer le caractère espace par la lettre T:
select count(*)
from dbo.profile
where [created] between convert(datetime,'2014-11-01T00:00:00.000')
and convert(datetime,'2014-11-30T23:59:59.997');`
J'ai vérifié votre profil et j'ai vu que vous étiez au Royaume-Uni. Si votre serveur SQL est configuré pour utiliser le format de date dmy, cela explique votre problème. Sans utiliser le "T" au lieu de l'espace dans la chaîne datetime, Sql Server ne le reconnaîtra pas au format ISO8601.
Essaye ça:
select count(*)
from dbo.profile
where [created] between convert(datetime,'2014-11-01T00:00:00.000')
and convert(datetime,'2014-11-30T23:59:59.997');
L'interrogation à l'aide de dates et/ou d'heures peut être délicate, pour vous assurer d'obtenir ce que vous recherchez, je recommande la lecture:
modifier: pour clarifier la valeur hors plage dans votre message d'erreur, il faudrait interpréter le mois comme 30 et le jour comme 11.
Je ne comprends pas pourquoi les données sont converties de varchar en datetime lorsque 'Created' est défini sur datetime
Les littéraux que vous fournissez pour la comparaison avec la colonne Created
sont des chaînes. Pour comparer ces littéraux avec la colonne datetime
, SQL Server tente de convertir les chaînes en types datetime
, selon les règles de priorité du type de données . Sans informations explicites sur le format des chaînes, SQL Server suit ses règles compliquées pour interpréter les chaînes comme des heures.
À mon avis, la meilleure façon d'éviter ces types de problèmes est d'être explicite sur les types. SQL Server fournit les CAST and CONVERT
fonctions à cet effet. Lorsque vous travaillez avec des chaînes et des types de date/heure, CONVERT
est préférable car il fournit un paramètre de style pour définir explicitement le format de chaîne.
La question utilise des chaînes au format ODBC canonique (avec millisecondes) (style 121). Le fait d'être explicite sur le type de données et le style de chaîne se traduit par ce qui suit:
SELECT COUNT(*)
FROM dbo.profile
WHERE [Created] BETWEEN
CONVERT(datetime, '2014-11-01 00:00:00.000', 121)
AND
CONVERT(datetime, '2014-11-30 23:59:59.997', 121);
Cela dit, il y a bonnes raisons (comme Aaron le souligne dans sa réponse ) pour utiliser une plage semi-ouverte au lieu de BETWEEN
(j'utilise le style 120 ci-dessous juste pour la variété):
SELECT COUNT(*)
FROM dbo.profile
WHERE
[Created] >= CONVERT(datetime, '2014-11-01 00:00:00', 120)
AND [Created] < CONVERT(datetime, '2014-12-01 00:00:00', 120);
Être explicite sur les types est une très bonne habitude à prendre, en particulier lorsqu'il s'agit de dates et d'heures.
Étant donné que BETWEEN
est très problématique en raison de l'arrondissement de différents types de date/heure et d'autres problèmes , et puisque YYYY-MM-DD
n'est pas un format sûr sans le maladroit T
, une plage ouverte utilisant la norme ISO les dates complètes sans séparateurs est une bien meilleure approche:
WHERE Created >= '20141101' AND Created < '20141201';