4

지연 도착 차원 및 NULL 비즈니스 키에 대한 차원 테이블에서 -1 및 -2 행을 사용하는 Kimball 데이터 마트를 구현하려고합니다. 사실과 차원 데이터를위한 하나의 스테이징 테이블, 데이터 마트를위한 2 개의 차원 테이블과 하나의 팩트 테이블을 생성하는 예제 코드가 있습니다. 다음은 SQL의 데이터를 사용한 예제 코드입니다.Kimball Data Mart에서 지연 도착 차원과 NULL 비즈니스 키를 처리하는 방법은 무엇입니까?

--drop table stg_sales 
--go 
CREATE TABLE dbo.stg_sales 
    (
    stg_sales_id  INT IDENTITY(1, 1) NOT NULL, 
    sales_number  INT NOT NULL, 
    sales_amt   INT NULL, 
    cust_number  INT NULL, 
    cust_firstname  NVARCHAR(50) NULL, 
    cust_lastname  NVARCHAR(100) NULL, 
    cust_address  NVARCHAR(500) NULL, 
    salesperson_number INT NULL, 
    CONSTRAINT pk_stg_sales PRIMARY KEY (stg_sales_id) 
) 

go 

INSERT stg_sales 
     (sales_number, 
     sales_amt, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     salesperson_number) 
VALUES (123, 
     434, 
     2342, 
     'Jim', 
     'Moriaty', 
     'something', 
     23) 

INSERT stg_sales 
     (sales_number, 
     sales_amt, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     salesperson_number) 
VALUES (124, 
     234, 
     2342, 
     'Jim', 
     'Moriaty', 
     'something', 
     23) 

INSERT stg_sales 
     (sales_number, 
     sales_amt, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     salesperson_number) 
VALUES (125, 
     434, 
     4545, 
     'Joe', 
     'Esk', 
     'someother', 
     24) 

INSERT stg_sales 
     (sales_number, 
     sales_amt, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     salesperson_number) 
VALUES (126, 
     434, 
     5555, 
     'Daniel', 
     'Hart', 
     'Someaddr', 
     NULL) --salesperson_number business key missing here 

INSERT stg_sales 
     (sales_number, 
     sales_amt, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     salesperson_number) 
VALUES (127, 
     333, 
     4444, 
     'Pat', 
     'Smith', 
     'Someaddr', 
     30) 

SELECT * 
FROM stg_sales 

--create a dimension and fact tables 
--drop table dbo.dim_customer 
--go 
CREATE TABLE dbo.dim_customer 
    (
    customer_wid INT IDENTITY(1, 1) NOT NULL, 
    cust_number INT NULL, 
    cust_firstname NVARCHAR(50) NULL, 
    cust_lastname NVARCHAR(100) NULL, 
    cust_address NVARCHAR(500) NULL, 
    date_insert DATETIME2 NOT NULL DEFAULT (Getdate()), 
    date_update DATETIME2 NULL, 
    is_current  BIT NOT NULL 
    CONSTRAINT pk_dim_customer PRIMARY KEY (customer_wid) 
    CONSTRAINT chk_is_current CHECK (is_current IN (0, 1)) 
) 

go 

SET IDENTITY_INSERT dbo.dim_customer ON 

INSERT dbo.dim_customer 
     (customer_wid, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     date_insert, 
     date_update, 
     is_current) 
VALUES (-1, 
     -1, 
     'unknown', 
     'unknown', 
     'unknown', 
     Getdate(), 
     Getdate(), 
     1) 

INSERT dbo.dim_customer 
     (customer_wid, 
     cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     date_insert, 
     date_update, 
     is_current) 
VALUES (-2, 
     -2, 
     'Error', 
     'Error', 
     'Error', 
     Getdate(), 
     Getdate(), 
     1) 

SET IDENTITY_INSERT dbo.dim_customer OFF 

--insert data into dimension table 
INSERT dbo.dim_customer 
     (cust_number, 
     cust_firstname, 
     cust_lastname, 
     cust_address, 
     is_current) 
SELECT DISTINCT cust_number, 
       cust_firstname, 
       cust_lastname, 
       cust_address, 
       1 AS is_current 
FROM dbo.stg_sales 
WHERE cust_number <> 4444 --left one record off to simulate the situation where you don't have corrensponding row in dim table (late arriving dimension) 
SELECT * 
FROM dbo.dim_customer 

DROP TABLE dbo.dim_salesperson 

