基于T-SQL查询中的datetime列的交替列值

时间:2011-06-13 23:45:34

标签: sql sql-server tsql

为可怕的标题道歉,不知道如何在没有样本的情况下解释这个:

我正在尝试在查询中返回一个列,该列在0到1之间交替,因为结果集上的datetime列的小时更改。 有没有人建议这样做的好方法?或者如何用CTE完成

我开始考虑使用CTE,但没有走得太远,我希望有一种更简单的方法。请参阅下面的一个非常基本的示例,我希望实现的是当前输出和我想要的输出。请注意,我创建了一个列[band],它可以完成我想要的,只要时间都在同一天。当然,当日期超过一天时它会中断。

declare @test as table(id int, dt datetime, comment varchar(50))

insert into @test values(1, '2011-01-01 07:00', 'one')
insert into @test values(2, '2011-01-01 07:30', 'two')
insert into @test values(3, '2011-01-02 07:50', 'three')
insert into @test values(4, '2011-01-03 08:00', 'four')
insert into @test values(5, '2011-01-03 08:50', 'five')
insert into @test values(6, '2011-01-03 09:00', 'six')
insert into @test values(7, '2011-01-03 10:00', 'seven');

select *, DATEPART(HOUR, dt) % 2 as [band]
from @test

当前输出

1   2011-01-01 07:00:00.000 one     1
2   2011-01-01 07:30:00.000 two     1
3   2011-01-02 07:50:00.000 three   1
4   2011-01-03 08:00:00.000 four    0
5   2011-01-03 08:50:00.000 five    0
6   2011-01-03 09:00:00.000 six     1
7   2011-01-03 10:00:00.000 seven   0

必需的输出

1   2011-01-01 07:00:00.000 one     1
2   2011-01-01 07:30:00.000 two     1
3   2011-01-02 07:50:00.000 three   0
4   2011-01-03 08:00:00.000 four    1
5   2011-01-03 08:50:00.000 five    1
6   2011-01-03 09:00:00.000 six     0
7   2011-01-03 10:00:00.000 seven   1

请注意,我希望[band]列交替显示,因为行中的日期时间会更改为新的小时数。他们是在同一天的下一个小时还是在第二天的另一个小时。

2 个答案:

答案 0 :(得分:5)

怎么样?

SELECT *, 
    (dense_rank() over (order by Dateadd(hh,Datediff(hh,0,dt),0))) % 2 as [band]
FROM @test

我现在手头没有sql。但

  1. dateadd / datediff清除小时的分钟数
  2. 然后,dense_rank会像rownumber一样命令它们,但不会重复数字
  3. 然后%2执行您在原始查询中执行的操作。

答案 1 :(得分:2)

据我所知,问题是:

您想要将每条记录的日期时间值与先前记录进行比较,如果小时或任何高于一小时的值已更改,则返回1,否则返回0.

没有好办法 - 你必须迭代。在SQL中,迭代意味着游标:

DECLARE timeLoop CURSOR FOR
SELECT ID, DT 
FROM @test
ORDER BY ID

DECLARE @Id Int
DECLARE @Current DATETIME
DECLARE @Last DATETIME
DECLARE @Change bit
OPEN timeLoop

FETCH NEXT FROM timeLoop into @ID, @Current
SET @LAST = DATEADD(-1, DY, @Current)

WHILE @FETCH_STATUS = 0
BEGIN
    IF ABS(DATEDIFF(h, @Last, @Current) >= 1) SET @Change = 1
    ELSE SET @Change = 0

    SELECT @Id, @Dt, @Change
    SET @Last = @Current

    FETCH NEXT FROM timeLoop into @ID, @Current
END

CLOSE timeLoop
DEALLOCATE timeLoop

对于上面的任何语法错误表示道歉 - 我没有在此框中使用sql server并且没有验证确切的语法,但这样可以帮助您。

实际上我认为你根本不需要CTE

SELECT a.ID, a.DT, ISNULL(b.DT, '1/1/1970')
    CASE     WHEN ABS(DATEDIFF(h, a.dt, ISNULL(b.DT, '1/1/1970')) < 1 THEN 1 
            DEFAULT 1 
    END AS Change
FROM @Test a
LEFT JOIN @Test b
    ON a.ID = b.ID-1

在左边连接上将表连接到自身ID到ID-1(并听取DBA的尖叫),第一行将连接到null,每个后续行将连接到前一行。