使用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)的方法,但无论我做什么,它为该驱动程序的所有登录连续放置序列号,尽管它不是相邻的行。我计划使用所需的序列号来增强逻辑以获得所需的输出。
还有其他方法吗?任何建议都会有所帮助。
此致 乔
答案 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