source

SQL Server에서 시간을 비교하려면 어떻게 해야 합니까?

manysource 2023. 6. 24. 09:18

SQL Server에서 시간을 비교하려면 어떻게 해야 합니까?

SQL 쿼리에서 datetime 필드의 시간을 비교하려고 하는데 맞는지 모르겠습니다.날짜 부분은 비교하고 싶지 않고, 시간 부분만 비교하고 싶습니다.

내가 하는 일은:

SELECT timeEvent 
FROM tbEvents 
WHERE convert(datetime, startHour, 8) >= convert(datetime, @startHour, 8)

맞나요?

08:00:0007:30:00날짜를 비교하는 게 아니라 시간 부분만 비교하고 싶습니다.

감사합니다!

비교는 가능하지만 날짜가 각 행에 대한 문자열로 변환되기 때문에 속도가 느려집니다.두 시간 부품을 효율적으로 비교하려면 다음을 시도합니다.

declare @first datetime
set @first = '2009-04-30 19:47:16.123'
declare @second datetime
set @second = '2009-04-10 19:47:16.123'

select (cast(@first as float) - floor(cast(@first as float))) -
       (cast(@second as float) - floor(cast(@second as float)))
       as Difference

긴 설명: SQL 서버의 날짜는 부동 소수점 번호로 저장됩니다.소수점 앞의 숫자는 날짜를 나타냅니다.소수점 뒤의 숫자는 시간을 나타냅니다.

다음은 예제 날짜입니다.

declare @mydate datetime
set @mydate = '2009-04-30 19:47:16.123'

이를 플로트로 변환합니다.

declare @myfloat float
set @myfloat = cast(@mydate as float)
select @myfloat
-- Shows 39931,8244921682

이제 쉼표 뒤에 있는 부분, 즉 시간:

set @myfloat = @myfloat - floor(@myfloat) 
select @myfloat
-- Shows 0,824492168212601

날짜/시간으로 다시 변환:

declare @mytime datetime
set @mytime = convert(datetime,@myfloat)
select @mytime
-- Shows 1900-01-01 19:47:16.123

1900-01-01은 "제로" 날짜입니다. 변환을 사용하여 시간 부분을 표시할 수 있습니다. 예를 들어 형식 108을 지정하면 다음과 같습니다.

select convert(varchar(32),@mytime,108)
-- Shows 19:47:16

날짜 시간과 변동 시간 사이의 변환은 매우 빠릅니다. 기본적으로 동일한 방식으로 저장되기 때문입니다.

convert(varchar(5), thedate, 108) between @leftTime and @rightTime

설명:

에 ,varchar(5)얻게 될 것입니다.HH:mm

에 ,varchar(8)은 당이얻은을 얻습니다.HH:mm ss

108은 SQL 날짜로부터 시간만 가져옵니다.

@leftTime그리고.@rightTime할 수 있는 는 두 가지입니다.

SQL Server 2008을 사용하는 경우 다음 작업을 수행할 수 있습니다.

WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)

다음은 전체 테스트입니다.

DECLARE @tbEvents TABLE (
    timeEvent   int      IDENTITY,
    startHour   datetime
)

INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE())
INSERT INTO @tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE())

--SELECT * FROM @tbEvents

DECLARE @startTime  datetime

SET @startTime = DATEADD(mi, 65, GETDATE())

SELECT
    timeEvent,
    CONVERT(time(0), startHour)  AS 'startHour',
    CONVERT(time(0), @startTime) AS '@startTime'
FROM @tbEvents
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), @startTime)

변환 날짜 시간을 트릭을 수행해야 하는 시간으로 변경하기만 하면 됩니다.

SELECT timeEvent 
FROM tbEvents 
WHERE convert(time, startHour) >= convert(time, @startHour)
if (cast('2012-06-20 23:49:14.363' as time) between 
    cast('2012-06-20 23:49:14.363' as time) and 
    cast('2012-06-20 23:49:14.363' as time))

지금까지 솔루션과 관련하여 언급한 한 가지(아마도 작은) 문제는 비교를 처리하기 위해 모두 함수 호출이 필요한 것 같다는 것입니다.즉, 쿼리 엔진은 사용자가 원하는 행을 찾기 위해 전체 테이블 검색을 수행해야 하며 인덱스를 사용할 수 없습니다.테이블이 특별히 커지지 않을 경우에는 악영향을 미치지 않을 수 있습니다(그리고 이 답변은 무시해도 좋습니다).

