SCD 类型 2 的 SQL 查询

Luk*_*mas 6 sql t-sql sql-server scd2 scd

我得到了下表,其中存在以下问题:

从数据集创建缓慢变化的维度类型 2。EMPLOYEE 表记录了每个员工的日常记录。类型 2 - 将具有有效数据和到期日期。

员工ID 日期 姓名 经理ID
123 3 月 1 日 约翰·史密斯 1
123 3月2日 约翰·史密斯 1
123 3月3日 约翰·史密斯 2
123 3 月 4 日 约翰·史密斯 3
123 3月5日 约翰·史密斯 3

我相信我的目标表应该如下所示:

员工ID 姓名 经理ID 生效日期 截止日期
123 约翰·史密斯 1 3 月 1 日 3月3日
123 约翰·史密斯 2 3月3日 3 月 4 日
123 约翰·史密斯 3 3 月 4 日 无效的

我尝试了以下查询:

SELECT employee_id, name, manager_id,
CASE
    WHEN LAG(manager_id) OVER() != manager_id THEN e.date 
    WHEN e.date = FIRST_VALUE(e.date) OVER() THEN e.date
    ELSE NULL
END as "Effective Date",
CASE 
    WHEN LEAD(manager_id) OVER() != manager_id THEN LEAD(e.date) OVER()
    ELSE NULL
END as "Expiration Date"
FROM employee e
Run Code Online (Sandbox Code Playgroud)

我的结果表如下:

员工ID 姓名 经理ID 生效日期 截止日期
123 约翰·史密斯 1 3 月 1 日 无效的
123 约翰·史密斯 1 无效的 3月3日
123 约翰·史密斯 2 3月3日 3 月 4 日
123 约翰·史密斯 3 3 月 4 日 无效的
123 约翰·史密斯 3 无效的 无效的

有谁知道根据我迄今为止所取得的成就,我可以改变查询以实现目标表的任何方法?不知怎的,我只需要得到 3 个经理 ID,但不同的 ID 不起作用。另外,我需要找到一种方法来组合每个经理 ID 的生效日期和到期日期。任何帮助将不胜感激。

Dal*_*e K 4

以下内容满足您的要求,并展示了如何添加 DDL+DML。它可能有点复杂,但我看不出有明显的方法来简化它。

该解决方案考虑了经理重复的可能性。而且它并不假设每一天都存在,因此如果缺少一天,它仍然可以工作。

declare @Test table (EmployeeID int, [Date] date, [Name] varchar(32), ManagerID int);

insert into @Test (EmployeeID, [Date], [Name], ManagerID)
values
(123, '1 Mar 2021', 'John Smith', 1),
(123, '2 Mar 2021', 'John Smith', 1),
(123, '3 Mar 2021', 'John Smith', 2),
(123, '4 Mar 2021', 'John Smith', 3),
(123, '5 Mar 2021', 'John Smith', 3);
--(123, '6 Mar 2021', 'John Smith', 2);

select EmployeeId, [Name], ManagerId, MinDate
  -- Use lead to get the last date of the next grouping - since it could in theory be more than one day on
  , lead(MinDate) over (partition by EmployeeId, [Name] order by Grouped) MaxDate
from (
  -- Get the min and max dates for a given grouping
  select EmployeeId, [Name], ManagerId, min([Date]) MinDate, max([Date]) MaxDate, Grouped
  from (
    select *
       -- Sum the change in manager to ensure that if a manager is repeated they form a different group
       , sum(Lagged) over (order by Date asc) Grouped
    from (
      select *
        -- Lag the manager to detect when it changes
        , case when lag(ManagerId,1,-1) over (order by [Date] asc) <> ManagerId then 1 else 0 end Lagged
      from @Test
    ) X
  ) Y
  group by EmployeeId, [Name], ManagerId, Grouped
) Z
order by EmployeeId, [Name], Grouped;
Run Code Online (Sandbox Code Playgroud)

返回:

员工ID 姓名 经理ID 最小日期 最大日期
123 约翰·史密斯 1 2021-03-01 2021-03-03
123 约翰·史密斯 2 2021-03-03 2021-03-04
123 约翰·史密斯 3 2021-03-04 无效的