AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 338129
Accepted
questionto42
questionto42
Asked: 2024-03-28 07:10:05 +0800 CST2024-03-28 07:10:05 +0800 CST 2024-03-28 07:10:05 +0800 CST

Como faço para criar e preencher uma tabela temporária de uma fonte de dados por meio de um DataTable C# sem nunca sair da tarefa de fluxo de dados do SSIS?

  • 772

Vim fazer esta pergunta depois de codificar em um componente de script por algum tempo, testando principalmente como fazer um loop nas colunas do Rowobjeto, 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 selectconsulta, 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 cwhich era o nome da coluna do Rowobjeto, não foi encontrado no DataRowobjeto drdo DateTableobjeto dt.

As colunas do objeto Row nem sempre correspondem ao nome da coluna do DataTable. Como faço para colar todas as colunas do Rowobjeto no DataTable para cada linha para que no final eu possa copiar os dados completos do DataTable para a tabela temporária?

sql-server
  • 2 2 respostas
  • 26 Views

2 respostas

  • Voted
  1. Best Answer
    questionto42
    2024-03-28T07:10:05+08:002024-03-28T07:10:05+08:00

    Depois de verificar isso por muitas horas, encontrei uma maneira de fazer isso. O principal a entender é que os nomes das colunas do Rowobjeto são alterados para que apenas as letras sejam mantidas, exemplo: my_column-1 btorna-se mycolumn1b. 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

    #region About me
    /* We use a DataTable to store the data from the input rows.
     * In the PreExecute method, we dynamically create columns in the DataTable based on the input columns.
     * In the Input0_ProcessInputRow method, we add each input row to the DataTable.
     * In the PostExecute method, we use SqlBulkCopy to efficiently insert all rows from the DataTable into the temporary table.
     * Once that is done, we can add columns with `select` queries from the temporary table in mere SQL.
     * The last step is not shown here; it could be either in the PostExecute or in another Script Component.
    */
    #endregion
    
    #region Namespaces
    using System;
    using System.Data;
    using System.Data.SqlClient;
    using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
    using System.Diagnostics;
    #endregion
    
    [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
    public class ScriptMain : UserComponent
    {
        private SqlConnection conn = null;
        private static string _connectionString => @"myconnectionstring";
        private DataTable dt = new DataTable();
        //private SqlCommand command = null;
    
        public override void PreExecute()
        {
            base.PreExecute();
            conn = new SqlConnection() { ConnectionString = _connectionString };
            conn.Open();
            // create temp table, make sure it matches your input
            using (SqlCommand cmd = new SqlCommand(@"CREATE TABLE ##TempTable (
    my_column1 varchar(50));", conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
    
        public override void Input0_ProcessInputRow(Input0Buffer Row)
        {
            // Create DataRow to store values
            DataRow dr = dt.NewRow();
    
            // Iterate over input columns to get original column names
            foreach (IDTSInputColumn100 inputColumn in this.ComponentMetaData.InputCollection[0].InputColumnCollection)
            {
                // Get the original column name
                string originalColumnName = inputColumn.Name;
    
                // Add column to DataTable with the original column name
                dt.Columns.Add(originalColumnName, typeof(object));
    
                // Get modified column name for checking null values in Row object
                string modifiedColumnName = originalColumnName.Replace("_", "").Replace(" ", "").Replace("-", "");
    
                // Check if the column is null
                PropertyInfo isNullProperty = typeof(Input0Buffer).GetProperty(modifiedColumnName + "_IsNull");
    
                if (isNullProperty != null)
                {
                    bool isNull = (bool)isNullProperty.GetValue(Row);
    
                    if (isNull)
                    {
                        // Handle null value as needed
                        // For example, you can set it to DBNull.Value
                        dr[originalColumnName] = DBNull.Value;
                        continue; // Skip to the next column
                    }
                }
    
                // Get property with matching name from Row object
                PropertyInfo property = typeof(Input0Buffer).GetProperty(modifiedColumnName);
    
                // Check if the property is null
                object value = property.GetValue(Row);
    
                // Check if the value is null
                if (value == null)
                {
                    // Handle null value as needed
                    // For example, you can set it to DBNull.Value
                    dr[originalColumnName] = DBNull.Value;
                }
                else
                {
                    // Add value to DataRow
                    dr[originalColumnName] = value;
                }
            }
            // Add populated DataRow to DataTable
            dt.Rows.Add(dr);
        }
    
        public override void PostExecute()
        {
            base.PostExecute();
            // here we would bulk copy data into the temp table
            // you may need to batch this operation or handle it differently based on your situation
            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))
            {
                // Now write that DataTable to the database 
                bulkCopy.DestinationTableName = "##tmpTable";
                bulkCopy.WriteToServer(dt);
            }
            this.conn.Close();
        }
    }
    

    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? .

    • 0
  2. Matt
    2024-03-30T22:54:37+08:002024-03-30T22:54:37+08:00

    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 ScriptMainfosse 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.

    • O SSIS foi projetado para passar tabelas da(s) origem(s) por meio de uma série de tarefas de transformação até o(s) destino(s). Portanto, existem componentes para consultar uma subconsulta (fonte original) e para adicionar colunas, calcular, transformar tudo sem script para a maioria dos casos de uso.
    • Desempenho. Usar uma CTE/Subconsulta na definição de origem original pode ter um desempenho exponencialmente melhor, pois reduzirá o número de linhas/quantidade de dados que são realmente puxados para o servidor SSIS na memória/disco para serem processados ​​no restante das etapas.
    • 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.
    • O uso do DataTable e da tabela temporária também pode levar a problemas de memória e desempenho em grandes conjuntos de dados.

    Então, acho que, ao determinar o uso de tarefas de script por linha como esta, eu perguntaria

    • Isso pode ser feito em um Derived Column Transformationou Lookup, Grouping, Conditional Splitetc
    • Isso pode ser feito com fórmula SQL na consulta de origem original ou outra transformação
    • C# me permitirá fazer algo que não posso fazer em SQL
    • Existe uma ferramenta melhor para esta transformação específica

    Definitivamente, 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.

    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve