Sql server 每当另一个字段值为零时,返回该字段的最大值

Sql server 每当另一个字段值为零时,返回该字段的最大值,sql-server,Sql Server,我有这样一个表结构: name idletime speed RJ14 300 0 RJ14 360 0 RJ14 400 0 RJ14 0 30 RJ14 50 0 VJ23 100 0 VJ23 160 0 VJ23 2

我有这样一个表结构:

name idletime speed RJ14 300 0 RJ14 360 0 RJ14 400 0 RJ14 0 30 RJ14 50 0 VJ23 100 0 VJ23 160 0 VJ23 200 0 VJ23 0 50 VJ23 30 0
那么您想要所有按ID排序的最大空闲记录,以及之后没有非空闲记录的所有记录

这比我想象的要复杂。您可以通过使用多个CTE来简化:

WITH CTE AS
(
    SELECT ID, Name, IdleTime, Speed,
           RN = ROW_NUMBER() OVER (PARTITION BY Name ORDER BY ID ASC)
    FROM dbo.TableName t
)
, Idles AS
(
    SELECT ID, Name, IdleTime, Speed, RN 
    FROM CTE
    WHERE Speed = 0 AND IdleTime <> 0
)
, NonIdles AS
(
    SELECT ID, Name, IdleTime, Speed, RN
    FROM CTE
    WHERE Speed <> 0 AND IdleTime = 0
)
SELECT ID, Name, IdleTime, Speed
FROM Idles i
WHERE NOT EXISTS
(
    SELECT 1 FROM Idles i2
    WHERE  i.Name = i2.Name AND i2.RN > i.RN
)
OR EXISTS
(
    SELECT 1 FROM NonIdles ni
    WHERE  i.Name = ni.Name AND i.RN + 1 = ni.RN 
)

对于您的示例数据

,我尝试了一种解决此问题的编程方法。这对我来说是成功的。下面的查询选择速度=0时的最大怠速时间和速度从非零值再次变为0的第一个怠速时间值

 Create table stack (id varchar(5), id1 int, id2 int)
 INSERT INTO STACK
 VALUES

 ('RJ14'  ,     300     ,      0     ),
 ('RJ14'  ,     360     ,      0     ),
 ('RJ14'  ,     400     ,      0     ),
 ('RJ14'  ,      0      ,      30    ),
 ('RJ14'  ,     50      ,      0     ),
 ('VJ23'  ,     100     ,      0     ),
 ('VJ23'  ,     160     ,      0     ),
 ('VJ23'  ,     200     ,      0     ),
 ('VJ23'  ,      0      ,      50    ),
 ('VJ23'  ,      30     ,      0     )

 declare @stack as table (name varchar(5),idletime int, id2 int, rws int)
 declare @val   as table (name varchar(5),idletime int )

 insert into @stack
 SELECT ID,ID1 idletime, id2, row_number() over(order by id ) as rws
 FROM STACK

 declare @id    int = 1
 declare @count int 
 declare @value int = 0

 select @count = count (*) from @stack

 while (@id <= @count)
 begin

     select @value = ID2 from @stack where rws = @id and id2 <> 0
     if @value <> 0
     begin
         insert into @val
         select name, idletime 
         from @stack
         where rws = @id -1
         union
         select name, idletime from
         @stack where rws = @id + 1
      end  
         select @id    = @id + 1
         select @value = 0
  end

  select *from @val ORDER BY NAME, idletime DESC
下面是同样的SQL-FIDLE

当特定名称的速度大于零时,空闲时间变为零。每次空闲时间变为零之前,我都需要它的值

每行都有一个唯一的id

质疑

然后,我们得到行号RN,其中下一行的速度为0:

要最终选择这些行号的所需列,请执行以下操作:

SELECT name,idletime
FROM numberedidletable
WHERE speed = 0 AND
      RN IN (

... 

             )
ORDER BY RN
假设

空闲时间对于每个部分都是增量的。 id是唯一的id 输出


什么是最大值?您不是简单地选择了速度为0的所有空闲时间吗?我看不出您是按名称分组的,所以我不理解最大值。@AbhishekAgrawal:现在越来越清楚了,但我缺少了一个指示顺序的列,例如datetime列。如果没有datetime列,则应更改该列或至少使用主键列。无法对数据排序。您有时间或id列吗?@bmsqldev:它们是RJ14和VJ23的最后一个值,所以我认为应该包括它们。@bmsqldev我相信idletime总是递增的,这就是为什么最后一个值是预期的。但是每次变为零之前的idletime值仍然是真的,并且预期的outputNeat方法+1!不确定是否会发生这种情况,因为OP没有指定,但您的解决方案可能会返回更多连续idletime=0值的行。是的,它会返回更多值。我想你的解决方案也能解决这个问题。我想我确保了它不会在速度为0的主管道上出现。。我正试图复制它,但我做不到。谢谢你的解决方案。出色的工作和解释。此解决方案正在工作,但它占用了太多的时间。在名称上有索引应该是有效的
 Create table stack (id varchar(5), id1 int, id2 int)
 INSERT INTO STACK
 VALUES

 ('RJ14'  ,     300     ,      0     ),
 ('RJ14'  ,     360     ,      0     ),
 ('RJ14'  ,     400     ,      0     ),
 ('RJ14'  ,      0      ,      30    ),
 ('RJ14'  ,     50      ,      0     ),
 ('VJ23'  ,     100     ,      0     ),
 ('VJ23'  ,     160     ,      0     ),
 ('VJ23'  ,     200     ,      0     ),
 ('VJ23'  ,      0      ,      50    ),
 ('VJ23'  ,      30     ,      0     )

 declare @stack as table (name varchar(5),idletime int, id2 int, rws int)
 declare @val   as table (name varchar(5),idletime int )

 insert into @stack
 SELECT ID,ID1 idletime, id2, row_number() over(order by id ) as rws
 FROM STACK

 declare @id    int = 1
 declare @count int 
 declare @value int = 0

 select @count = count (*) from @stack

 while (@id <= @count)
 begin

     select @value = ID2 from @stack where rws = @id and id2 <> 0
     if @value <> 0
     begin
         insert into @val
         select name, idletime 
         from @stack
         where rws = @id -1
         union
         select name, idletime from
         @stack where rws = @id + 1
      end  
         select @id    = @id + 1
         select @value = 0
  end

  select *from @val ORDER BY NAME, idletime DESC
;WITH numberedidletable AS
(
  SELECT id,name,idletime,speed, 
    ROW_NUMBER() OVER (ORDER BY name,id) AS RN
  FROM idletable
)

SELECT name,idletime
FROM numberedidletable
WHERE speed = 0 AND
      RN IN (
                (SELECT RN-1
                 FROM numberedidletable tmpnit
                 WHERE speed<>0 AND
                       numberedidletable.name = tmpnit.name)
            UNION ALL
                (SELECT MAX(RN)
                  FROM numberedidletable
                  GROUP BY name)
             )
ORDER BY RN
;WITH numberedidletable AS
(
  SELECT id,name,idletime,speed, 
    ROW_NUMBER() OVER (ORDER BY name,id) AS RN
  FROM idletable
)
            (SELECT RN-1
             FROM numberedidletable tmpnit
             WHERE speed<>0 AND
                   numberedidletable.name = tmpnit.name)
        UNION ALL
            (SELECT MAX(RN)
              FROM numberedidletable
              GROUP BY name)
SELECT name,idletime
FROM numberedidletable
WHERE speed = 0 AND
      RN IN (

... 

             )
ORDER BY RN
name    idletime
RJ14    400
RJ14    50
VJ23    200
VJ23    30