SQL "사이에"포함되지 않음


136

다음과 같은 쿼리가 있습니다.

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

그러나 이것은 1 일에 데이터가 있어도 결과가 없습니다.

created_at외모가 좋아 2013-05-01 22:25:19, 나는 그것이 시간과 관련이있다 의심? 이 문제를 어떻게 해결할 수 있습니까?

더 큰 날짜 범위를 사용하면 제대로 작동하지만 단일 날짜에서도 (포함) 작동해야합니다.


23
1과 1 사이의 숫자는 몇 개입니까? 1.5는 1과 1 사이 여야합니까? 날짜 / 시간 범위에 BETWEEN을 사용하지 마십시오. 이제까지. "정확하게 작동"한다고 평가하는 방법에주의하십시오. 마지막 날의 결과를 자세히 조사 했습니까? 시간과 관련이없는 모든 행만 포함합니다.
Aaron Bertrand

Aaron의 업데이트 된 URL : sqlblog.org/2011/10/19/…
JayRizzo

답변:


295

그것은 이다 포함. 날짜 시간을 날짜와 비교하고 있습니다. 두 번째 날짜는 하루가 시작 되는 자정으로 해석 됩니다 .

이 문제를 해결하는 한 가지 방법은 다음과 같습니다.

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'

Aaron Bertrand는 날짜 ( here ) 에 긴 블로그 항목을 가지고 있으며 여기 에서 기타 날짜 문제에 대해 설명합니다.


15
이 정답에 대한 완전성을 위해 dateadd다음 날에 사용 하는 것이 좋습니다 .
팀 레너

7
@TimLehner 좋은 답변을 위해 '20130501'의 ISO-8601 형식을 사용했을 것입니다. DATEFORMAT DMY와 미국 이외의 사람들을 위해, 당신이 얻을 :set dateformat dmy;select month(cast('2013-05-01' as datetime)); =1
RichardTheKiwi

2
@RichardTheKiwi- 명시 적 비트가 지정된 종료 날짜 이후 하루를 확인하는 것과 함께 한쪽 끝 ( >=) 에서 닫히고 다른 쪽 ( )에서 열린 간격을 사용하고 있다고 생각합니다 <.
HABO

3
@scottb 개인적으로, 나는 datetime으로 수업을 표시, 내보내기, 가져 오기 또는 작성하고 싶을 때마다 datetimes로 변환 해야하는 것이 성가시다. SQL Server에는 대부분의 목적으로 날짜 시간을 조작하고 비교할 수있는 많은 내장 기능이 있다고 생각합니다.
Tim Lehner

10
where절 에서 열을 캐스트해서는 안됩니다. 열의 색인이 손실되기 때문입니다. 정말 나쁜 패턴입니다.
부지 나스

49

BETWEEN구문 에서 두 번째 날짜 참조 는 마술처럼 "날의 끝"으로 간주되지만 이는 사실이 아닙니다 .

즉, 이것은 예상되었다 :

사례 선택 * 
WHERE BETWEEN created_at 의 시작 '2013년 5월 1일'AND 의 끝 '2013년 5월 1일'

그러나 실제로 일어나는 일은 다음과 같습니다.

사례 선택 * 
'2013-05-01 00 : 00 : 00 + 00000 '과 '2013-05-01 00 : 00 : 00 + 00000 '
 사이에 created_at이 (가) 있습니다

다음과 같습니다.

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

문제에 대한 인식 / 기대 중 하나입니다 BETWEEN어느 않습니다 낮은 값과 범위의 상단 값을 모두 포함하지만, 하지 않는 마술 날짜가 또는 "말" "의 시작"합니다.

BETWEEN 날짜 범위별로 필터링 할 때는 사용하지 않아야합니다.

항상>= AND < 대신 사용하십시오

사례 선택 * 
어디에 (created_at > = '20130501' 그리고 created_at < '20130502')

여기서 괄호는 선택 사항이지만 더 복잡한 쿼리에서 중요 할 수 있습니다.


2
질문에 대한 답변이 이미
접수 된 후이

5
편집자에게; 의사 SQL을 코드 블록으로 만들려고하지 마십시오. 댓글이 BOLD에 의존하기 때문에 단순히 작동하지 않습니다.
Used_By_Already

2
편집자에게 (다시) 의사 코드를 통해 가짜 인용 부호를 추가하지 마십시오. 그들은 이해력을 돕지 않습니다.
Used_By_Already

18

다음 두 옵션 중 하나를 수행해야합니다.

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

내 개인적인 취향은 두 번째 옵션입니다. 또한 Aaron Bertrand 사용해야하는지 에 대한 명확한 설명을 가지고 있습니다.


6
2의 경우 +1. 1의 경우 -1.이 해킹은 완전히 신뢰할 수없고 나쁜 생각입니다.
Aaron Bertrand

1
@AaronBertrand 나는 또한 옵션 2를 선호합니다 (자주 사용합니다). 그러나 왜 옵션 1이 "완전히 신뢰할 수 없다"고 말합니까?
Barranka

5
전체 내용을 읽어주십시오 . BETWEEN시간이 포함 된 날짜 범위 쿼리에는 사용해서는 안됩니다 . 너무 많이 잘못 될 수 있습니다.
Aaron Bertrand


7

날짜 시간 필드와 날짜 필드를 비교하는 가장 좋은 해결책은 다음과 같습니다.

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 

이것은 시작 날짜와 종료 날짜 및 그 사이의 날짜를 포함하므로 명령문 사이에 포함되는 것과 같습니다.


3
cast(created_at as date)

2008 및 최신 버전의 SQL Server에서만 작동합니다.

이전 버전을 사용하는 경우

convert(varchar, created_at, 101)

2
convert(varchar, created_at, 101)결과는 같고 dd/MM/yyyyOP의 문자열은입니다 yyyy-MM-dd.이 답변은 효과가 없다고 생각합니다.).
shA.t

2

date()날짜 시간에서 날짜를 추출하고 결과를 포함 날짜로 제공 하는 기능을 사용할 수 있습니다 .

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

0

SQL 쿼리 사이의 동적 날짜

var startDate = '2019-08-22';
var Enddate = '2019-10-22'
     let sql = "SELECT * FROM Cases WHERE created_at BETWEEN '?' AND '?'";
     const users = await mysql.query( sql, [startDate, Enddate]);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.