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 200 0 VJ23 0 50 VJ23 30 0Sql 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
那么您想要所有按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