--create salesperson table 
CREATE TABLE dbo.dim_salesperson 
    (
    salesperson_wid  INT IDENTITY(1, 1) NOT NULL, 
    salesperson_number INT NULL, 
    salesperson_firstname NVARCHAR(50) NULL, 
    salesperson_lastname NVARCHAR(100) NULL, 
    salesperson_address NVARCHAR(500) NULL, 
    date_insert   DATETIME2 NOT NULL DEFAULT (Getdate()), 
    date_update   DATETIME2 NULL, 
    is_current   BIT NOT NULL 
    CONSTRAINT pk_dim_salesperson PRIMARY KEY (salesperson_wid) 
    CONSTRAINT chk_dim_salesperson_is_current CHECK (is_current IN (0, 1)) 
) 

go 

SET IDENTITY_INSERT dbo.dim_salesperson ON 

INSERT dbo.dim_salesperson 
     (salesperson_wid, 
     salesperson_number, 
     salesperson_firstname, 
     salesperson_lastname, 
     salesperson_address, 
     date_insert, 
     date_update, 
     is_current) 
VALUES (-1, 
     -1, 
     'Not available', 
     'Not available', 
     'Not available', 
     Getdate(), 
     Getdate(), 
     1) 

INSERT dbo.dim_salesperson 
     (salesperson_wid, 
     salesperson_number, 
     salesperson_firstname, 
     salesperson_lastname, 
     salesperson_address, 
     date_insert, 
     date_update, 
     is_current) 
VALUES (-2, 
     -2, 
     'Error', 
     'Error', 
     'Error', 
     Getdate(), 
     Getdate(), 
     1) 

SET IDENTITY_INSERT dbo.dim_salesperson OFF 

--insert data into salesperson 
INSERT dbo.dim_salesperson 
     (salesperson_number, 
     salesperson_firstname, 
     salesperson_lastname, 
     salesperson_address, 
     is_current) 
VALUES (23, 
     'John', 
     'Fox', 
     'something', 
     1) 

INSERT dbo.dim_salesperson 
     (salesperson_number, 
     salesperson_firstname, 
     salesperson_lastname, 
     salesperson_address, 
     is_current) 
VALUES (24, 
     'Hadley', 
     'Fox', 
     'something', 
     1) 

INSERT dbo.dim_salesperson 
     (salesperson_number, 
     salesperson_firstname, 
     salesperson_lastname, 
     salesperson_address, 
     is_current) 
VALUES (30, 
     'Ashley', 
     'Fox', 
     'something', 
     1) 

SELECT * 
FROM dbo.dim_salesperson 

SELECT * 
FROM dbo.stg_sales 

--create and populate the fact table 
--drop table dbo.f_sales 
--go 
CREATE TABLE dbo.f_sales 
    (
    sales_number INT NOT NULL, 
    customer_wid INT NOT NULL, 
    salesperson_wid INT NOT NULL, 
    sales_amt  INT NULL 
    CONSTRAINT pk_f_sales PRIMARY KEY (sales_number) 
    CONSTRAINT fk_customer_wid FOREIGN KEY (customer_wid) REFERENCES 
    dbo.dim_customer(customer_wid), 
    CONSTRAINT fk_salesperson_wid FOREIGN KEY (salesperson_wid) REFERENCES 
    dbo.dim_salesperson(salesperson_wid) 
) 

--populate the fact table 
INSERT dbo.f_sales 
     (sales_number, 
     customer_wid, 
     salesperson_wid, 
     sales_amt) 
SELECT stg.sales_number, 
     Isnull(dimcust.customer_wid, -1) AS customer_wid, 
     --this is maybe correct way to assign -1 foreign key when there is no corresponding dimension row in the dim table 
     Isnull(dimsp.salesperson_wid, -2) AS salesperson_wid, 
     --NOT CORRECT, how to assign -2 foreign key when the business key is NULL in the source? 
     stg.sales_amt 
FROM dbo.stg_sales AS stg 
     LEFT JOIN dbo.dim_customer AS dimcust 
       ON stg.cust_number = dimcust.cust_number 
     LEFT JOIN dbo.dim_salesperson AS dimsp 
       ON stg.salesperson_number = dimsp.salesperson_number 

SELECT * 
FROM dbo.f_sales 

원본 시스템에 비즈니스 키가없는 행에 -2를 어떻게 할당 할 수 있습니까?

이것은 기본적으로 내가 달성하기 위해 노력하고있어 :

Handling NULL in dimensions and measures

당신은 킴볼이 구현 뒤에 이론에 대한 자세한 내용을보실 수 있습니다 편집 :

,210

가 나는 왼쪽에서 COALESCE 또는 ISNULL 조인을 사용할 수 있다고 생각, 올바른 결과를 가져 오는 것 같습니다 : 순수

-- add nullable keys to the staging table 
alter table dbo.stg_sales ADD 
    sales_person_wid integer null 
, customer_wid  integer null 
; 

-- insert to staging table here (as in your example) 

-- lookup sales person key 
update dbo.stg_sales 
set sales_person_wid = p.sales_person_wid 
from dbo.stg_sales as s , dbo.dim_salesperson as p 
where s.salesperson_number = p.salesperson_number ; 

