如何用 T-SQL 查询多条装配线的产品进入和退出时间?
可以去掉固定的 'MAIN' 条件,分别按“进入的装配线 + ChassisNumber”和“退出的装配线 + ChassisNumber”分组,再用装配线和 ChassisNumber 对两组结果进行 FULL OUTER JOIN。输出的 AssemblyLine 也要改为实际装配线名称,原来的 'AssemblyLine' 是固定字符串。
修改后的查询
查询保留了原来的日期范围和地点条件,仍然为每组取最早进入时间和最晚退出时间:
;WITH FilteredMoves AS
(
SELECT
ChassisNumber,
TimeStamp,
ToAssemblyLineName,
FromAssemblyLineName
FROM DIM.ChassisMoveLog
WHERE TimeStamp >= CAST(
DATEADD(DAY, -1, CAST(GETDATE() AS DATE))
AS DATETIME
)
AND TimeStamp < CAST(CAST(GETDATE() AS DATE) AS DATETIME)
AND PhysicalLocation = 'Chillicothe'
),
Enters AS
(
SELECT
ToAssemblyLineName AS AssemblyLine,
ChassisNumber,
MIN(TimeStamp) AS MinTime
FROM FilteredMoves
WHERE ToAssemblyLineName <> FromAssemblyLineName
GROUP BY
ToAssemblyLineName,
ChassisNumber
),
Exits AS
(
SELECT
FromAssemblyLineName AS AssemblyLine,
ChassisNumber,
MAX(TimeStamp) AS MaxTime
FROM FilteredMoves
WHERE FromAssemblyLineName <> ToAssemblyLineName
GROUP BY
FromAssemblyLineName,
ChassisNumber
)
SELECT
COALESCE(Enters.AssemblyLine, Exits.AssemblyLine) AS AssemblyLine,
COALESCE(Enters.ChassisNumber, Exits.ChassisNumber) AS ChassisNumber,
Enters.MinTime AS EnterTime,
Exits.MaxTime AS ExitTime
FROM Enters
FULL OUTER JOIN Exits
ON Enters.AssemblyLine = Exits.AssemblyLine
AND Enters.ChassisNumber = Exits.ChassisNumber
ORDER BY
AssemblyLine ASC,
EnterTime ASC,
ExitTime ASC;
这个查询假设两个装配线字段中的非 NULL 名称都属于需要统计的装配线。如果其中还包含仓库、场外区域等名称,需要根据实际的装配线清单,分别限制进入侧的 ToAssemblyLineName 和退出侧的 FromAssemblyLineName。
为什么分组和关联条件都要增加装配线
原查询通过 'MAIN' 限定了装配线,只按 ChassisNumber 分组就能得到 MAIN 的结果。扩展到多条装配线后,同一产品可能经过不同装配线,需要分别汇总:
- 进入记录按
ToAssemblyLineName, ChassisNumber分组。 - 退出记录按
FromAssemblyLineName, ChassisNumber分组。 - 进入和退出结果按
AssemblyLine, ChassisNumber同时关联。
如果关联时仍然只使用 ChassisNumber,同一产品在不同装配线上的进入和退出记录就可能错误组合。
条件 ToAssemblyLineName <> FromAssemblyLineName 用来排除起点和终点为同一装配线的记录。例如,一条从 A 转到 B 的记录会贡献 A 的退出时间和 B 的进入时间。
FULL OUTER JOIN 会保留两侧未匹配的结果:只有进入记录时,ExitTime 为 NULL;只有退出记录时,EnterTime 为 NULL。
NULL 值需要根据业务含义处理
上面的查询沿用了原查询中 <> 对 NULL 的处理方式:只要起点或终点为 NULL,比较条件就不会成立,该记录不会进入汇总。
如果业务规定 NULL 表示“装配线外”,并且这些进出记录也要统计,可以将 Enters 的条件替换为:
WHERE ToAssemblyLineName IS NOT NULL
AND (
FromAssemblyLineName IS NULL
OR ToAssemblyLineName <> FromAssemblyLineName
)
将 Exits 的条件替换为:
WHERE FromAssemblyLineName IS NOT NULL
AND (
ToAssemblyLineName IS NULL
OR FromAssemblyLineName <> ToAssemblyLineName
)
采用这种处理前,需要确认 NULL 的业务含义。如果 NULL 表示数据缺失,直接将其当作装配线外可能影响统计准确性。
统计范围与进出配对的限制
日期条件根据 SQL Server 的 GETDATE(),取前一天零点到当天零点的记录,包含开始时间,不包含结束时间。如果报表需要支持任意日期,可以将这两个边界改为传入的开始时间和结束时间参数。
查询得到的是筛选范围内每个“装配线 + 产品”的最早进入时间和最晚退出时间。如果同一产品一天内多次进出同一装配线,这些记录会汇总为一行,两个时间不一定属于同一次停留。
跨日期的记录也不会自动配对。例如,产品前天进入、昨天退出,查询昨天的数据时只会显示退出时间。如果需要逐次进出配对或计算每次停留时长,还需要明确重复进入、缺失退出和跨日期记录的处理规则,再设计按事件顺序配对的查询。
备注:内容仅供参考。
