quinta-feira, 11 de abril de 2019

Power BI Desktop Update [até Abril de 2019]

Nesta release foi removida em definitivo a área do antigo espaço dos filtros onde havia certa redundância nas funcionalidades. Agora todos os recursos estão na aba exclusiva para filtros e o recurso está bem lapidado.

Antes os filtros do painel também apareciam junto com área de configuração dos campos.




















Agora os filtros estão todos em um único local com recursos completos de formatação e controles para habilitar, desabilitar, bloquear, renomear, etc...































Especificamente nesta versão foram incluídas as opções de alterar o título dos filtros para garantir a criação de nomes mais amigáveis para o usuário.
















Agora também temos a opção de bloquear a alteração do tipo de filtro entre basic e advenced mode.

Esta opção é configurada para o relatório todo e deve ser alterada nas opções gerais do relatório.

























































Uso de expressões em títulos de gráficos, botões, url, imagens.


Até então os títulos atribuídos aos elementos gráficos e às urls associadas a botões eram estáticos e não eram afetados pelo contexto do painel . Agora eles podem ser dinâmicos baseados em medidas DAX que afetam o contexto de filtro.

Essa novidade cria uma grande expectativa, a possibilidade de ampliar significativamente as opções de customização de propriedades. Isso é muito útil e já existe no antigo report server e agora está sendo incorporada ao power bi aos poucos.

Exemplo de medida usada em um título de gráfico.






O título do gráfico apresenta o texto com a classe selecionada.

Para acessar as propriedades e atribuir a nova medida:




























Após a configuração, o campo da propriedade irá apresentar um ícone no lugar do valor, indicando que a propriedade é dinâmica.

Essa customização vale para as URLs. Agora  ações, botões, imagens, formas também permitem usar medidas para dinamizar o valor da propriedade para criar urls diferentes dependendo do contexto do painel.





















Também foi disponibilizada a opção de fazer drillthrough entre diferentes relatórios, até então estava restrito a paginas do mesmo relatório, agora o conceito de drill foi ampliado para fora.

Key Influencers visual agora também suporta campos com valores contínuos como alvos para análise

Essas são apenas algumas das principais novidades desta versão.



Vídeo:





Power BI Desktop Update [até março de 2019]


Neste mês, algumas funcionalidades apontadas como importantes pelos usuários no Power BI Ideas  foram disponibilizadas na release. Entre elas estão: filtros únicos em slicers, novo formato para mapas, customização dos balões de tooltips, nova tela de modelagem de dados, entre outros. Então vamos a elas.

Single-Select

Essa configuração garante que apenas um valor seja selecionado em um filtro. Até a versão anterior isso não era possível, com ctrl, o usuário conseguia fazer seleção múltipla, o que pode ser um problema em alguns casos onde medidas DAX utilizam o resultado de seleções únicas em filtros.






















Outro benefício de se usar essa configuração nos filtros, surge quando o usuário utiliza o formato dropdown. Até então ao selecionar um item, a lista permanecia aberta e o usuário tinha que obrigatoriamente fecha-lá apos seleção. Agora com esta versão, ao clicar no item a lista é recolhida automaticamente.




















Modelo de mapa de Calor

Com esta versão de mapa o resultado final para análises que apresentam muitos pontos passa a ser visualmente mais agradável, destacando melhor, onde realmente existem valores maiores, poluindo bem menos a tela com excesso de pontos. Veja.

Configuração padrão.













Com Heap Map.




















Filtar a partir das categorias dos gráficos

Em muitos casos, selecionar uma categoria em um gráfico de barras pode ser difícil, pois o tamanho proporcional pode ser muito pequeno para o clique. A partir desta versão, o item pode ser destacado pelo próprio label da categoria.




A falta de um recurso como este também fazia com que não fosse possível filtrar todas as medidas envolvidas em uma categoria de um gráfico ao mesmo tempo, apenas uma medida de cada vez poderia ser selecionada, com essa atualização, toda a categoria, com todas as medidas podem ser selecionadas ao mesmo tempo em um clique.