-- decide what to do with missing business keys 
update dbo.stg_sales 
set sales_person_wid = -2 
where sales_person_wid is null ; 


-- do similar for customer 

-- now all keys in staging table are not null 

-- load to fact table 

그러나 조회 기법으로

INSERT dbo.f_sales 
     (sales_number, 
     customer_wid, 
     salesperson_wid, 
     sales_amt) 
SELECT stg.sales_number, 
     Isnull(dimcust.customer_wid, -1) AS customer_wid, 
     --this is maybe correct way to assign -1 foreign key when there is no corresponding dimension row in the dim table 
     dimsp.salesperson_wid, 
     stg.sales_amt 
FROM dbo.stg_sales AS stg 
     LEFT JOIN dbo.dim_customer AS dimcust 
       ON COALESCE(stg.cust_number, -2) = dimcust.cust_number 
     LEFT JOIN dbo.dim_salesperson AS dimsp 
       ON COALESCE(stg.salesperson_number, -2) = dimsp.salesperson_number 

답변

4

을, 일반적인 기술은 할당하는 것입니다 특별 (알 수 없음, n/a, 오류) 비즈니스 키를 추출 또는 정리 중 트랜잭션으로 보냅니다. 즉, 레코드가 스테이징 테이블에 도착하기 전에 특수 Error 비즈니스 키가 할당되었을 수 있습니다.

마지막으로 지연된 차원은 비즈니스 키 (salesperson_number)가 운영 체제에 알려져 있음을 의미하지만 트랜잭션 (판매 사실)은 차원 데이터 앞에웨어 하우스를 생성했습니다. 따라서 salesperson_numbernot null이지만 dimenson 테이블에는 존재하지 않습니다. 이 트랜잭션을 어딘가에 저장하고 레코드가 차원에 도착하면 FK (salesperson_wid)를 업데이트해야합니다. 하루 정도 지나서.

+0

답장을 보내 주셔서 감사합니다. 스테이징 테이블 조회를 위해 차원 테이블을 사용하는 것은 결코 마음에 들지 않습니다. 이전에는 이러한 상황에서 ETL 도구를 사용했으며 준비 영역이 아닌 사실로드에서이 문제를 해결하는 것이 일반적입니다. -2로 join 연산에서 NULL을 대체하기 위해 왼쪽 조인 조건에서 coalesce/isnull 함수를 사용할 수 있다고 생각합니다. – jrara

+0

내 질문을 편집했습니다. – jrara

0

나는 늦은 도착 사실이 사실과 관련된 차원이 서서히 변하는 곳이며 사실은 늦었다 고 생각했습니다. 영업 시스템이 있고 'Opal Fruit'이라는 제품이 있으며이 제품의 이름이 'Starburst'로 변경됩니다. 회사는 이름 변경이 영업에 영향을 미치는지 추적하여 유형 2 천천히 변화하는 차원 (SCD)을 설정하기를 원합니다. SCD에서 제품 이름을 추적하므로 제품 이름이 변경 될 때마다 동일한 비즈니스 (자연) 키와 다른 대리 키를 사용하여 해당 제품에 대한 새 레코드를 발행하고 유효한 시작 날짜와 종료 날짜를 기록합니다 그 이름으로. 따라서 'Opal Fruit'은 1970 년 1 월 1 일부터 유효하며, 1993 년 8 월 28 일까지 유효합니다. 제품 이름이 'Opal Fruit'인 버전은 '29/3/1995 '부터 유효하며 유효'to '는 여전히 유효하므로 null입니다.

이름 변경 후 언젠가 1/4/1995에 거래일이 1995 년 1/4/1, 일부 거래일이 27/3/1995 인 일부 판매 거래가 발생합니다. 늦은 도착은 제품 차원이 변경된 후 지정된 차원에 대한 트랜잭션이 도착 함을 의미합니다. 따라서 1995 년 3 월 27 일에 도착한 트랜잭션에는 제품 이름이 'Opal Fruitt'인 제품 차원의 대리 키가 있어야하며 1/4/1995에 도착한 제품 차원에는 제품 차원의 Surroagte 키가 필요합니다. 이름은 'Starburst'입니다.당신이해야 할 일은 'Opal Fruit/Starburst'제품의 어떤 버전이 거래일에 최신인지를 결정하고 판매 사실로 들어가면 해당 제품 대리 키를 거래에 할당하는 것입니다.

그건 늦은 도착 사실에 대한 나의 이해입니다. 차원 요소를 처리하기 전에 도착한 사실은 도착한 것이 분명히 일찍 도착하는 사실이며, 늦은 것은 아닙니다. 어쩌면 그것은 용어 일뿐입니다.