%let APPDIR=%SYSGET(NOME_DIRETORIO);
%include "&APPDIR\PROG\GECRPDeclaraLibNames.sas";
%macro GESCD(TipoSCD, TipoChv,
NomeBiblStg, TabStg, CmpChaveStg, CmpRetornoStg,
NomeBiblDim, TabDim, CmpChaveSkDim, CmpChaveDim,
NomeCmpDatIniVigDim, NomeCmpDatFimVigDim );
/*
PROGRAMA SAS
PROJ: Tarefas gerais de ETL.
DESC: Realiza a tarefa de SCD tipos I e II a partir de uma tabela de stage e uma dimensão.
AUTOR: Erick Furst - erick.furst@coresynesis.com.br
DATA: 2009-09-08
INPUTS/OUTPUTS
INs : Nome biblioteca, tabela, campo(s) chave de negócio e campo(s) de retorno da tabela
stage: NomeBiblStg, TabStg, CmpChaveStg, CmpRetornoStg.
Nome biblioteca, tabela, campo(s) chave substituta, campo(s) chave de negócio e campo(s) de retorno da
tabela de dimensão: NomeBiblDim, TabDim, CmpChaveSkDim, CmpChaveDim.
Obs.: (Só poderá ser informado um campo para a variável "CmpChaveSkDim".)
OUTs: Não há.
MODIFICACOES
2009-09-10 - Erick Furst - erick.furst@coresynesis.com.br
(+) Alteração para realização de SCD Tipo I sem surrogate Key.
2009-09-12 - Erick Furst - erick.furst@coresynesis.com.br
(+) Alteração para correção do campo de suurogate key que estava fixo qdo deveria utilizar a variável.
*/
/*-------------------------------------------------------------------------------------------------------------------*/
/* Armazena Data Atual do sistema para gravação do controle de histórico do SCD tipo 2. */
%let DataAtual = today( );
/* Recupera o valor da maior Sk armazenada na dimensão. */
%if &TipoChv = 'S' %then %do;
proc sql;
SELECT MAX( &CmpChaveSkDim ) into : Maior FROM &NomeBiblDim..&TabDim ;
quit;
%end;
/* Recupera o tipo e o tamanho de dados dos campos da tabela de Stage. Já no formato para trabalho no DATA STEP.
E armazena na tabela WORK.TamStg*/
proc sql;
CREATE TABLE WORK.TamStg AS
select 'length ' || NAME || ' ' || CASE TYPE WHEN 'char' THEN '$' ELSE '' END || TRIM(PUT(LENGTH,6.)) || ';' AS TamCol
from dictionary.columns
where UPPER(libname)= UPPER("&NomeBiblStg")
and UPPER(MEMNAME) = UPPER("&TabStg");
quit;
/* Recupera o tipo e o tamanho de dados dos campos da tabela de Dimensão. Já no formato para trabalho no DATA STEP.
E armazena na tabela WORK.TamDim*/
proc sql;
CREATE TABLE WORK.TamDim AS
select 'length ' || NAME || ' ' || CASE TYPE WHEN 'char' THEN '$' ELSE '' END || TRIM(PUT(LENGTH,6.)) || ';' AS TamCol
from dictionary.columns
where UPPER(libname)= UPPER("&NomeBiblDim")
and UPPER(MEMNAME) = UPPER("&TabDim");
quit;
/* Desmembra a String armazenada na variável &CmpChaveStg (Campos chave da tabela de Stage)
para identificação dos campos. E concatenação posterior na string do call execute que gerará o código do lookup. */
data WORK.ChaveStg;
CmpChaveStg = &CmpChaveStg;
CmpChaveStgTra = CmpChaveStg;
CmpChaveStgLst = CmpChaveStgTra;
Pos = 1;
PosIni = 1;
PosFim = length(CmpChaveStgTra);
OrdemStg = 0;
do while (Pos ^= 0);
Pos = INDEX(CmpChaveStgTra, ",");
if Pos = 0 then
CmpChaveStgLst = SUBSTR(CmpChaveStgTra, PosIni, PosFim);
else do;
CmpChaveStgLst = SUBSTR(CmpChaveStgTra, PosIni, Pos - 1);
CmpChaveStgTra = SUBSTR(CmpChaveStgTra, Pos+1 , PosFim - Pos);
PosIni=1;
PosFim = length(CmpChaveStgTra);
end;
OrdemStg = OrdemStg + 1;
output;
end;
drop CmpChaveStgTra; drop Pos; drop PosIni; drop PosFim;
run;
/* Desmembra a String armazenada na variável &CmpChaveDim (Campos chave da tabela de Dimensão)
para identificação dos campos. E concatenação posterior na string do call execute que gerará o código do lookup. */
data WORK.ChaveDim;
CmpChaveDim = &CmpChaveDim;
CmpChaveDimTra = CmpChaveDim;
CmpChaveDimLst = CmpChaveDim;*AQUI;
Pos = 1;
PosIni = 1;
PosFim = length(CmpChaveDimTra);
OrdemDim = 0;
do while (Pos ^= 0);
Pos = INDEX(CmpChaveDimTra, ",");
if Pos = 0 then
CmpChaveDimLst = SUBSTR(CmpChaveDimTra, PosIni, PosFim);
else do;
CmpChaveDimLst = SUBSTR(CmpChaveDimTra, PosIni, Pos - 1);
CmpChaveDimTra = SUBSTR(CmpChaveDimTra, Pos+1 , PosFim - Pos);
PosIni=1;
PosFim = length(CmpChaveDimTra);
end;
OrdemDim = OrdemDim + 1;
output;
end;
drop CmpChaveDimTra; drop Pos; drop PosIni; drop PosFim;
run;
data _null_;
length TamCol $100;
length TxtLengthDim $1000;
declare hash LstTamColDim(dataset:"WORK.TamDim");
LstTamColDim.defineKey("TamCol");
LstTamColDim.defineData("TamCol");
LstTamColDim.defineDone();
declare hiter iterDim('LstTamColDim');
crTamCol = iterDim.first();
do while (crTamCol=0);
TxtLengthDim = CATS(TxtLengthDim, TamCol);
crTamCol = iterDim.next();
end;
drop TamCol; drop crTamCol;
call symput('LengthDim',TxtLengthDim);
run;
/* SCD Tipo I & II */
/* *************** */
data _null_;
/* Tratamento de campos. */
/* ********************* */
/* Definição de padrão para substituição com a função "rxparse". Uso necessário para passagem de
campos de parâmetro separados por vírgula. A substituição de caracteres é feita através da função
"rxchange" e também é feita a limpeza de caracteres brancos através da função "compress". */
rx=rxparse("$',;' to '"",""'"); /* Definição de padrão para substituição. */
* Chave da Tabela de Stage;
length CmpChaveStgCon $1000;
CmpChaveStgCon = &CmpChaveStg || ' ';
call rxchange(rx,length(CmpChaveStgCon),CmpChaveStgCon); /* Substituição de valor */
CmpChaveStgCon=compress(CmpChaveStgCon); /* Eliminação de espaços brancos. */
* Campos de retorno da Tabela de Stage;
length CmpRetornoStgCon $1000;
CmpRetornoStgCon = &CmpRetornoStg || ' ';
call rxchange(rx,length(CmpRetornoStgCon),CmpRetornoStgCon); /* Substituição de valor */
CmpRetornoStgCon=compress(CmpRetornoStgCon); /* Eliminação de espaços brancos. */
* Chave da Tabela de Dimensão;
length CmpChaveDimCon $1000;
CmpChaveDimCon = &CmpChaveDim || ' ';
call rxchange(rx,length(CmpChaveDimCon),CmpChaveDimCon); /* Substituição de valor */
CmpChaveDimCon=compress(CmpChaveDimCon); /* Eliminação de espaços brancos. */
rx=rxparse("$',""' to ' '"); /* Definição de padrão para substituição. */
CS = CmpChaveStgCon;
call rxchange(rx,length(CS),CS); /* Substituição de valor */
CD = CmpChaveDimCon;
call rxchange(rx,length(CD),CD); /* Substituição de valor */
call symput('ChvStg',CS);
call symput('ChvDim',CD);
/* SCD Tipo I & II (Criação de tabela de Update e Insert) */
/* ****************************************************** */
length TxtInUp $5000;
TxtInUp = 'data WORK.SCDI WORK.SCDU; ';
/* O cursor abaixo monta o comando lenght para a tabela de Stage.*/
length TamCol $100;
length TxtLengthStg $1000;
declare hash LstTamColStg(dataset:"WORK.TamStg");
LstTamColStg.defineKey("TamCol");
LstTamColStg.defineData("TamCol");
LstTamColStg.defineDone();
declare hiter iterStg('LstTamColStg');
crTamCol = iterStg.first();
do while (crTamCol=0);
TxtLengthStg = CATS(TxtLengthStg, TamCol);
crTamCol = iterStg.next();
end;
drop TamCol; drop crTamCol;
/* Concatenação dos blocos da string na variável final TxtCodLookup. */
TxtInUp = CATS(TxtInUp, ' ');
TxtInUp = CATS(TxtInUp, TxtLengthStg);
TxtInUp2 =
%if &TipoChv = 'S' %then %do;
symget('CmpChaveSkDim') || ' = ' || symget('Maior') || '; ' ||
'if MISSING(' || symget('CmpChaveSkDim') || ') then ' || symget('CmpChaveSkDim') || ' = 0; ' ||
%end;
'declare hash Stage(dataset:"'|| symget('NomeBiblStg') || '.' || symget('TabStg') ||
'", ordered: "' || TRIM(CmpChaveStgCon) || '"); ' ||
'Stage.defineKey("' || TRIM(CmpChaveStgCon) || '"); ' ||
'Stage.defineData("' || TRIM(CmpRetornoStgCon) || '"); ' ||
'Stage.defineDone(); ' ||
'declare hash Dimensao(dataset:"' || symget('NomeBiblDim') || '.' || symget('TabDim') ||
'", ordered: "' || TRIM(CmpChaveDimCon) || '"); ' ||
'Dimensao.defineKey("' || TRIM(CmpChaveDimCon) || '"); ' ||
'Dimensao.defineData("' || TRIM(CmpChaveDimCon) || '"); ' ||
'Dimensao.defineDone(); ' ||
'declare hiter iterStage("Stage"); ' ||
'rc = iterStage.first(); ' ||
'do while (rc=0); ';
TxtInUp = CATS(TxtInUp, TxtInUp2);
/* O cursor abaixo monta o comando de comparação entre o(s) campo(s) chave da tabela de Dimensão com o(s)
campo(s) chave da tabela de Stage. Para a posterior recuperação de campos feito pelo comando FIND do objeto HASH.
Ex.: CampoChaveTabelaDimensão = CampoChaveTabelaStage; */
length OrdemStg 3; length CmpChaveStgLst $32;
declare hash LstStg(dataset:"WORK.ChaveStg");
LstStg.defineKey("OrdemStg");
LstStg.defineData("OrdemStg","CmpChaveStgLst");
LstStg.defineDone();
declare hiter iterChvStg('LstStg');
length OrdemDim 3; length CmpChaveDimLst $32;
declare hash LstDim(dataset:"WORK.ChaveDim");
LstDim.defineKey("OrdemDim");
LstDim.defineData("OrdemDim","CmpChaveDimLst");
LstDim.defineDone();
cursor = iterChvStg.first();
do while (cursor=0);
OrdemDim = OrdemStg;
cursor = LstDim.find();
TxtInUp = CATS(TxtInUp, CmpChaveDimLst || ' = ' || CmpChaveStgLst || '; ');
cursor = iterChvStg.next();
end;
drop CmpChavePesLst; drop CmpChaveManLst; drop OrdemPes; drop OrdemStg; drop cursor;
TxtInUp3 =
%if &TipoChv = 'S' %then %do;
' if &TipoSCD = 2 then do ' ||
symget('CmpChaveSkDim') || ' = ' || symget('CmpChaveSkDim') || ' + 1; ' ||
' DataIniVig = &DataAtual; ' ||
' DataFimVig = -21914; ' ||
' end; ' ||
%end;
' if Dimensao.FIND() = 0 then ' ||
' output WORK.SCDU; ' ||
' else do; ' ||
%if &TipoChv = 'S' %then %do;
' if &TipoSCD = 1 then ' || symget('CmpChaveSkDim') || ' = ' || symget('CmpChaveSkDim') || ' + 1; ' ||
%end;
' output WORK.SCDI; ' ||
' end; ' ||
' rc = iterStage.next(); ' ||
'end; ' ||
'drop rc; ' ||
'run; ';
TxtInUp = CATS(TxtInUp, TxtInUp3);
/* Gera e executa o código de SCD para criação de tabela de insert e update. */
CALL EXECUTE (TxtInUp);
drop _All_;
run;
%if &TipoSCD = 1 %then %goto Tipo1;
%else %goto Tipo2;
%Tipo1:
/* Preparação Tipo I */
/* ***************** */
data WORK.SCDU;
set WORK.SCDU;
&LengthDim;
drop %if &TipoChv = 'S' %then %do; &CmpChaveSkDim %end; &NomeCmpDatIniVigDim &NomeCmpDatFimVigDim;
run;
data WORK.SCDI;
set WORK.SCDI;
&LengthDim;
drop &NomeCmpDatIniVigDim &NomeCmpDatFimVigDim;
run;
/* Atualização Tipo I */
/* ****************** */
data &NomeBiblDim..&TabDim;
modify &NomeBiblDim..&TabDim WORK.SCDU;
by &ChvDim;
if _iorc_ = %sysrc(_sok) then replace;
else _ERROR_=0;
run;
%goto Saida;
%Tipo2:
/* Atualização Tipo II */
/* ******************* */
data WORK.SCDData;
set WORK.SCDU;
&LengthDim;
&NomeCmpDatFimVigDim = &DataAtual;
keep &ChvDim &NomeCmpDatFimVigDim;
run;
proc sort data=&NomeBiblDim..&TabDim;
by &ChvDim descending &NomeCmpDatIniVigDim;
run;
data &NomeBiblDim..&TabDim;
modify &NomeBiblDim..&TabDim WORK.SCDU;
by &ChvDim;
if _iorc_ = %sysrc(_sok) then replace;
else _ERROR_=0;
run;
/* Inserção Tipo II */
/* **************** */
proc append base=&NomeBiblDim..&TabDim data=WORK.SCDU
force;
run;
%goto Saida;
%Saida:
/* Inserção Tipo I e II */
/* ********************* */
proc append base=&NomeBiblDim..&TabDim data=WORK.SCDI
force;
run;
/* Ordenação Geral */
/* *************** */
%if &TipoChv = 'S' %then %do;
proc sort data=&NomeBiblDim..&TabDim;
by &CmpChaveSkDim;
run;
%end;
proc sql;
DROP TABLE WORK.TamStg;
DROP TABLE WORK.TamDim;
DROP TABLE WORK.ChaveStg;
DROP TABLE WORK.ChaveDim;
DROP TABLE Work.SCDI;
DROP TABLE Work.SCDU;
DROP TABLE Work.SCDData;
quit;
%mend;
Sem comentários:
Enviar um comentário