Formatação do tooltip padrão




O tooltip padrão com fundo preto e fonte branca agora pode ser alterado para ser suavizado ou combinado com as cores do painel.


















Link para URL externa:

Esse recurso permite que seja incluído botões, formas ou imagens com ações que direcionam o usuário para uma URL externa. Isso pode ser útil para direcionar para páginas web com manuais, para fontes ou artigos que complementam a análise apresentada no painel.
















Tela de Modelagem de Dados

Nova tela para modelagem traz a opção de configurar as propriedades das tabelas e atributos na mesma pagina, até então isso era feito alternando com a tela Data.



















































Além disso, essa nova tela traz a possibilidade de criar visualizações parciais do modelo, com conjuntos de tabelas específicas simplificando a visualização de grandes modelos de dados.

A experiência de modelagem dados do power bi vem se aprimorando e se aproximando do Data Tools, onde os modelos do Analysis Services Tabular são configurados.




















































Organizar em pastas: Uma das novas propriedades chamada "Display Folder" ajuda organizar os atributos do modelo em pastas.




































Novas funções DAX

Buscar uma string dentro de outra: https://dax.guide/containsstring/ | https://dax.guide/containsstringexact/
Retornar um valor com base em chaves equivalentes: https://dax.guide/lookupvalue/
Conta itens diferentes mas não considera black como item valido: https://dax.guide/distinctcountnoblank/



Custom Visual

Power Slicer: Um custom visual interessante  que permite maior controle sob as customizações visuais de um slice. Além disso possui recurso de hierarquia de atributos e configuração valores padrao utilizando JavaScritp.

Exemplo: marcar o mês com base na data atual.




























Vídeo:



Fontes:
https://github.com/Microsoft/powerbi-desktop-samples/tree/master/2019
https://powerbi.microsoft.com/pt-br/blog/power-bi-desktop-march-2019-feature-summary/


quinta-feira, 28 de março de 2019

Dimensão com Hierarquia Auto-referenciada - Parent-Child

Uma dimensão do tipo parent-child implementa o conceito auto-referenciamento de uma árvore desbalanceada, ou seja, possui ramos com tamanhos diferentes dependendo da profundidade de cada encadeamento.

Este tipo de dimensão pode aparecer em projetos que trabalham com listas de materiais que possuem subcomponentes, em sistemas corporativos que organizam os recursos humanos em estrutura organizacionais, em contas contábeis, etc..

Os projetos criados com o modelo tradicional do analysis services multidimensional (MDX) já possuem uma configuração nativa para tratar este tipo de dimensão, basta configurar corretamente as propriedades para que funcione.

Configuração das propriedades da dimensão





























Visualizando a dimensão
















Porém, com modelos tabulares criados com DAX esse suporte nativo não existe. Para obter uma hierarquia navegável no modelo de dados, você precisa decompor os níveis até um determinado ponto para obter uma hierarquia pai-filho.

Para isso o DAX fornece funções específicas para trabalhar com uma hierarquia pai-filho usando colunas calculadas.

Hierarquias Pai-Filho em DAX


A hierarquia é implementada utilizando as funções do grupo PATH.

PATH

PATHCONTAINS

PATHITEM

PATHITEMREVERSE

PATHLENGTH


Dados de Exemplo: Este exemplo será feito com base nesta tabela, onde o código da coluna gerente é o código pai.
















1-Identificar o caminho completo: 

Utiliza a coluna Gerente para referenciar todas as relações e retornar uma string com o caminho completo com todos os níveis superiores.



















Neste exemplo, existe uma coluna com a hierarquia já criada, em algumas fontes de dados isso pode existir, se esse for o caso, o primeiro passo pode ser substituído por esta função.


















2-Descobrindo o tamanho do caminho: 