반면에 테이블이 상당히 커질 수 있으면 쿼리 성능이 저하될 수 있습니다.

날짜 부분을 비교하고 싶지 않다고 말씀하신 것은 알고 있습니다만, 날짜 시간 열에 실제 날짜가 저장되어 있습니까, 아니면 시간만 저장하기 위해 사용하고 있습니까?후자의 경우 단순 비교 연산자를 사용하면 CPU 사용량이 모두 감소하고 쿼리 엔진이 통계와 인덱스(있는 경우)를 사용하여 쿼리를 최적화할 수 있습니다.

그러나 datetime 열이 이벤트의 날짜와 시간을 모두 저장하는 데 사용되는 경우에는 분명히 작동하지 않습니다.이 경우 앱과 테이블 구조를 수정하거나, 날짜와 시간을 두 개의 별도의 날짜/시간 열로 구분하거나, 원본 테이블의 모든 (관련) 열을 선택하는 인덱스 보기를 만들 수 있습니다.검색할 시간 요소가 포함된 추가 열(이전 답변 중 하나를 사용하여 계산) - 대신 보기를 쿼리하도록 앱을 변경합니다.

플로트를 사용하면 작동하지 않습니다.

DECLARE @t1 datetime, @t2 datetime
SELECT @t1 = '19000101 23:55:00', @t2 = '20001102 23:55:00'
SELECT CAST(@t1 as float) - floor(CAST(@t1 as float)), CAST(@t2 as float) - floor(CAST(@t2 as float))

값이 동일하지 않음을 알 수 있습니다(SQL Server 2005).이 방법을 사용하여 현재 시간을 23:55:00과 00:05:00 사이로 비교하던 자정 전후의 시간(전체 방법이 더 자세한 내용을 가지고 있음)을 확인하고자 했습니다.

다른 답변에 추가:

날짜 시간에서 날짜를 트리밍하는 함수를 만들 수 있습니다.

CREATE FUNCTION dbo.f_trimdate (@dat datetime) RETURNS DATETIME AS BEGIN
    RETURN CONVERT(DATETIME, CONVERT(FLOAT, @dat) - CONVERT(INT, @dat))
END

그래서 이것은:

DECLARE @dat DATETIME
SELECT @dat = '20080201 02:25:46.000'
SELECT dbo.f_trimdate(@dat)

1900-01-01 02:25:46.000을 반환합니다.

날짜 부품 사용 함수: DATEPART(날짜 부품, 날짜)

예#

날짜 부품(@YourVar, hh)*60) + 날짜 부품(@YourVar, mi)*60)을 선택합니다.

이렇게 하면 하루의 총 시간을 분 단위로 표시하여 보다 쉽게 비교할 수 있습니다.

날짜가 같을 경우 DateDiff를 사용할 수 있습니다. 그렇지 않으면 위와 같이 날짜를 삭제해야 합니다.

날짜 시간의 두 변수를 생성하고 비교해야 할 날짜의 시간만 설정할 수 있습니다.

declare  @date1 datetime;
declare  @date2 datetime;

select   @date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114)
select   @date2 = CONVERT(varchar(20),GETDATE(), 114)

날짜는 "1900-01-01"이 될 것입니다. 비교할 수 있습니다.

if @date1 <= @date2
   print '@date1 less then @date2'
else
   print '@date1 more then @date2'
SELECT timeEvent 
  FROM tbEvents 
 WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'

SQL Server에서 스타일 108("hh:mm:ss")을 사용하여 현재 날짜/시간을 막대로 변환하도록 지시합니다.필요한 경우 다른 변환자인 '01:01:01'을 대체할 수도 있습니다.

저는 당신이 사용하고 싶어한다고 믿습니다.DATEPART('hour', datetime).

참조는 다음과 같습니다.

http://msdn.microsoft.com/en-us/library/ms174420.aspx

저는 스토리지 내부(날짜 시간은 정수 = 일 및 분수 = 시간)에 의존하는 것을 좋아하지 않지만, Jhonny D라는 답과 동일한 작업을 수행합니다.캐노. 이게 제가 아는 모든 db 개발자들이 하는 방식입니다.문자열로 변환하지 마십시오.float/int로 처리되지 않도록 해야 하는 경우 DatePart()를 사용하여 시간/분/초/밀리초를 꺼내는 것이 가장 좋은 옵션입니다.

