Разработка медленно меняющегося сценария типа измерения 2 с помощью postgresql - PullRequest
0 голосов
/ 17 июня 2019

Допустим, у меня есть следующая целевая таблица:

CREATE TABLE DimCustomer (
CustomerKey serial PRIMARY KEY,
    CustomerNum int NOT NULL,
    CustomerName varchar(25) NOT NULL,
    Planet varchar(25) NOT NULL,
    RowIsCurrent char(1) NOT NULL DEFAULT 'Y',
    RowStartDate date NOT NULL DEFAULT CURRENT_TIMESTAMP,
    RowEndDate date NOT NULL DEFAULT '12/31/9999'
);

INSERT INTO DimCustomer
(CustomerNum, CustomerName, Planet,  RowStartDate) 
VALUES (101,'Anakin Skywalker', 'Tatooine',   CURRENT_TIMESTAMP - INTERVAL '101 days'),
       (102,'Yoda', 'Coruscant',  CURRENT_TIMESTAMP - INTERVAL '100 days'),
       (103,'Obi-Wan Kenobi', 'Coruscant',  CURRENT_TIMESTAMP - INTERVAL '100 days')

И у меня есть следующая промежуточная таблица:

CREATE TABLE Staging_DimCustomer
(
    CustomerNum int NOT NULL,
    CustomerName varchar(25) NOT NULL,
    Planet varchar(25) NOT NULL,
    ChangeDate date NOT NULL DEFAULT CURRENT_TIMESTAMP,
    RankNo int NOT NULL DEFAULT 1
)
INSERT INTO Staging_DimCustomer(CustomerNum, CustomerName, Planet, ChangeDate)
VALUES
(103,'Ben Kenobi', 'Coruscant',   CURRENT_TIMESTAMP - INTERVAL '99 days')

В промежуточной таблице это выглядит как 'Obi-Wan Kenobi' (customernum 103) изменил свое имя на 'Ben Kenobi'.Я хочу создать скрипт, который реализует тип scd 2 и выдает следующий результат (медленно изменяющийся тип измерения 2):

enter image description here

Моя попытка состоит в следующем:

INSERT INTO DimCustomer (
  CustomerNum, CustomerName, Planet, RowIsCurrent, RowStartDate, RowEndDate
  ) 
 select CustomerNum, CustomerName, Planet, 'Y', ChangeDate, '12/31/9999'
 from Staging_DimCustomer 

 ON CONFLICT (CustomerNum) and RowIsCurrent = 'Y'
  DO UPDATE SET
    CustomerName = EXCLUDED.CustomerName,
    Planet = EXCLUDED.Planet,
    RowIsCurrent = 'N',
    RowEndDate = EXCLUDED.ChangeDate

Я не знаю, как искать измененные значения, обновлять существующие строки, чтобы удалить их, а затем вставлять новые строки с флагом rowiscurrent = 'Y'.Я пытаюсь смоделировать свое решение на основе этой статьи SQL Server http://www.made2mentor.com/2013/08/how-to-load-slowly-changing-dimensions-using-t-sql-merge/.

1 Ответ

1 голос
/ 17 июня 2019

Предполагая, что все изменения находятся в самой последней строке, вы можете обновить текущую строку и затем вставить:

with u as (
      update dimCustomer c
          set RowIsCurrent = 'N',
              RowEndDate = sc.ChangeDate
      from Staging_DimCustomer sc
      where sc.CustomerNum = c.CustomerNum and
            c.RowIsCurrent = 'Y'
     )
insert into dimCustomer (CustomerNum, CustomerName, Planet, RowIsCurrent, RowStartDate, RowEndDate
                         ) 
     select CustomerNum, CustomerName, Planet, 'Y', ChangeDate, '9999-12-31'::date
     from Staging_DimCustomer sc;

Это предполагает, что изменения имеют место в самой последней записи.Реализовать исторические изменения довольно сложно, и я предполагаю, что в этом нет необходимости.

Обратите внимание, что вам может потребоваться дополнительная проверка того, что вставляемая строка действительно отличается от текущей строки.

РЕДАКТИРОВАТЬ:

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

with sc as (
      select *
      from Staging_DimCustomer
      where not exists (select 1
                        from DimCustomer c
                        where c.CustomerNum = sc.CustomerNum and
                              c.CustomerName = sc.CustomerName and
                              . . .  -- whatever other columns you want to check
                      )
     ),
     u as (
      update dimCustomer c
          set RowIsCurrent = 'N',
              RowEndDate = sc.ChangeDate
      from sc
      where sc.CustomerNum = c.CustomerNum and
            c.RowIsCurrent = 'Y'
     )
insert into dimCustomer (CustomerNum, CustomerName, Planet, RowIsCurrent, RowStartDate, RowEndDate
                         ) 
     select CustomerNum, CustomerName, Planet, 'Y', ChangeDate, '9999-12-31'::date
     from sc;
...