Utilizar a função PATHLENGTH para identificar o tamanho. Esse valor será útil para identificar quantos níveis devem ser criados.


















3-Criando os níveis:

Nível 1: Utilizar PARENTITEM para localizar o código do nivel 1 e fornecer o parâmetro para LOOKUPVALUE localizar o nome do profissional.

























Nível 2: A partir do nível 2 é necessário fazer uma verificação no tamanho.






























O processo se repete para quantos níveis forem necessários.

O resultado final pode ser observado em um filtro ou em uma matrix.





Fonte:
https://docs.microsoft.com/en-us/dax/parent-and-child-functions- dax
https://www.daxpatterns.com/parent-child-hierarchies/
https://docs.microsoft.com/en-us/dax/understanding-functions- for-parent-child- hierarchies-in-dax
https://www.youtube.com/watch?v=QFKTr8tAQXE&list=PLWfPHxJoa7zthSaAMlt0JkJpFeVtdHzq6&index=42



quarta-feira, 20 de março de 2019

Iterações em Conjuntos de Dados Com Cursores e Sem Cursores

Em SQL existem duas formas de fazer iterações sobre as linhas de uma tabela, acessando a cada ciclo um registro específico.


1-Acesso iterativo/procedural através do uso de CURSOR: Um objeto que carrega a tabela em memória e permite a iteração linha a linha através de variáveis.

2-Set-Based declarativo: Acessa os dados utilizando os princípios relacionais que aplicam as regras da teoria de conjuntos, que opera com tabelas como conjuntos de entradas

A linguagem de consulta SQL é diferente das linguagens de programação tradicionais, ela é essencialmente declarativa e não procedural, isso significa que você deve se preocupar em definir o que você quer e não como obter o que você quer.

Na teoria, é sempre indicado utilizar abordagem que utiliza operações Set-Based em tabelas e evitar operações com linhas individuais com cursores devido a problemas de performance.

Realizar operações com cursores acaba quebrando o princípio da teoria de conjuntos com o qual os bancos de dados relacionais foram criados, pois além de definir o quê será retornado é necessário definir como operar sobre esse dado.

Por outro lado, quando é usada a abordagem de conjuntos, não é possível garantir a ordenação precisa das linhas retornadas a menos que seja usado cuidadosamente a cláusula ORDER BY, para garantir o retorno de valores únicos para a ordenação. Já com iterações com cursores é possível garantir o controle total da ordenação.


Iteração com Cursores


Cursores são estruturas da linguagem T-SQL que permitem o processamento das linhas retornadas por uma consulta (SELECT), através de estruturas complexas de programação, como repetições ou  comandos condicionais.
O exemplo básico de cursor consiste em uma repetição (loop) onde um mesmo conjunto de comandos é executado para todas as linhas do retorno de uma consulta.

A sequência de declaração: DECLARE > OPEN > FETCH (loop) > CLOSE > DEALLOCATE

DECLARE @curcustid AS INT;

-- Cursor para percorrer os nomes dos objetos
DECLARE cust_cursor CURSOR FAST_FORWARD FOR 

  SELECT custid   FROM Sales.Customers;

  -- Abrindo Cursor para leitura
 OPEN cust_cursor;

-- Lendo a primeira linha e atribuindo às variáveis que serão atualizadas a cada iteração
FETCH NEXT FROM cust_cursor INTO @curcustid;

-- Percorrendo linhas do cursor (enquanto houver)
WHILE @@FETCH_STATUS = 0
BEGIN 

    EXEC Sales.ProcessCustomer @custid = @curcustid;

    FETCH NEXT FROM cust_cursor INTO @curcustid;
END;

-- Fechando Cursor para leitura
CLOSE cust_cursor;

-- Desalocando o cursor
DEALLOCATE cust_cursor;


