SQL запрос для отображения временного тренда таблицы измерений SCD типа 2 - PullRequest
0 голосов
/ 07 августа 2020

Таблица, приведенная ниже:

pk,EmployeeNo,Building,ValidFrom,ValidTo. 
1, 1, a, 2000-01-01, 2008-06-01
2, 1, b, 2008-06-01, 2010-06-01
3, 1, c, 2010-06-01, 2011-08-01
4, 2, a, 2000-01-01, 2008-06-01
5, 2, b, 2008-06-01, 2010-06-01
6, 2, c, 2010-06-01, 2011-08-01

Я относительно новичок SQL разработчик и использую MS SQL Server. Я хотел бы разработать запрос SQL, который мог бы использовать приведенную выше таблицу, построенную с использованием медленно меняющихся измерений типа 2 (с датой validfrom и validto date), и создать таблицу ежедневного тренда количества клиентов с течением времени. Вывод ниже:

Date, Employee Count
1/1/2000, 2
1/2/2000, 2

Ответы [ 3 ]

0 голосов
/ 11 августа 2020

Следующий SQL похоже работает. Я предположил, что Employee действителен до даты ValidTo, но не на нее, чтобы избежать двойного подсчета в эти даты, когда ValidFrom и ValidTo перекрываются; вам необходимо изменить логику INNER JOIN c, если это предположение неверно.

    --Get the min and max dates in the employee table
DECLARE @todate date, @fromdate date
SELECT @fromdate= min(ValidFrom) from [POC].[dbo].[EmployeeSCD2];
SELECT @todate= max(validto) from [POC].[dbo].[EmployeeSCD2];

-- Generate a list of all the dates between the two dates
WITH calendar (FromDate) AS (
    SELECT @fromdate AS FromDate
    UNION ALL
    SELECT DATEADD(day, 1, FromDate)
    FROM Calendar
    WHERE FromDate < @todate
)
-- Join the list of dates to the employee table - gives a record per date per employee active on that date
SELECT CAL.FromDate, COUNT(EMP.EMPLOYEENO) 'Employee Count' 
FROM CALENDAR CAL
INNER JOIN [POC].[dbo].[EmployeeSCD2] EMP ON CAL.FromDate >= EMP.ValidFrom AND CAL.FromDate < EMP.ValidTo
group by cal.FromDate
OPTION (MAXRECURSION 0) -- Without this parameter the recursion stops after 100 loops
;
0 голосов
/ 11 августа 2020

Простой способ - создать таблицу дат и затем подсчитать, сколько сотрудников (или клиентов) было в эту конкретную дату.

;with t as (   -- this is your table/Dimension
    select pk,EmployeeNo,Building,ValidFrom,ValidTo 
    from (values (1, 1, 'a', '2000-01-01', '2008-06-01'),
                 (2, 1, 'b', '2008-06-01', '2010-06-01'),
                 (3, 1, 'c', '2010-06-01', '2011-08-01'),
                 (4, 2, 'a', '2000-01-01', '2008-06-01'),
                 (5, 2, 'b', '2008-06-01', '2010-06-01'),
                 (6, 2, 'c', '2010-06-01', '2011-08-01')
        )t (pk,EmployeeNo,Building,ValidFrom,ValidTo)
)
, dates as ( -- this is a recursive query, building a date table from 2000-01-01 up to today
    select convert(date, '2000-01-01') as d
    union all
    select DATEADD(d,1,d) 
    from dates 
    where d < getdate()-1
)
select d.d, count(1) as [Employe count]  
from dates d
inner join t on d.d between t.ValidFrom and t.ValidTo -- will join only valid employee
group by d.d 
option (maxrecursion 0)  -- since our dates table recurse over more than 100 times and the dataset is fairly small, you need this option
0 голосов
/ 07 августа 2020

Вы можете использовать агрегацию и кумулятивную сумму - после отмены разворота данных:

with d as (
      select validfrom as dte, 1 as inc
      from t
      union all
      select validto, -1
      from t
     )
select dte, sum(sum(inc)) over (order by dte)
from d
group by dte
order by dte;

Примечание. Это предполагает, что дата validto не включена. Если вы хотите, чтобы он был включен, добавьте к нему «1».

EDIT:

Если вам нужны результаты только для этих двух дат, используйте:

select v.dte,
       (select count(*) 
        from t
        where t.validfrom <= v.dte and t.validto >= t.validto
       ) as cnt
from (values ('2020-01-01'), ('2020-01-02')) v(dte);
...