我有一种情况,我需要在一个位置匹配资产的到达和离开。问题是资产移动并不总是按时间顺序输入数据库,也没有任何当前的方法将数据库中的到达和离开联系在一起。
注意事项:
表的结构(类似)如下:
CREATE TABLE Movements
(
MoveID int IDENTITY (1,1),
ItemID int,
EventType CHAR,
moveTime datetime,
LocID int,
ShelfID int,
altShelfID int
)
Run Code Online (Sandbox Code Playgroud)
我已经包含了测试数据:
SET IDENTITY_INSERT movements on
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(1,3,'A','2013-01-05 09:00',1,3,NULL)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(2,3,'D','2013-01-06 13:00',1,3,NULL)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(3,3,'A','2013-01-07 09:00',1,3,NULL)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(4,3,'A','2013-01-15 09:00',1,3,NULL)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(5,3,'D','2013-01-07 15:00',1,3,NULL)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(6,3,'A','2013-01-16 09:00',2,NULL,7)
INSERT INTO movements
(MoveID,ItemID,EventType,moveTime,LocID,ShelfID,altShelfID)
VALUES(7,3,'D','2013-01-15 12:00',1,3,NULL)
SET IDENTITY_INSERT movements off
Run Code Online (Sandbox Code Playgroud)
询问
SELECT CASE WHEN sch_A.itemID IS NULL THEN Sch_D.itemID
ELSE Sch_A.itemID
END AS ID ,
Sch_A.moveTime AS Arrival_Time ,
Sch_D.moveTime AS Departure_Time ,
Sch_A.LocID ,
Sch_A.ShelfID ,
Sch_A.AltShelfID ,
Sch_D.LocID ,
Sch_D.ShelfID ,
Sch_D.AltShelfID ,
Sch_A.MoveID AS ArrivalMoveID ,
Sch_D.MoveID AS DepartureMoveID
FROM Movements Sch_A
FULL JOIN Movements Sch_D ON Sch_A.itemID = Sch_D.itemID
AND Sch_A.LocID = Sch_D.LocID
AND ISNULL(Sch_A.ShelfID,
0) = ISNULL(Sch_D.ShelfID,
0)
AND ISNULL(Sch_A.AltShelfID,
0) = ISNULL(Sch_D.AltShelfID,
0)
AND Sch_A.MoveID != Sch_D.MoveID
AND Sch_A.moveTime <= Sch_D.moveTime
WHERE ( Sch_A.EventType != 'D'
OR Sch_A.EventType IS NULL
)
AND ( Sch_D.EventType != 'A'
OR Sch_D.EventType IS NULL
)
Run Code Online (Sandbox Code Playgroud)
返回的结果多次与同一日程表匹配:
3 2013-01-05 09:00:00.000 2013-01-06 13:00:00.000 1 3 NULL 1 3 NULL 1 2
3 2013-01-05 09:00:00.000 2013-01-07 15:00:00.000 1 3 NULL 1 3 NULL 1 5
3 2013-01-05 09:00:00.000 2013-01-15 12:00:00.000 1 3 NULL 1 3 NULL 1 7
3 2013-01-07 09:00:00.000 2013-01-07 15:00:00.000 1 3 NULL 1 3 NULL 3 5
3 2013-01-07 09:00:00.000 2013-01-15 12:00:00.000 1 3 NULL 1 3 NULL 3 7
3 2013-01-15 09:00:00.000 2013-01-15 12:00:00.000 1 3 NULL 1 3 NULL 4 7
3 2013-01-16 09:00:00.000 NULL 2 NULL 7 NULL NULL NULL 6 NULL
Run Code Online (Sandbox Code Playgroud)
我想看到的是以下内容:
3 2013-01-05 09:00:00.000 2013-01-06 13:00:00.000 1 3 NULL 1 3 NULL 1 2
3 2013-01-07 09:00:00.000 2013-01-07 15:00:00.000 1 3 NULL 1 3 NULL 3 5
3 2013-01-15 09:00:00.000 2013-01-15 12:00:00.000 1 3 NULL 1 3 NULL 4 7
3 2013-01-16 09:00:00.000 NULL 2 NULL 7 NULL NULL NULL 6 NULL
Run Code Online (Sandbox Code Playgroud)
如何减少日程表的重复匹配?谢谢。
更新:正如保罗在下面建议的那样,我可以尝试制作一个相关列来即时匹配项目。执行以下操作有什么危险:
SELECT CASE WHEN sch_A.itemID IS NULL THEN Sch_D.itemID
ELSE Sch_A.itemID
END AS ID ,
Sch_A.moveTime AS Arrival_Time ,
Sch_D.moveTime AS Departure_Time ,
Sch_A.LocID ,
Sch_A.ShelfID ,
Sch_A.AltShelfID ,
Sch_D.LocID ,
Sch_D.ShelfID ,
Sch_D.AltShelfID ,
Sch_A.MoveID AS ArrivalMoveID ,
Sch_D.MoveID AS DepartureMoveID
FROM Movements Sch_A
FULL JOIN Movements Sch_D
ON Sch_A.itemID = Sch_D.itemID
AND Sch_D.MoveID = (select top 1 MoveID from movements i
where i.EventType = 'D' and Sch_A.movetime < i.movetime
AND Sch_A.itemID = i.itemID
AND Sch_A.LocID = i.LocID
AND ISNULL(Sch_A.ShelfID,
0) = ISNULL(i.ShelfID,
0)
AND ISNULL(Sch_A.AltShelfID,
0) = ISNULL(i.AltShelfID,
0)
AND Sch_A.MoveID != i.MoveID
order by i.moveTime ASC)
WHERE ( Sch_A.EventType != 'D'
OR Sch_A.EventType IS NULL
)
AND ( Sch_D.EventType != 'A'
OR Sch_D.EventType IS NULL
)
Run Code Online (Sandbox Code Playgroud)
有点难看,但我只能自己预先计算才能做到这一点。
update movements
set linkTime = (select top 1 movetime from movements i
where i.EventType = 'D' and movements.movetime < i.movetime
and movements.locid = i.locid
order by i.moveTime asc)
where movements.EventType = 'A'
select a.*, d.*
from (select * from movements
where EventType = 'A') as a
left outer join (select * from movements
where EventType = 'D') as d ON a.locid = d.locid AND a.linktime = d.movetime
Run Code Online (Sandbox Code Playgroud)
本质上,我预先计算了您在 UPDATE 语句中讨论的链接,然后使用它在 SELECT 中根据需要进行链接。我错过了一些与示例数据无关的列(itemID 等)。
插入到 #temporary 表中可能比永久向运动添加新列更有意义,但这将取决于本地知识..
注意:linkTime 是添加到移动表中的日期时间类型的新列