SQL "между" не включительно

У меня есть такой запрос:

SELECT * FROM Cases WHERE created_at BETWEEN '2013-05-01' AND '2013-05-01'

Но это не дает никаких результатов, даже если есть данные о первом.

created_at выглядит как 2013-05-01 22:25:19, я подозреваю, что это связано с временем? Как это можно решить?

Он отлично работает, если я делаю более крупные диапазоны дат, но он должен (включительно) работать с одной датой тоже.

Ответ 1

Это включено. Вы сравниваете дату и время. Вторая дата интерпретируется как полночь, когда начинается день.

Один из способов исправить это:

SELECT *
FROM Cases
WHERE cast(created_at as date) BETWEEN '2013-05-01' AND '2013-05-01'

Еще один способ исправить это с помощью явных двоичных сравнений

SELECT *
FROM Cases
WHERE created_at >= '2013-05-01' AND created_at < '2013-05-02'

Аарон Бертран имеет длинную запись в блоге о датах (здесь), где он обсуждает эту и другие проблемы с датами.

Ответ 2

Предполагалось, что вторая ссылка на дату в синтаксисе BETWEEN магически считается "концом дня", но это неверно.

то есть. это ожидалось:

SELECT * FROM Cases 
WHERE created_at BETWEEN the beginning of '2013-05-01' AND the end of '2013-05-01'

но что действительно происходит, это:

SELECT * FROM Cases 
WHERE created_at BETWEEN '2013-05-01 00:00:00+00000' AND '2013-05-01 00:00:00+00000'

Это становится эквивалентом:

SELECT * FROM Cases WHERE created_at = '2013-05-01 00:00:00+00000'

Проблема заключается в одном из представлений/ожиданий о BETWEEN, которые делает, включают BOTH более низкое значение и верхние значения в диапазоне, но не волшебным образом создает введите "начало" или "конец".

BETWEEN следует избегать при фильтрации по диапазонам дат.

Всегда используйте >= AND < вместо

SELECT * FROM Cases 
WHERE (created_at >= '20130501' AND created_at < '20130502')

круглые скобки необязательны здесь, но могут иметь значение в более сложных запросах.

Ответ 3

Вам нужно сделать один из этих двух вариантов:

  1. Включите компонент времени в ваше условие between: ... where created_at between '2013-05-01 00:00:00' and '2013-05-01 23:59:59' (не рекомендуется... см. последний абзац)
  2. Используйте неравенства вместо between. Обратите внимание, что тогда вам придется добавить один день ко второму значению: ... where (created_at >= '2013-05-01' and created_at < '2013-05-02')

Мои личные предпочтения - второй вариант. Кроме того, Аарон Бертран имеет очень четкое объяснение того, почему его следует использовать.

Ответ 4

Просто используйте метку времени в качестве даты:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' 

Ответ 5

Я считаю, что лучшим решением для сравнения поля даты и времени с полем даты является следующее:

DECLARE @StartDate DATE = '5/1/2013', 
        @EndDate   DATE = '5/1/2013' 

SELECT * 
FROM   cases 
WHERE  Datediff(day, created_at, @StartDate) <= 0 
       AND Datediff(day, created_at, @EndDate) >= 0 

Это эквивалентно инклюзивному утверждению между, поскольку оно включает как дату начала и окончания, так и те, которые попадают между ними.

Ответ 6

cast(created_at as date)

Это будет работать только в 2008 году и более поздних версиях SQL Server

Если вы используете более старую версию, используйте

convert(varchar, created_at, 101)

Ответ 7

Вы можете использовать функцию date() которая извлечет дату из даты и времени и выдаст вам результат как включающую дату:

SELECT * FROM Cases WHERE date(created_at)='2013-05-01' AND '2013-05-01'

Ответ 8

В качестве альтернативы:

SELECT *
FROM Cases
WHERE convert(varchar, created_at, 120) Like '2013-05-01%'