繁体   English   中英

SQL Server如何按顺序选择第一行

[英]SQL Server how to select first row in sequence

我有一个包含以下示例数据的表:

Tag          Loc        Time1
A            10         6/2/15 8:00 AM
A            10         6/2/15 7:50 AM
A            10         6/2/15 7:30 AM
A            20         6/2/15 7:20 AM
A            20         6/2/15 7:15 AM
B            10         6/2/15 7:12 AM
B            10         6/2/15 7:11 AM
A            10         6/2/15 7:10 AM
A            10         6/2/15 7:00 AM

我需要SQL来选择序列中第一个(最早的)行,直到位置发生变化,然后再次选择最早的行,直到位置发生变化。 换句话说,我需要以上输出:

Tag         Loc         Time1
A           10          6/2/15 7:30 AM
A           20          6/2/15 7:15 AM
A           10          6/2/15 7:00 AM
B           10          6/2/15 7:11 AM

我在Giorgos尝试了这个 - 但是选择中的一些行是重复的:

declare @temptbl table (rowid int primary key identity, tag nvarchar(1), loc int, time1 datetime)
declare @tag as nvarchar(1), @loc as int, @time1 as datetime

insert into @temptbl (tag, loc, time1) values (1,20,'6/5/2015 7:15 AM')
insert into @temptbl (tag, loc, time1) values (1,20,'6/5/2015 7:20 AM')
insert into @temptbl (tag, loc, time1) values (1,20,'6/5/2015 7:25 AM')
insert into @temptbl (tag, loc, time1) values (4,20,'6/5/2015 7:20 AM')
insert into @temptbl (tag, loc, time1) values (4,20,'6/5/2015 7:25 AM')
insert into @temptbl (tag, loc, time1) values (4,20,'6/5/2015 7:30 AM')
insert into @temptbl (tag, loc, time1) values (4,20,'6/5/2015 7:35 AM')
insert into @temptbl (tag, loc, time1) values (4,20,'6/5/2015 7:40 AM')

select * from @temptbl

SELECT Tag, Loc, MIN(Time1) as time2
FROM (
SELECT Tag, Loc, Time1,      
       ROW_NUMBER() OVER (ORDER BY Time1) - 
       ROW_NUMBER() OVER (PARTITION BY Tag, Loc 
                          ORDER BY Time1) AS grp
FROM @temptbl ) t

GROUP BY Tag, Loc, grp

结果如下(每个标签应该只有一行)

Tag  Loc time2
1   20  2015-06-05 07:15:00.000
1   20  2015-06-05 07:25:00.000
4   20  2015-06-05 07:20:00.000
4   20  2015-06-05 07:30:00.000

假设您正在使用MS SQL Server 2012或更高版本, lag窗口函数将允许您将行与前一行进行比较:

SELECT tag, loc, time1
FROM   (SELECT tag, loc, time1,
               LAG (loc) OVER (PARTITION BY tag ORDER BY time1) AS lagloc
        FROM   my_table) t 
WHERE  loc != lagloc OR lagloc IS NULL

如果您使用SQL Server 2012之前的版本,这是一个替代解决方案:

SELECT Tag, Loc, MIN(Time1)
FROM (
SELECT Tag, Loc, Time1,      
       ROW_NUMBER() OVER (ORDER BY Time1) - 
       ROW_NUMBER() OVER (PARTITION BY Tag, Loc 
                          ORDER BY Time1) AS grp
FROM mytable ) t
GROUP BY Tag, Loc, grp

它应该适用于SQL Server 2005+。

ROW_NUMBER()是为了确定连续海岛使用TagLoc记录: grp将举行属于同一组的所有记录的值相同

编辑:如果表行排序不是基于Time1列,则Time1必须由任何列指定行顺序替换,例如自动增量PK。

在这里演示

请试试这个:

