在SQL Server中填充值
我有一个表projects,以及对那些projectstatus列的更改日志:OldStatus和NewStatus 我想计算以下期间的项目状态:在SQL Server中填充值,sql,sql-server,sql-server-2016,Sql,Sql Server,Sql Server 2016,我有一个表projects,以及对那些projectstatus列的更改日志:OldStatus和NewStatus 我想计算以下期间的项目状态: Project_ID Period OldStatus NewStatus 123 201705 NULL NULL 123 201706 NULL NULL 123 201707 A D 123 201708 NULL
Project_ID Period OldStatus NewStatus
123 201705 NULL NULL
123 201706 NULL NULL
123 201707 A D
123 201708 NULL NULL
123 201709 NULL NULL
123 201710 NULL NULL
123 201711 D A
123 201712 NULL NULL
123 201713 NULL NULL
我的理想输出:
Project_ID Period Status
123 201705 A
123 201706 A
123 201707 D
123 201708 D
123 201709 D
123 201710 D
123 201711 A
123 201712 A
123 201713 A
如果未找到以前的状态,则为
测试数据:
SELECT '123' AS [Project_ID], 201603 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201604 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201605 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201606 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201607 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201608 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201609 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201610 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201611 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201612 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201613 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201701 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201702 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201703 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201704 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201705 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201706 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201707 AS [Period], 'A' AS [OldStatus], 'D' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201708 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201709 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201710 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201711 AS [Period], 'D' AS [OldStatus], 'A' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201712 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201713 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201801 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201802 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201803 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201804 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201805 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201806 AS [Period], 'A' AS [OldStatus], 'D' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201807 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201808 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201809 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201810 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201811 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201812 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201813 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201814 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201815 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201816 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201901 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201902 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201903 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201904 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201705 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201706 AS [Period], 'A' AS [OldStatus], 'I' AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201707 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
编辑
我的最终查询基于下面@Gordon Linoff的回答
我介绍了第二个表:project_main,其中包括当前的项目状态。在没有记录历史的情况下,这是必需的
SELECT
p.project_id,
p.period,
COALESCE(p.new_status, pprev.new_status, pnext.old_status, crrnt.status) AS status
FROM projects p OUTER APPLY
(SELECT TOP (1) old_status
FROM projects p2
WHERE p2.project_id = p.project_id AND p2.period >= p.period
AND old_status IS NOT NULL
ORDER BY p2.period DESC
) pnext OUTER APPLY
(SELECT TOP (1) new_status
FROM projects p2
WHERE p2.project_id = p.project_id AND p2.period <= p.period
AND new_status IS NOT NULL
ORDER BY p2.period DESC
) pprev OUTER APPLY
(SELECT TOP (1) Status
FROM project_main p3 -- The current project status is stored here
WHERE PR.project_id = p3.project_id) crrnt
ORDER BY Period ASC;
嗯,您真正想要的是LAG和LEAD上的ignorenulls选项,但SQL Server不支持这一点
select p.project_id, p.period,
coalesce(p.new_status, pnext.old_status, pprev.new_status, 'A') as status
from projects p outer apply
(select top (1) old_status
from projects p2
where p2.project_id = p.project_id and
p2.period >= p.period and
p2.old_status is not null
order by p2.period asc
) pnext outer apply
(select top (1) new_status
from projects p2
where p2.project_id = p.project_id and
p2.period <= p.period and
p2.new_status is not null
order by p2.period desc
) pprev;
像这样使用coalesce和case语句:
SELECT Project_ID,
Period,
CASE
WHEN COALESCE([NewStatus], [OldStatus]) IS NULL
THEN 'A'
ELSE COALESCE([NewStatus], [OldStatus])
END as [status]
FROM
(
SELECT '123' AS [Project_ID], 201603 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201604 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201605 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201606 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201607 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201608 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201609 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201610 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201611 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201612 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201613 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201701 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201702 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201703 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201704 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201705 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201706 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201707 AS [Period], 'A' AS [OldStatus], 'D' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201708 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201709 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201710 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201711 AS [Period], 'D' AS [OldStatus], 'A' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201712 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201713 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201801 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201802 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201803 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201804 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201805 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201806 AS [Period], 'A' AS [OldStatus], 'D' AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201807 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201808 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201809 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201810 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201811 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201812 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201813 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201814 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201815 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201816 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201901 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201902 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201903 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '123' AS [Project_ID], 201904 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201705 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201706 AS [Period], 'A' AS [OldStatus], 'I' AS [NewStatus]
UNION ALL
SELECT '321' AS [Project_ID], 201707 AS [Period], NULL AS [OldStatus], NULL AS [NewStatus]
) a
在每个子查询中添加的old_status/new_status不为NULL,这看起来很有希望。我不知道在其他DBMS中的超前/滞后上有一个IGNORE NULL选项,但这在这里非常有用。在没有记录旧/新状态的情况下,添加“a”作为默认值的另一个合并参数,效果非常好。谢谢@布莱尔。非常感谢。