당신의 출발을 가정합니다.시간 열 및 @start시간 변수는 둘 다 DATTIME입니다.이 경우 문자열로 변환해야 합니다.

SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), @startHour, 8)

아래 쿼리는 날짜의 시간을 제공합니다.

select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table

@ronmurp는 유효한 문제를 제기합니다. 주조/플로어 접근 방식은 동시에 다른 값을 반환합니다.@littlechris의 답을 따라 1분, 초, 밀리초 구성 요소가 있는 시간을 해결하는 보다 일반적인 솔루션의 경우 이 함수를 사용하여 하루 시작부터 밀리초 수를 계산할 수 있습니다.

Create Function [dbo].[MsFromStartOfDay] ( @DateTime datetime )
Returns int
As
  Begin
      Return (
               ( Datepart( ms , @DateTime ) ) +
               ( Datepart( ss , @DateTime ) * 1000 ) +
               ( Datepart( mi , @DateTime ) * 1000 * 60 ) +
               ( Datepart( hh , @DateTime ) * 1000 * 60 * 60 )
              )
  End

동일한 시간으로 두 개의 다른 날짜에 대해 동일한 int를 반환하는 것을 확인했습니다.

declare @first datetime
set @first = '1900-01-01 23:59:39.090'
declare @second datetime
set @second = '2000-11-02 23:56:39.090'
Select dbo.MsFromStartOfDay( @first )
Select dbo.MsFromStartOfDay( @second )

이 솔루션이 항상 기대했던 int를 반환하는 것은 아닙니다.예를 들어 SQL 2005에서 다음을 시도하면 '556'이 아닌 '557'으로 의도가 반환됩니다.

set @first = '1900-01-01 23:59:39.556'
set @second = '2000-11-02 23:56:39.556'

이것은 Float로 저장된 DateTime의 특성과 관련이 있다고 생각합니다.그래도 두 숫자를 비교할 수 있습니다.그리고 DateTime을 사용하여 .NET에서 캡처한 DateTime의 "실제" 데이터 세트에 대해 이 접근 방식을 사용했습니다.이제() SQL에 저장되어 계산이 정확하다는 것을 알게 되었습니다.

TL;DR

검색에서 인덱스를 사용하려면 시간 값과 날짜 값을 구분합니다(성능을 위해).다음과 같은 작업을 수행할 수 있습니다. (1) 함수 기반 인덱스를 사용하거나 (2) 시간에 한해 새 열을 만들고 이 열을 인덱싱하여 사용합니다.SELECT


SQL에서 함수를 사용하면 인덱스 성능이 향상되지 않습니다.WHERE엔진이 검색을 수행해야 합니다.다음을 사용하여 쿼리 실행EXPLAIN SELECT...이것을 확인하기 위해.이 문제는 엔진이 각 비교에 대해 필드의 모든 값을 처리해야 하고 변환된 값이 인덱싱되지 않기 때문에 발생합니다.

대부분의 대답은 사용하라고 말합니다.float(),convert(),cast(),addtime()이 작업을 수행하면 데이터베이스에서 인덱스를 사용하지 않습니다.작은 테이블의 경우 괜찮을지도 모릅니다.

의 기능을 사용해도 됩니다.WHERE하지만 매개 변수(where field = func(value)테이블의 각 필드 값을 변경하지 않기 때문입니다.

인덱스를 계속 사용하려는 경우 시간 값에 대한 함수 기반 인덱스를 만들 수 있습니다.이 작업을 수행하는 적절한 방법(및 지원)은 데이터베이스 엔진에 따라 다를 수 있습니다.다른 옵션은 시간 값만 저장하고 이 열을 색인화하는 열을 추가하는 것이지만, 먼저 이전 방법을 사용해 보십시오.


06-02 편집

데이터베이스를 업데이트하기 전에 성능 테스트를 수행하여 새 시간 열을 사용하거나 인덱스를 사용할 수 있습니다.테스트를 통해 성능 향상이 미미하며(어느 정도 개선될 수 있을 때) 새 인덱스를 추가하는 데 드는 수고와 오버헤드를 감당할 가치가 없다는 것을 알게 되었습니다.

언급URL : https://stackoverflow.com/questions/807909/how-can-i-compare-time-in-sql-server