; with t --Samples
as (
select *
from (values 
('A',            10         ,'6/2/15 8:00 AM')
, ('A',            10         ,'6/2/15 7:50 AM')
, ('A',            10         ,'6/2/15 7:30 AM')
, ('A',            20         ,'6/2/15 7:20 AM')
, ('A',            20         ,'6/2/15 7:15 AM')
, ('B',            10         ,'6/2/15 7:12 AM')
, ('B',            10         ,'6/2/15 7:11 AM')
, ('A',            10         ,'6/2/15 7:10 AM')
, ('A',            10         ,'6/2/15 7:00 AM')
) t(Tag, Loc, Time1)
)
, t2 --get the origin order
as (
select *, ROW_NUMBER() over (order by (select null)) OriginOrder
from t)
, t3 --detect the tag, and loc changes (last row in group)
as (
select t2.*
from t2
    left join t2 t on t.OriginOrder=t2.OriginOrder+1 --get the next row
where not(t2.Tag = t.Tag and t2.Loc = t.Loc) --the next row has other tag and/or loc
    or (t.OriginOrder is null) --or there isn't next row
)
, t4 --make the groups about the next row
as (
select *, ROW_NUMBER() over (order by t3.OriginOrder) GroupOrder
from t3
)
, t5 --detect the tag, and loc changes (first row in group)
as (
select t2.*
from t2
    left join t2 t on t.OriginOrder=t2.OriginOrder-1 --get the previous row
where not(t2.Tag = t.Tag and t2.Loc = t.Loc) --the previous row has other tag and/or loc
    or (t.OriginOrder is null) --or there isn't previous row
)
, t6 --make the groups about the previous row
as (
select *, ROW_NUMBER() over (order by t5.OriginOrder) GroupOrder
from t5
)
--The result
select t2.Tag, t2.Loc, t2.Time1
from t4 
    join t6 on t4.GroupOrder=t6.GroupOrder
    cross apply (select top 1 * from t2 where t2.OriginOrder between t6.OriginOrder and t4.OriginOrder order by t2.Time1) t2

我评论我的查询,所以我认为这是可以理解的。

你可以试试这个,改变yourTable与表的名称你想

declare @temptbl table (rowid int primary key identity, tag nvarchar(1), loc int, time1 datetime)

declare @tag as nvarchar(1), @loc as int, @time1 as datetime

declare tempcur cursor for 
select tag, loc, time1
from YourTable
-- order here by time or whatever columns you want to

open tempcur

fetch next from tempcur
into @tag, @loc, @time1

while (@@fetch_status = 0)
begin
    if not exists (select top 1 * from @temptbl where tag = @tag and loc = @loc and rowid = (select max(rowid) from @temptbl))
    begin
        print 'insert'
        print @tag
        print @loc
        print @time1
        insert into @temptbl (tag, loc, time1) values (@tag, @loc, @time1)
    end
    else
    begin
        print 'update'
        print @tag
        print @loc
        print @time1
        update @temptbl
        set tag = @tag,
            loc = @loc,
            time1 = @time1
         where tag = @tag and loc = @loc and rowid = (select max(rowid) from @temptbl)
    end


    fetch next from tempcur
    into @tag, @loc, @time1
end

deallocate tempcur

select * from @temptbl

考虑到这一点,我想知道是否有办法不使用游标。 这似乎有效:


SELECT t1.tag, t1.loc, t1.time1 
FROM( 
     SELECT tag, loc, time1, ROW_NUMBER() over (PARTITION BY tag ORDER by tag, 
     time1) AS row1 
     FROM @temptbl) t1
LEFT JOIN (
     SELECT tag, loc, time1, ROW_NUMBER() over (PARTITION BY tag ORDER by tag, 
     time1) AS row1 
     FROM @temptbl) t2
ON t1.row1=t2.row1+1 AND t1.tag=t2.tag
WHERE t2.tag IS NULL OR t1.loc <> t2.loc
ORDER BY tag, time1 DESC

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM