问题 sql server 2008中的超前滞后功能的替代


我想将当前行与下一行中的值进行比较。 SQL有 LEAD 和 LAG 函数来获取下一个和以前的值,但我不能使用它们,因为我使用的是SQL Server 2008。

那么我怎么得到这个?

我有输出表

+----+-------+-----------+-------------------------+
| Id | ActId |  StatusId |       MinStartTime      |
+----+-------+-----------+-------------------------+
| 1  |  42   | 1         | 2014-02-14 11:17:21.203 |
| 2  |  42   | 1         | 2014-02-14 11:50:19.367 |
| 3  |  42   | 1         | 2014-02-14 11:50:19.380 |
| 4  |  42   | 6         | 2014-02-17 05:25:57.280 |
| 5  |  42   | 6         | 2014-02-19 06:09:33.150 |
| 6  |  42   | 1         | 2014-02-19 06:11:24.393 |
| 7  |  42   | 6         | 2014-02-19 06:11:24.410 |
| 8  |  42   | 8         | 2014-02-19 06:44:47.070 |
+----+-------+-----------+-------------------------+

我想要做的是,如果当前行状态为1并且下一行状态为6并且两个时间相同(最多几分钟),那么我想获得状态为1的行。

例如:Id 6行具有状态1而Id 7行具有状态6但两个时间相同即。 2014-02-19 06:11

所以我想得到状态1的这一行或id,即。 id 6


2226
2018-03-05 04:26


起源



答案:


在你的情况下, ids似乎是数字,你可以做一个自我加入:

select t.*
from table t join
     table tnext
     on t.id = tnext.id - 1 and
        t.StatusId = 1 and
        tnext.StatusId = 6 and
        datediff(second, t.MinStartTime, tnext.MinStartTime) < 60;

这不是完全相同的一分钟。它在60秒内。你真的需要相同的日历时间分钟吗?如果是这样,你可以这样做:

select t.*
from table t join
     table tnext
     on t.id = tnext.id - 1 and
        t.StatusId = 1 and
        tnext.StatusId = 6 and
        datediff(second, t.MinStartTime, tnext.MinStartTime) < 60 and
        datepart(minute, t.MinStartTime) = datepart(minute, tnext.MinStartTime);

11
2018-03-05 04:31



也许上述解决方案假设Id列中没有漏洞。 - Riz
感谢您的时间和完美的解决方案......我将时间比作CONVERT(char(16),t1.MinStartTime,120)..所以它将返回时间达到几分钟......这是错误的方法吗? - Mahajan344
@Spenzo。 。 。不,这是一个很好的方法。但谁能记住所有的格式 convert(),所以我倾向于找到其他解决方案(例如答案中的那个)。 - Gordon Linoff
根据戈登的出色答案,进行了更为复杂的多表连接。 - ScottLenart
谢谢@GordonLinoff。你永远是超级巨星:) - ViKiNG


答案:


在你的情况下, ids似乎是数字,你可以做一个自我加入:

select t.*
from table t join
     table tnext
     on t.id = tnext.id - 1 and
        t.StatusId = 1 and
        tnext.StatusId = 6 and
        datediff(second, t.MinStartTime, tnext.MinStartTime) < 60;

这不是完全相同的一分钟。它在60秒内。你真的需要相同的日历时间分钟吗?如果是这样,你可以这样做:

select t.*
from table t join
     table tnext
     on t.id = tnext.id - 1 and
        t.StatusId = 1 and
        tnext.StatusId = 6 and
        datediff(second, t.MinStartTime, tnext.MinStartTime) < 60 and
        datepart(minute, t.MinStartTime) = datepart(minute, tnext.MinStartTime);

11
2018-03-05 04:31



也许上述解决方案假设Id列中没有漏洞。 - Riz
感谢您的时间和完美的解决方案......我将时间比作CONVERT(char(16),t1.MinStartTime,120)..所以它将返回时间达到几分钟......这是错误的方法吗? - Mahajan344
@Spenzo。 。 。不,这是一个很好的方法。但谁能记住所有的格式 convert(),所以我倾向于找到其他解决方案(例如答案中的那个)。 - Gordon Linoff
根据戈登的出色答案,进行了更为复杂的多表连接。 - ScottLenart
谢谢@GordonLinoff。你永远是超级巨星:) - ViKiNG


只需使用Gordon的基础创建的两个不同的表发布更复杂的联接。请原谅特定的对象名称,但你会得到要点。获取样本中从一个到下一个的百分比变化。

选择
      fm0.SAMPLE curFMSample
    ,fm1.SAMPLE nextFMSample
    ,fm0.TEMPERATURE curFMTemp
    ,fm1.TEMPERATURE nextFMTemp
    ,ABS(CAST((fm0.Temperature  -  fm1.Temperature)AS DECIMAL(4,0))/ CAST(fm0.TEMPERATURE AS DECIMAL(4,0)))AS fmTempChange
    ,fm0.GAUGE curFMGauge
    ,fm1.GAUGE nextFMGauge
    ,ABS(CAST((fm0.GAUGE  -  fm1.GAUGE)AS DECIMAL(4,4))/ CAST(fm0.GAUGE as DECIMAL(4,4)))AS fmGaugeChange
    ,fm0.WIDTH curFMWidth
    ,fm1.WIDTH nextFMWidth
    ,ABS(CAST((fm0.Width  -  fm1.Width)AS DECIMAL(4,2))/ CAST(fm0.Width AS DECIMAL(4,2)))AS fmWidthChange
    ,cl0.TEMPERATURE curClrTemp
    ,cl1.TEMPERATURE nextClrTemp
    ,ABS(CAST((cl0.Temperature  -  cl1.Temperature)AS DECIMAL(4,0))/ CAST(cl0.TEMPERATURE AS DECIMAL(4,0)))AS clrTempChange
从
    dbo.COIL_FINISHING_MILL_EXIT_STR02 fm0
    INNER JOIN dbo.COIL_FINISHING_MILL_EXIT_STR02 fm1 ON(fm0.SAMPLE = fm1.SAMPLE  -  1 AND fm1.coil = fm0.coil)
    INNER JOIN dbo.COIL_COILER_STR02 cl0 ON fm0.coil = cl0.coil AND fm0.SAMPLE = cl0.SAMPLE
    INNER JOIN dbo.COIL_COILER_STR02 cl1 ON(cl0.SAMPLE = cl1.SAMPLE  -  1 AND cl1.coil = cl0.coil)
哪里
    fm0.coil = 2015515872

0
2017-09-23 15:15





好吧,如果你没有顺序行id但是有不同的步骤(如果某些记录被删除,例如..),我建议一个非常简单的解决方案:

declare @t table(id int, obj_name varchar(5))

insert @t select 1,'a'

insert @t select 5,'b'

insert @t select 22,'c'

insert @t select 543,'d'

---------------------------------
select *from @t

示例源表@t:

---------------------------------
id  obj_name

1   a

5   b

22  c

543 d

---------------------------------

选择自我加入

select obj_name_prev=tt.obj_name, obj_name_next=min(t.obj_name)

from @t t

join @t tt on tt.id < t.id

group by tt.obj_name

结果:

---------------------------------
obj_name_prev   obj_name_next

a   b

b   c

c   d

---------------------------------

0
2018-02-08 14:38