Algumas considerações:
Um cursor deve estar sempre associado a uma consulta, especificada ao declarar o cursor.
O comando FETCH popula as variáveis recebidas como parâmetro com os valores da próxima linha da consulta a ser lida. O número de variáveis passadas como parâmetro deve ser igual ao número de colunas retornadas na consulta associada ao cursor.
A variável global @@FETCH_STATUS retorna o resultado da última operação FETCH executada por um cursor na conexão.
O status 0 significa que o comando FETCH retornou uma linha, qualquer outro resultado significa que não houve linha retornada.
Cursores são estruturas relativamente lentas se comparadas ao desempenho de consultas do banco. O uso descuidado desse método pode causar sérios problemas de performance.


Set-Based

Para obter o mesmo efeito e cumprir o mesmo tipo de tarefa usando somente instruções padrão sql sem usar cursores, você pode usar as cláusulas ORDER BY em conjunto com TOP(1) e um loop com WHILE.

Exemplo de iteração sem usar cursor:

DECLARE @curcustid AS INT;

--Seleciona o cliente com o menor número de código
SET @curcustid = (SELECT TOP (1) custid FROM Sales.Customers ORDER BY custid);

--Itera enquanto houver clientes com valores maiores que o atual
WHILE @curcustid IS NOT NULL
BEGIN
      EXEC Sales.ProcessCustomer @custid = @curcustid;
   
    --Atribui o valor de código do próximo cliente
     SET @curcustid = (SELECT TOP (1) custid FROM Sales.Customers WHERE custid > @curcustid ORDER BY custid);
END;
GO

Nestes casos é necessário criar indice para a coluna custid, caso contrário a tabela será toda escanada e a performance será pior do que um cursor.

Datas Relativas Usando Power BI Filter Visual, DAX e JavaScript

Um requisito frequente em painéis criados com Power BI é a definição de um filtro padrão para a data atual ou ano atual. Quando um painel é renderizado, ele apresenta os filtros que foram salvos por último e estes são sempre estáticos (não são alterados de forma relativa).

Para que não seja necessário re-filtrar o painel sempre que ele é carregado e para que a data seja atualizada sem intervenção manual, temos algumas alternativas para implementar um filtro padrão com datas relativas.

1-Utilizando a configuração do visual de filtros do Power BI

Quando um campo do tipo data é utilizado como filtro o Power BI, a configuração abaixo é apresentada como opção para definir datas relativas (relativas a data atual).

Clique no menu e selecione a opção relative.


















Será apresentada uma lista de opções para configuração do tipo de intervalo que será usado.

Para selecionar o ano atual escolha a opção "This". Irá por padrão manter o filtro do ano atual com base na data de hoje. No dia 01/01/2020 o filtro será alterado para o ano novo, sem que tenha que ser atualizado manualmente.
















Existe diferentes combinações de datas relativas, para períodos maiores é possível usar a opção "Last". Neste exemplo serão filtrados como padrão os últimos 5 anos com base na data de hoje 20/03/2019.






















2-Criando uma nova coluna no modelo de dados


Outra alternativa interessante é a de criar uma nova coluna utilizando DAX para identificar o ano atual. Este método é interessante pois permite que o filtro seja utilizando de forma implícita, sem que tenha que obrigatoriamente criar um visual do tipo filtro na tela do painel.

Último Ano = IF('Calendar'[Year]= MAX('Calendar'[Year]);"Último Ano";FORMAT('Calendar'[Date]; "YYYY"))

Na função acima, se o ano da linha atual for igual ao maior ano, ou seja, o ano mais recente, então defina como "Último Ano", senão, apresenta a data em um formato de ano.

Agora basta manter o filtro "Ultimo Ano" selecionado. Seja no próprio painel com um filtro ou seja internamente como filtro de pagina.



3-Usando JavaScript


Usando um custom visual chamado Power Slicer https://appsource.microsoft.com/en-us/product/power-bi-visuals/WA104382000 é possivel implementar também com funções javascript.

