Vim fazer esta pergunta depois de codificar em um componente de script por algum tempo, testando principalmente como fazer um loop nas colunas do Row
objeto, consulte Looping Through Columns in SSIS Script Component - Stack Overflow e a observação abaixo dele que me pede para abrir um nova pergunta. Também verifiquei minuciosamente a pergunta ainda mais antiga sobre a mesma coisa em Aplicar transformação de linha para múltiplas colunas de entrada em Transformação de script para descobrir como percorrer as colunas. Esta não é, portanto, a questão aqui.
Migro alguns trabalhos do SQL Agent para o SSIS. Os trabalhos do Agente executam SQL e têm muitos select
:s ou CTE:s aninhados. Meu objetivo é pegar cada código SQL fornecido e dividi-lo por cada nível de consulta aninhado, para que cada nível chame a atenção à primeira vista ao observar a tarefa de fluxo de dados do SSIS. Passo a passo é melhor do que observar grandes consultas SQL aninhadas.
Não sou o primeiro a fazer perguntas sobre como permanecer dentro do DFT e alterar a fonte de dados, consulte SSIS data flow to update source table rows after copying to destination , embora essa pergunta seja sobre como alterar a própria tabela de origem, enquanto esta pergunta é sobre como colocar alterações no topo da tabela de origem e tornando-a a nova saída dentro do DFT.
Veja este padrão:
select abc.*, abc.column1 + abc.column2 as column3 from (select * from xyz) abc
Ou com um CTE:
with abc as (
select * from xyz
)
select abc.*, abc.column1 + abc.column2 as column3 from abc
Os dois são iguais, e tento dividi-los em duas etapas na Tarefa de Fluxo de Dados (DFT), uma após a outra, para que haja, na melhor das hipóteses, apenas um nível de consulta SQL para cada nível de consulta aninhada:
Fonte OLE DB "DataSourceAbc":
select * from xyz
Componente de script:
create ##tmpDataSourceAbc as (...);
select abc.*, abc.column1 + abc.column2 as column3 from ##tmpDataSourceAbc;
Muitas vezes, trata-se apenas de adicionar algumas colunas ou alterar um pouco as colunas, ou fazer uma pesquisa ou algo semelhante, e para isso, o SSIS ou terceiros fornecem ferramentas como Coluna Derivada ou componentes de Pesquisa. Mas quero evitar reescrever o código SQL que tenho em mãos na linguagem SSIS com seu próprio tipo de dados. Chame-me de preguiçoso ou com medo, mas gostaria de assumir o código SQL como está, em vez de torná-lo um código SSIS.
Além do mais, eu gostaria de usar as ferramentas integradas que permitem SQL e evitar componentes de script sempre que possível, é por isso que uso a "OLE DB Source" no início para buscar dados com SQL do servidor em vez de apenas selecionando em uma tabela temporária dentro do componente de script. E como quero trabalhar mais na saída dessa select
consulta, preciso de um componente de script após a "Fonte OLE DB" com suas setas de saída para que ele possa passar todas as colunas posteriormente. Para deixar isso claro, se eu deixasse o fluxo de dados para um destino, o fluxo de dados pararia, pois não possui setas de saída e eu teria que adicionar as colunas após passar para a próxima etapa do Fluxo de Controle, e não o faço. quero isso. Quero ficar dentro do DFT o tempo todo, pois a consulta do SQL Agent também é apenas uma tarefa de fluxo de dados.
Portanto, o plano é criar um componente de script que pegue os dados de uma fonte OLE DB (por exemplo), depois crie uma tabela temporária e preencha essa tabela temporária com a fonte de dados. Depois, adiciona uma nova coluna ou altera algo em cima da tabela temporária, e por se tratar de uma tabela temporária, a nova coluna pode ser feita com mero SQL dentro da mesma DFT.
O que eu sei, mas ainda não quero fazer:
Eu sei como selecionar dados em uma tabela temporária com SQL em C#, consulte Selecionar na explicação/tabelas temporárias . Mas isso significaria ter um SQL que preenche a tabela temporária enquanto eu quero preenchê-la com os dados importados que obtive de um componente que está upstream no fluxo de dados.
Também sei que posso criar a tabela temporária no fluxo de controle, consulte Como criar uma tabela temporária na tarefa de fluxo de controle do SSIS e depois usá-la na tarefa de fluxo de dados? . No entanto, quero que a tabela temporária seja criada em execução no DFT exatamente quando eu precisar, como uma consulta aninhada ou CTE que é substituída por uma consulta de tabela temporária. Então, o pacote fica mais legível se eu supervisionar todo o fluxo de dados no DFT sem voltar ao Fluxo de Controle.
Assim, o plano é:
- Um DataTable armazena os dados das linhas de entrada com todas as suas colunas originais.
- No método PreExecute, crie colunas dinamicamente no DataTable com base nas colunas de entrada.
- No método Input0_ProcessInputRow, preencha o DataTable com cada linha de entrada.
- No método PostExecute, insira todas as linhas do DataTable na tabela temporária.
- Adicione uma coluna.
Tudo isso seria um componente de script que adiciona uma coluna à fonte de dados.
Mas tenho dificuldade em mapear as colunas do objeto Row com as colunas DataTable. Assim, a questão:
Alguém descobriu como as colunas do objeto Row podem ser mapeadas para um DataTable que eu uso para preencher a tabela temporária? Algo como:
DataTable dt = new DataTable();
DataRow dr = dt.NewRow();
...
foreach (var c in columns){
dr[c] = c;
}
dt.Rows.Add(dr);
Recebo este código: "A coluna 'myCol' não pertence à tabela." Assim, o c
which era o nome da coluna do Row
objeto, não foi encontrado no DataRow
objeto dr
do DateTable
objeto dt
.
As colunas do objeto Row nem sempre correspondem ao nome da coluna do DataTable. Como faço para colar todas as colunas do Row
objeto no DataTable para cada linha para que no final eu possa copiar os dados completos do DataTable para a tabela temporária?
Depois de verificar isso por muitas horas, encontrei uma maneira de fazer isso. O principal a entender é que os nomes das colunas do
Row
objeto são alterados para que apenas as letras sejam mantidas, exemplo:my_column-1 b
torna-semycolumn1b
. Se você mapear os nomes abreviados das colunas para encurtá-los também no outro lado, ou seja, os nomes das colunas originais da fonte de dados, isso funcionará.Código
Saída
A saída de uma tabela temporária é salva no banco de dados tempdb do seu servidor. Ele não é salvo no banco de dados em que você trabalha.
Consulte Como ver a tabela temporária criada por código no SQL Server? .
Primeiro, elogie você por abrir a pergunta, adicionando alguns detalhes e tentando uma resposta cuidadosa. Honestamente, sua resposta me fez pensar um pouco mais e poderia funcionar, desde que
public class ScriptMain
fosse criada uma vez no nível do DataSet, o que acredito ser provável, mas ainda não tentei.No entanto, existem alguns pontos de design que você pode considerar em sua solução final.
Input0_ProcessInputRow(Input0Buffer Row)
foi projetado para ser uma transformação por linha e cuja saída pode ser consumida nas próximas etapas. Em outras palavras, ele foi projetado para adicionar as novas colunas ou transformar o conteúdo da coluna diretamente na linha original, o que então modifica o conjunto de dados tabular disponível para as próximas etapas do pacote.Então, acho que, ao determinar o uso de tarefas de script por linha como esta, eu perguntaria
Derived Column Transformation
ouLookup, Grouping, Conditional Split
etcDefinitivamente, já faz alguns anos que usei scripts, pois abandonei o SSIS em favor de outras ferramentas, dadas APIs modernas e arquiteturas de nuvem. No entanto, usar um script no SSIS era geralmente (não exclusivamente) para obter uma fonte de algum lugar que exigisse raspar um site, interagir com o Microsoft Exchange, fazer coisas que realmente não são ideais. Em processos SQL ETL e de arquivamento puro, o SSIS deve ser capaz de lidar com isso dentro de seus componentes nativos.