Як порівняти дату і час лише з датою в SQL Server


77
Select * from [User] U
where  U.DateCreated = '2014-02-07'     

але в базі даних користувач був створений на 2014-02-07 12:30:47.220і коли я лише помістив'2014-02-07'

Він не відображає жодних даних

Відповіді:


82

НЕ спокушайтеся робити такі речі:

Select * from [User] U where convert(varchar(10),U.DateCreated, 120) = '2014-02-07'

Це кращий спосіб:

Select * from [User] U 
where U.DateCreated >= '2014-02-07' and U.DateCreated < dateadd(day,1,'2014-02-07')

див .: Що насправді означає слово “SARGable”?

EDIT + Є дві основні причини для уникнення використання функцій на даних у реченні where (або в умовах об'єднання).

  1. У більшості випадків використання функції даних для фільтрування або об’єднання усуває можливість оптимізатора отримувати доступ до індексу в цьому полі, отже, робить запит повільнішим (або дорожчим).
  2. Інший - для кожного рядка задіяних даних виконується принаймні одне обчислення. Це може бути додавання сотень, тисяч або багатьох мільйонів обчислень до запиту, щоб ми могли порівняти з одним критерієм, таким як 2014-02-07. Набагато ефективніше змінювати критерії відповідно до даних.

"Внесення змін до критеріїв відповідно до даних" - це мій спосіб описати "використання SARGABLEпредикатів"


І не використовуйте між ними.

найкраща практика з діапазонами дат та часу - уникати МІЖ і завжди використовувати форму:

WHERE col> = '20120101' AND col <'20120201' Ця форма працює з усіма типами та з усіма точностями, незалежно від того, чи застосовується часова частина.

http://sqlmag.com/t-sql/t-sql-best-practices-part-2 (Іцік Бен-Ган)


2
Якщо у вас є час, вам слід пояснити, чому один кращий за інший (використання індексу), це зробить це кращою відповіддю
Серпітон,

простіше сказати, ніж зробити, існує декілька типів даних (дата, дата-час, дата-час2, невеликий час), а також різні версії mssql. Одна відповідь не відповідає всім, чого я боюся. Але додам примітку.
Used_By_Вже

1
Якщо ви використовуєте привід (datetime як дату), він все одно використовуватиме індекс у полі datetime. Спробуй це.
Steve Ford

@ Стів Форд, я згоден - в останніх версіях mssql - що саме тому я сказав: "це легше сказати, ніж зробити"; це твердо бути правим у будь-яких умовах. Однак корисною є використання предикатів, що підлягають сарганізації, навіть якщо оптимізатори canіноді компенсують.
Used_By_Вже

2
найбезпечніший date literalформат - "РРРРММДД". Типи даних: дата чи дата чи час, або час, або дата і час2 або невеликий час НЕ мають формату, оскільки вони зберігаються як числа. Для літералів дати `` РРРР-ММ-ДД '' НЕ цілком безпечно існує один параметр мови, який може неправильно інтерпретувати цю послідовність як РРРР-ДД-ММ
Used_By_Already

69

Якщо ви використовуєте SQL Server 2008 або пізнішої версії, ви можете використовувати тип даних date:

SELECT *
FROM [User] U
WHERE CAST(U.DateCreated as DATE) = '2014-02-07'

Слід зазначити, що якщо стовпець дати індексується, тоді він все одно використовуватиме індекс і може бути SARGable. Це особливий випадок для дат та часу.

введіть тут опис зображення

Ви бачите, що SQL Server насправді перетворює це на пропозиції> та <:

введіть тут опис зображення

Я щойно спробував це на великій таблиці, із вторинним індексом у стовпці дати відповідно до коментарів @ kobik, і індекс все ще використовується, це не стосується прикладів, які використовують BETWEEN або> = і <:

SELECT *
FROM [User] U
WHERE CAST(U.DateCreated as DATE) = '2016-07-05'

показує використання індексу з вторинним індексом


могло здатися, що я націлювався на цю відповідь, це було не так, оскільки ми розміщували повідомлення майже одночасно, і я не знав про вашу відповідь. Але щоб зменшити потребу у вас знову збільшувати розмір вашого зображення, я маю змінити приклад "не робити", можливо, це допоможе?
Used_By_Вже

Як зараз працює AaronsBadбаза даних?
Pure.Krome

@ Pure.Krome, як ви можете зрозуміти, це була тимчасова база даних, яка більше не існує.
Стів Форд

"Слід зазначити, що якщо стовпець дати індексується, тоді він все одно використовуватиме індекс і має значення SARGable" - Це вірно, коли DateCreated є PK або кластерним індексом. для некластеризованого індексу існує повне сканування таблиці.
kobik

@kobik насправді я щойно провів тест, і це рішення використовує індекс для великої таблиці. Інші рішення - ні.
Стів Форд

3

Відповідно до вашого запиту Select * from [User] U where U.DateCreated = '2014-02-07'

SQL Server порівнює точну дату та час, тобто (порівняння 2014-02-07 12:30:47.220з2014-02-07 00:00:00.000 для рівності). тому результат порівняння хибний

Тому, порівнюючи дати, потрібно враховувати і час. Можна використовувати
Select * from [User] U where U.DateCreated BETWEEN '2014-02-07' AND '2014-02-08'.


2
На жаль, SQL визначає betweenз рівними на обох кінцях (> = і <=), наприклад, select * from x where col_1 between 'A' and 'M' включає A і M (плюс B до L, звичайно). Цей інклюзивний характер betweenє приголомшливим для чогось на зразок покажчика документів; але для діапазонів дати / часу це катастрофа, оскільки створює перекриття. Я знаю, що використання між виглядає чудово, але насправді SQL betweenпросто не працює належним чином для діапазонів дат. Завжди використовуйте комбінацію> = з <як уU.DateCreated >='2014-02-07' and U.DateCreated < '2014-02-08'
Used_By_Already

@Used_By_Arready Погодьтеся з вами, але для цього конкретного випадку (під питанням), between це нормально. Ваша пропозиція використовувати, >=і <, безсумнівно, є кращою betweenдля діапазонів дат. Я просто хочу сказати, що ми повинні враховувати час і коли порівнюємо дати.
imdzeeshan

0

Звичайно, це стара тема, але щоб зробити її повною.

З SQL 2008 ви можете використовувати тип даних DATE, тому ви можете просто зробити:

SELECT CONVERT(DATE,GETDATE())

OR

Select * from [User] U
where  CONVERT(DATE,U.DateCreated) = '2014-02-07' 

-2

Будь ласка, спробуйте це. Цей запит може бути використаний для порівняння дат

select * from [User] U where convert(varchar(10),U.DateCreated, 120) = '2014-02-07'

-3

Ви можете використовувати LIKEоператор замість =. Але щоб зробити це за допомогою DateStamp, потрібно CONVERTспочатку до VARCHAR:

SELECT * 
FROM [User] U
WHERE CONVERT(VARCHAR, U.DateCreated, 120) LIKE '2014-02-07%'

1
+1, оскільки це діючі рішення, і їх можна використовувати в багатьох сценаріях, будь ласка, не голосуйте за робочі відповіді лише тому, що ви вважаєте, що це не є доброю практикою, надайте нам надійну статтю чи документ, тоді ви переконуєте нас більше
драми

3
Перетворення рядка @Ahmad з подальшим порівнянням дорожче порівняння з датами. Отже, голоси проти є виправданими, оскільки це не є хорошим способом зробити те, що хоче зробити ОП.
mbomb007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.