Este custom visual permite um maior controle sob as customizações do visual de um slice. Além disso possui recurso configuração valores padrão utilizando funções JavaScritp.

Crie um filtro com o Ano e informe na propriedade "Default Value" a função: (new Date().getFullYear()-5)

Essa função irá retornar o ano de 2019 e será decrementado por 5, resultando no ano de 2014.

Sempre que o painel for carregado, será filtrado de acordo como resultado da função javascript.













Definir filtro padrão baseado em uma data relativa, nos garante que os painéis não irão carregar dados desnecessários nos casos onde as análises são feitas predominantemente com base no ano atual. Estes métodos de se obter períodos relativos podem ser aplicadas dependendo da necessidade de cada cenário.


Vídeo:


terça-feira, 19 de março de 2019

Calcular Corretamente Idade em DAX

A princípio uma forma intuitiva para se fazer um cálculo de idade seria utilizar a função DateDiff para verificar a diferença entre a data atual e data de nascimento e fazer a divisão por 365.

Idade = DIVIDE(DATEDIFF(TODAY();Planilha1[Data];DAY);365)














Porém o resultado desta função é incorreto, neste exemplo a data de aniversário para completar 34 anos ainda não ocorreu e a função está marcando 34.

A forma correta de obter estes resultados, utiliza a função YEARFRAC.

 YEARFRAC  = Calcula a fração do ano representada pelo número de dias inteiros entre duas datas.

INT faz o arredondamento.









Funções para cálculo de idade que levam em consideração a fração do ano:

Idade Fracionada = YEARFRAC (Planilha1[Data]; Planilha1[Hoje] )

Idade Arredondada = INT(YEARFRAC (Planilha1[Data]; Planilha1[Hoje] ) )


Fonte:
https://www.sqlbi.com/blog/marco/2018/06/24/correct-calculate-of-age-in-dax-from-birthday/
https://docs.microsoft.com/en-us/dax/yearfrac-function-dax


Carga Incremental com SQL e Integration Services - SSIS/TSQL Incremental Load

O processo de carga e transformação em um modelo de data warehouse apresenta alguns desafios que podem ser abordados de diferentes formas, dependendo principalmente do volume de dados envolvido. Nos casos em que o volume é pequeno e o tempo de carga é baixo, uma das estratégias mais comum é a carga FULL. Nesta abordagem, o banco de dados do DW é truncado, todos seus registros são apagados e recarregados com informações atualizadas, mantendo assim a integridade entre a fonte e o DW. Apesar de ser uma técnica que mantem a integridade, ela acaba carregando dados que não foram alterados, sem necessidade, gerando um gargalo em bancos de dados maiores.

Neste artigo vamos abordar algumas alternativas para realizar uma carga incremental.

Basicamente, todos os exemplos seguem a mesma lógica que se baseia em comparar uma base de ORIGEM com uma base de DESTINO (DW) e:

1-Detectar novos registros. Registros que existem na origem mas não existem no destino
2-Detectar registros atualizados: Registros que existem em ambos bancos mas possui algum campo com valor diferente
3-Opcionalmente deletar registros no destino que foram deletados ou não existem mais na origem.


Para nossos exemplos, vamos criar algumas tabelas e inserir alguns dados:

--Criar bancos de origem e destino
CREATE DATABASE [SSISIncrementalLoad_Source]
CREATE DATABASE [SSISIncrementalLoad_Dest]

--Criar uma tabela no banco de origem
CREATE TABLE dbo.tblSource
(ColID int NOT NULL
,ColA varchar(10) NULL
,ColB datetime NULL constraint df_ColB default (getDate())
,ColC int NULL
,constraint PK_tblSource primary key clustered (ColID))

--Criar uma tabela no banco de destino
CREATE TABLE dbo.tblDest
(ColID int NOT NULL
,ColA varchar(10) NULL
,ColB datetime NULL
,ColC int NULL)

