PAYATHON 2026

如何用 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(),取前一天零点到当天零点的记录,包含开始时间,不包含结束时间。如果报表需要支持任意日期,可以将这两个边界改为传入的开始时间和结束时间参数。

查询得到的是筛选范围内每个“装配线 + 产品”的最早进入时间和最晚退出时间。如果同一产品一天内多次进出同一装配线,这些记录会汇总为一行,两个时间不一定属于同一次停留。

跨日期的记录也不会自动配对。例如,产品前天进入、昨天退出,查询昨天的数据时只会显示退出时间。如果需要逐次进出配对或计算每次停留时长,还需要明确重复进入、缺失退出和跨日期记录的处理规则,再设计按事件顺序配对的查询。

备注:内容仅供参考。