使用交叉应用和透视转换 SQL 中的分段时间段

问题描述 投票:0回答:2

我的核心表数据如下所示。它正在跟踪订单状态。

身份证 零件编号 已进入 选择时间 交货时间
100 50A 2024-03-28 08:59:13.727 2024-03-28 09:30:20.237 2024-03-28 09:56:42.570
125 60B 2024-03-28 08:59:22.290 2024-03-28 09:31:32.543 2024-03-28 09:56:50.683
171 50A 2024-03-28 14:31:28.480
211 70B 2024-03-28 14:31:33.613

我需要编写一个查询将其转换为这种格式:

t_邮票 50A_100 60B_125 50A_171 70B_211
2024-03-28 08:59:13.727 已输入
2024-03-28 08:59:22.290 已输入
2024-03-28 09:30:20.237 已挑选
2024-03-28 09:31:32.543 已挑选
2024-03-28 09:56:42.570 已交付
2024-03-28 09:56:50.683 已交付
2024-03-28 14:31:28.480 已输入
2024-03-28 14:31:33.613 已输入

换句话说,我需要创建一个

t_stamp
列,其中包含原始表中的每个时间戳。我需要为每个 ID 指定一个名为
[PartNum]_[ID]
的列。我需要根据原始时间戳来自的列返回 ENTERED、PICKED 或 DELIVERED。如果 t_stamp 与给定列中的任何信息都不对应,我只需返回 null。据我所知,如果源数据中有大量 ID,并且有大量空值,将会有大量列。

这就是我所得到的。我可以通过将其放入

WHERE
子句来手动获取每个 ID 所需的数据,但我不知道如何使用
PIVOT
来获取每个 ID + PartNum 组合的列。
PIVOT
是否是合适的工具?

Select B.* 
 From  MyTable A
 CROSS APPLY (VALUES (EnteredOn,'ENTERED')
                     ,(PickedTime,'PICKED')
                     ,(DeliveredTime,'DELIVERED')
             ) B(t_stamp,[Status])
WHERE ID = 100
ORDER BY t_stamp ASC

该查询返回这些结果。如何将每个 ID(来自上面的原始结果)合并到其自己的列中并如上所述插入空值?

t_邮票 状态
2024-03-28 08:59:13.727 已输入
2024-03-28 09:30:20.237 已挑选
2024-03-28 09:56:42.570 已交付
sql sql-server pivot sql-server-2008-r2
2个回答
0
投票

数据

CREATE TABLE mytable(
   ID            INTEGER  NOT NULL 
  ,PartNum       VARCHAR(40) NOT NULL
  ,EnteredOn     VARCHAR(40) NOT NULL
  ,PickedTime    VARCHAR(40)
  ,DeliveredTime VARCHAR(40)
);
INSERT INTO mytable(ID,PartNum,EnteredOn,PickedTime,DeliveredTime) VALUES 
(100,'50A','2024-03-28 08:59:13.727','2024-03-28 09:30:20.237','2024-03-28 09:56:42.570'),
(125,'60B','2024-03-28 08:59:22.290','2024-03-28 09:31:32.543','2024-03-28 09:56:50.683'),
(171,'50A','2024-03-28 14:31:28.480',NULL,NULL),
(211,'70B','2024-03-28 14:31:33.613',NULL,NULL);

同时使用逆透视和透视

select *
from 
(
 select CONCAT(PartNum,'_',ID) COL
  ,st,
  t_stamp
from (select ID,PartNum,
  EnteredOn as Entered,
  PickedTime as Picked,
  DeliveredTime as Delivered
  from mytable) m
unpivot
(
  t_stamp
  for st in ([Entered]
      ,[Picked]
      ,[Delivered]
      )
) unpiv
) src
pivot
(
  max(st)
  for COL in ([50A_100], [60B_125], [50A_171],[70B_211])
) piv;

dbfiddle


0
投票

类似这样的:

SELECT  t_stamp
,   max(CASE WHEN partnum = '50A' AND id = 100 THEN Status END) AS [50A_100]
,   max(CASE WHEN partnum = '60B' AND id = 125 THEN Status END) AS [60B_125]
,   max(CASE WHEN partnum = '50A' AND id = 171 THEN Status END) AS [50A_171]
,   max(CASE WHEN partnum = '70B' AND id = 211 THEN Status END) AS [70B_211]
FROM
(
    VALUES  (100, N'50A', N'2024-03-28 08:59:13.727', N'2024-03-28 09:30:20.237', N'2024-03-28 09:56:42.570')
    ,   (125, N'60B', N'2024-03-28 08:59:22.290', N'2024-03-28 09:31:32.543', N'2024-03-28 09:56:50.683')
    ,   (171, N'50A', N'2024-03-28 14:31:28.480', NULL, NULL)
    ,   (211, N'70B', N'2024-03-28 14:31:33.613', NULL, NULL)
) t (ID,PartNum,EnteredOn,PickedTime,DeliveredTime)
CROSS APPLY (VALUES (EnteredOn,'ENTERED')
                     ,(PickedTime,'PICKED')
                     ,(DeliveredTime,'DELIVERED')
             ) B(t_stamp,[Status])
WHERE   t_stamp IS NOT NULL
GROUP BY t_stamp

这只是一个普通的条件聚合,其中 MAX(CASE WHEN) 为您感兴趣的每个部分创建列。

© www.soinside.com 2019 - 2024. All rights reserved.