--Inserir alguns dados na origem
USE SSISIncrementalLoad_Source
GO
INSERT INTO dbo.tblSource (ColID,ColA,ColB,ColC) VALUES(0, 'A', '200180101', -1)
INSERT INTO dbo.tblSource (ColID,ColA,ColB,ColC) VALUES(1, 'B', '20180102', -2)
INSERT INTO dbo.tblSource (ColID,ColA,ColB,ColC) VALUES(2, 'N', '20180103', -3)


--Inserir alguns dados no destino
USE SSISIncrementalLoad_Dest
GO
--Inserir uma linha não alerada
INSERT INTO dbo.tblDest(ColID,ColA,ColB,ColC) VALUES(0, 'A', '200180101', -1)
--Inserir linha alterada
INSERT INTO dbo.tblDest (ColID,ColA,ColB,ColC) VALUES(1, 'C', '20190101', -2)


--Consultar novas linhas
SELECT s.ColID, s.ColA, s.ColB, s.ColC
FROM SSISIncrementalLoad_Source.dbo.tblSource s
LEFT JOIN SSISIncrementalLoad_Dest.dbo.tblDest d ON d.ColID = s.ColID
WHERE d.ColID IS NULL


Usando SQL Padrão para identificar linhas novas e alteradas:

Para iniciar, vamos aos exemplos básicos de como inserir, dados novos e atualizados:

Para inserir novas linhas, o segredo está na cláusula WHERE onde são filtradas linhas que não existem no destino, logo são linhas novas.

--Inserir no destino apenas as linhas novas
INSERT INTO SSISIncrementalLoad_Dest.dbo.tblDest (ColID, ColA, ColB, ColC)
SELECT s.ColID, s.ColA, s.ColB, s.ColC
FROM SSISIncrementalLoad_Source.dbo.tblSource s
     LEFT JOIN SSISIncrementalLoad_Dest.dbo.tblDest d ON d.ColID = s.ColID
WHERE d.ColID IS NULL

No processo de atualização, é feito um JOIN para identificar apenas as linhas que as colunas da origem e destino são diferentes e a atualização é feita apenas nestes casos.

--Atualizar dados no destino com as linhas alteradas.
UPDATE d
SET
   d.ColA = s.ColA
   ,d.ColB = s.ColB
   ,d.ColC = s.ColC
FROM SSISIncrementalLoad_Dest.dbo.tblDest d
     INNER JOIN SSISIncrementalLoad_Source.dbo.tblSource s ON s.ColID = d.ColID
WHERE (
(d.ColA != s.ColA)
OR (d.ColB != s.ColB)
OR (d.ColC != s.ColC)
)


Implementação do padrão utilizando o SSIS

Agora que vimos o padrão em sql, vamos criar um processo ETL utilizando o Integration Services.

Crie um pacote e inclua um objeto control flow do tipo data flow. Utilize as tarefas de Lookup, Condicional split e Row Command para realizar a a tarefa.





























1-Criar uma conexão Origem OLE DB: Conexão com tabela de origem

2-LEFT JOIN : Criar uma tarefa de Lookup apontando para a tabela de destino

































Fazer a junção entre origem e destino através da coluna ColID e incluir o sulfixo Dest_ nas novas colunas retornadas. Isso irá ajudar na diferenciação.


























Como por padrão a tarefa Lookup faz Inner Join e não Left Join, temos que marcar a opção de ignorar as falhas de saída. Isso vai fazer com que os casos que não houver correspondência exata entre os IDs de origem e destino, seja retornado NULL na coluna da tabela de destino. O valor NULL será usado para identificar a ausência do registro na tabela de destino.
















3-Divisão Condicional: Criar uma tarefa "Condicional Split" para separar o fluxo de novas linhas e linhas atualizadas.

New Rows: Quando a coluna ID do destino for null, isso significa que o lookup não achou, logo é novo
Changed Rows: Compara as colunas da origem e destino para identificar as diferenças, se houver alguma retorna.
Unchanged: Todos os demais casos.



