ROW_NUMBER不按行顺序应用

时间:2016-06-10 02:09:09

标签: sql sql-server join sql-server-2012 sequence

使用SQL SERVER 2012 我有一个要求,我必须稍微清理源以获得所需的输出。

我有车辆名称,GPSTime,登录/注销,DriverID作为列。 由于源数据不干净,我们正在尝试生成一个表格,这个表格更清晰,每个登录都有后续注销。

我有以下数据

Vehicle         GPS      Login/Logoff  Driver 

Veh1 28-01-2016 06:30 Login D1 Veh1 28-01-2016 06:35 Login D1 Veh1 28-01-2016 06:40 Login D1 Veh1 28-01-2016 09:40 Logoff D1 Veh1 28-01-2016 10:30 Login D2 Veh1 28-01-2016 12:30 Logoff D2 Veh1 28-01-2016 15:30 Login D1 Veh1 28-01-2016 17:30 Logoff D1

我正在尝试将输出作为

Veh1 28-01-2016 06:30 Login D1 --> Tricky bit to take the first login Veh1 28-01-2016 09:40 Logoff D1 Veh1 28-01-2016 10:30 Login D2 Veh1 28-01-2016 12:30 Logoff D2 Veh1 28-01-2016 15:30 Login D1 Veh1 28-01-2016 17:30 Logoff D1

我尝试了row_number,ROW_NUMBER()OVER(PARTITION BY DriverID ORDER BY GPSTime asc)的方法,但无论我做什么,它为该驱动程序的所有登录连续放置序列号,尽管它不是相邻的行。我计划使用所需的序列号来增强逻辑以获得所需的输出。

还有其他方法吗?任何建议都会有所帮助。

此致 乔

3 个答案:

答案 0 :(得分:0)

所以打破问题。你拥有的是登出后所有登录的列表。

按照您想要的顺序获取登录列表很容易

 SELECT t1.VEH, t1.DRIVE, t1.TimeStamp
 FROM tablename t1
 WHERE t1.LoginLogoff = 'Login'
 ORDER BY t1.TimeStamp ASC

现在您必须将注销“插入”到此列表中。如果您只想退出时间

简单的方法是执行子查询并提取所需的值

 SELECT t1.VEH, t1.DRIVE, t1.TimeStamp as LoginTS,
    (Select t2.TimeStamp
     FROM tableName t2
     WHERE t2.LoginLogoff = 'Logoff'
       and t1.VEH = t2.VEH
       and t1.DRIVE = t2.DRIVE
       and t2.TimeStamp > t1.TimeStamp
     ORDER BY t2.TimeStamp ASC
     FETCH FIRST 1 ROW ONLY
   ) AS LogoutTS
 FROM tablename t1
 WHERE t1.LoginLogoff = 'Login'
 ORDER BY t1.TimeStamp ASC

你也可以把它作为一个加入,但我会把它留给你。

如果你真的需要两行,你可以交叉连接到一个两行表来“拉出”你需要的值。

答案 1 :(得分:0)

您的要求不是很清楚,但听起来您想要删除连续登录或注销的行(每个驱动程序?),并且只在登录/注销状态发生变化时保留第一行。

如果是这种情况,那么使用select t.vehicle, t.gps, t.login_logoff, t.driver from (select t.*, case when lag(login_logoff) over (partition by driver order by gps) = login_logoff then 1 else 0 end as is_duplicate_row from tbl t) t where t.is_duplicate_row = 0 order by t.gps 窗口函数可以派上用场。

这是一个查询,可以让您了解如何完成此任务:

<h2 class="highlightText3">SERVICES</h2>
<figure class="image-wrapper">
  <img class="bigImages" src="https://images.unsplash.com/photo-1465152251391-e94453ee3f5a?ixlib=rb-0.3.5&q=80&fm=jpg&crop=entropy&s=2f3699fc4dbc682fbecdc4fa4d5f6cad" alt="Surfing a big wave">
</figure>

答案 2 :(得分:0)

在插入或更新此表时,您可以增加一个额外的列并将其标记为适合。这比编写复杂查询更容易。

无论如何,我只尝试过你现有的桌面设计。我认为你需要每辆车的登录注销状态。 您可以尝试使用其他示例数据,并告诉我它无法正常工作的地方。

declare @t table(Vehicle varchar(50),GPS datetime,Login_Logoff varchar(50),Driver varchar(50))
insert into @t values
 ('Veh1','2016-01-28 06:30','Login','D1')
,('Veh1','2016-01-28 06:35','Login','D1')
,('Veh1','2016-01-28 06:40','Login','D1')
,('Veh1','2016-01-28 09:40','Logoff','D1')
,('Veh1','2016-01-28 10:30','Login','D2')
,('Veh1','2016-01-28 12:30','Logoff','D2')
,('Veh1','2016-01-28 15:30','Login','D1')
,('Veh1','2016-01-28 17:30','Logoff','D1')

;

WITH CTE
AS (
    SELECT *
        ,row_number() OVER (
            PARTITION BY vehicle ORDER BY gps
            ) rn
    FROM @t
    )
    ,CTE1
AS (
    SELECT vehicle
        ,gps
        ,Login_Logoff
        ,driver
        ,rn
    FROM cte
    WHERE rn = 1

    UNION ALL

    SELECT a.vehicle
        ,CASE 
            WHEN b.driver = a.Driver
                AND a.Login_Logoff <> b.Login_Logoff
                THEN a.gps
            WHEN b.driver <> a.Driver
                THEN a.gps
            END
        ,a.login_logoff
        ,a.Driver
        ,b.rn + 1
    FROM cte a
    INNER JOIN CTE1 b ON a.rn = b.rn + 1
    WHERE a.rn <= 8
    )
SELECT vehicle
    ,gps
    ,Login_Logoff
    ,driver
FROM cte1
WHERE gps IS NOT NULL