4-Destino OLE DB: Crie uma tarefa de destination para enviar e inserir o fluxo de novas linhas diretamente para a tabela de destino.


























5-Update Destino Linha-por-linha: Inserir Linhas Alteradas com a tarefa OLE DB Command. Conecte o fluxo de linhas alteradas em uma tarega OLE DB Command.

Essa tarefa executa um comando sql para cada linha do fluxo de dados.

Configure as propriedades e informe o comando UPDATE com os parâmetros para serem mapeados na sequência.




































Mapeando os Parâmetros
Fazer o mapeamento do fluxo de entrada de dados com o comando sql.

As colunas da tabela destino serão atualizadas com o conteúdo da tabela de origem com base no ID (mapeado na clausula WHERE).

A sequencia que os parâmetros aparecem no comando é a sequência de numeração do nome do parâmetro.




















Esse padrão de carga incremental funciona bem, mas pode ser demorado para cargas muito volumosas, para isso existe uma variação para cargas maiores que realizam operações em conjuntos de dados e não em linha por linha, como no exemplo acima.


Padrão ETL Incremental Set-Based

Este exemplo utiliza uma tabela intermediaria stage para enviar as linhas alteradas e fazer a atualização em conjunto.
















1- Truncate Stage Update: O primeiro passo é garantir que a tabela stage esteja truncada, sem linha alguma. Para isso utilize um control flow para executar um comando sql

































2-Incremental Load Flow: O segundo passo, implementa o mesmo processo de carga padrão descrito anteriormente, mas ao invés de executar a atualização linha por linha, a tabela stage será populada com o fluxo de dados de linhas atualizadas.


























3- Set-Based Update: A terceira etapa executa um comando SQL para realizar a atualização a tabela destino com os dados da stage

































Pronto, desta maneira o processo de atualização é feito em conjunto, o processo desta forma é muito mais eficiente.

Carga Incremental utilizando o comando MERGE do T-SQL

Como alternativa ainda existe o comando MERGE disponível no T-SQL do SQL Server a partir de 2012.

Ele aplica a mesma lógica em um código bem enxuto e de fácil leitura. Ele define a origem e destino, identifica a coluna de junção nos casos de linhas alteradas, especifica as colunas que serão comparadas e ainda traz a possibilidade de fazer a exclusão.


MERGE INTO [dbo].[tblDest] AS TGT --Alvo
USING [dbo].[tblSource] AS SRC --Fonte

--Faz a comparação das linhas de SRC com TGT
ON SRC.ColID = TGT.ColID

--Quando a linha na fonte for igual a linha que já existe no alvo e tiver algum campo com valor diferente entre elas
WHEN MATCHED AND ( TGT.ColA <> SRC.ColA OR TGT.ColB <> SRC.ColB OR TGT.ColC <> SRC.ColC)
 THEN
   UPDATE
      SET TGT.ColA = SRC.ColA,
          TGT.ColB = SRC.ColB,
          TGT.ColC = SRC.ColC

--Quando a linha da fonte não existir no alvo, insere como nova linha
WHEN NOT MATCHED
    THEN
      INSERT
      VALUES(SRC.ColID, SRC.ColA, SRC.ColB, SRC.ColC)

--Quando existe alguma linha no alvo que não existe na fonte. DELETE (opcional)
WHEN NOT MATCHED BY SOURCE THEN
DELETE;

Estas são algumas técnicas relacionadas ao processo de carga ETL incremental, muito útil em situações onde é necessário manter a integridade entre a origem e o destino mas não é possível realizar uma carga full devido ao volume de dados.


Fonte:
https://andyleonard.blog/2007/07/ssis-design-pattern-incremental-loads/
http://www.sqlservercentral.com/articles/Integration+Services+(SSIS)/72492/
https://docs.microsoft.com/pt-br/sql/t-sql/statements/merge-transact-sql?view=sql-server-2017