SSIS — переменная объекта, преобразованная в DataTable, становится пустой

Я пытаюсь создать объектную переменную, которая будет содержать коллекцию из Выполнение задачи SQL. Эта коллекция будет использоваться в нескольких задачах сценария во всем пакете ETL.

Проблема в том, что после первого Fill первой задачи сценария объектная переменная становится пустой. Вот код того, как я использовал переменную в DataTable:

try
            {
                DataTable dt = new DataTable();

                OleDbDataAdapter da = new OleDbDataAdapter();

                da.Fill(dt, Dts.Variables["reportMetrics"].Value);

                Dts.TaskResult = (int)ScriptResults.Success;
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message);
                Dts.TaskResult = (int)ScriptResults.Failure;
            }

Во всем пакете ETL компоненты Script Task будут содержать этот фрагмент кода. Поскольку переменная становится пустой после первого Fill, я не могу повторно использовать объектную переменную.

Я предполагаю, что метод Fill как-то связан с этим.

Спасибо!


person DustineTheGreat    schedule 03.12.2014    source источник
comment
Посмотрите мой ответ на этот вопрос, он показывает, как повторно использовать объектную переменную с потоками ADODB stackoverflow.com/questions/25253319/   -  person Kyle Hale    schedule 03.12.2014


Ответы (3)


Похоже, ваш объект Dts.Variables["reportMetrics"].Value содержит объект DataReader. Этот объект разрешает прямой доступ к данным только для чтения. Вы не можете заполнить DataTable дважды, используя DataReader. Чтобы выполнить вашу задачу, вам нужно создать еще одну задачу сценария, которая выполняет именно то, что вы описали здесь: она читает объект Reader to DataTable и сохраняет этот объект DataTable в другом Dts.Variable с типом Object.

Dts.Variables["reportMetricsTable"].Value = dt

После этого все ваши последующие задачи сценария должны либо создавать копию этой таблицы, если они изменяют данные, либо использовать ее напрямую, если они не изменяют ее.

DataTable dtCopy = (Dts.Variables["reportMetricsTable"].Value as DataTable).Copy()

person Slava    schedule 03.12.2014

У меня была аналогичная ситуация. Хотя я думаю, что вы можете выполнить задачу SQL с запросом SELECT COUNT(*) и присвоить результат переменной SSIS, я создал переменную int SSIS с именем totalCount с исходным значением 0. Я ожидаю, что общее количество be > 0 (иначе мне нечего будет повторять), поэтому я создал оператор if в своей задаче сценария. Если значение равно нулю, я предполагаю, что totalCount не был инициализирован, поэтому я использую тот же код, что и вы (с методом Fill). В противном случае (т. е. в дальнейших итерациях) я пропускаю эту часть и продолжаю использовать переменную totalCount. Вот блок кода. Надеюсь, поможет:

if ((int)Dts.Variables["User::totalCount"].Value == 0)    // if the total count variable has not been initialized...
        {
            System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter();
            DataTable stagingTablesQryResult = new DataTable();
            da.Fill(stagingTablesQryResult, Dts.Variables["User::stagingTablesQryResultSet"].Value);    // to be used for logging how many files are we iterating. It may be more efficient to do a count(*) outside this script and save the total number of rows for the query but I made this as proof of concept for future developments.

            Dts.Variables["User::totalCount"].Value = stagingTablesQryResult.Rows.Count;
        }

Console.WriteLine("{0}. Looking for data file {0} of {1} using search string '{2}'.", counter, Dts.Variables["User::totalCount"].Value, fileNameSearchString);
person Marcos    schedule 01.11.2016
comment
Извините, я считаю, что вы ищете повторное использование коллекции, а не только общее количество элементов. Что, если вы создадите переменную SSIS типа Object и назначите ей переменную DataTable в своей задаче сценария? Я сделал что-то подобное, но это был массив, назначенный объектной переменной SSIS, но я думаю, что применима та же логика. Удачи! - person Marcos; 01.11.2016

Превосходно

Это помогло мне решить проблему при создании платформы myt ETL.

По сути, я выполняю задачу SQL для создания набора данных задач, есть некоторые встроенные преобразования и правила, которые выдвигают соответствующие задачи на первый план, которые по очевидным причинам я хочу выполнять только один раз за выполнение.

Затем мне нужно получить уникальные идентификаторы процессов из набора данных (для использования в цикле For Each)

В FEL я хочу затем получить соответствующие записи из исходного набора данных, чтобы затем выполнить дальнейший процесс FEL.

Я столкнулся с тем же «пустым набором данных» для второго выполнения против набора данных.

Я подумал, что попытаюсь поделиться своим решением, чтобы помочь другим

Вам нужно будет добавить пространства имен

используя System.Data.OleDb;

в сценарии

Снимок экрана с решением

Получить набор данных

Выполнить SQL - получить ваши данные и передать в переменный объект

Потяните D Объявите переменные объекты

 public void Main()
        {
            DataTable dt            = new DataTable();
            OleDbDataAdapter da     = new OleDbDataAdapter();
            //Read the original table
            da.Fill(dt, Dts.Variables["Tbl"].Value);
            //Push to a replica
            Dts.Variables["TblClone"].Value = dt;

            Dts.TaskResult = (int)ScriptResults.Success;
        }

Построить список процессов Получает список идентификаторов процессов (и имен) путем фильтрации по полю ранга в наборе данных.

Объявление объектов переменных

public void Main()
        {  //Take a copy of the Cloned Dataset
            DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();

            //Lock the output object variable
            Dts.VariableDispenser.LockForWrite("User::ProcTbl");

            //Create a data table to place the results into which we can write to the output object once finished
            DataTable dtWrite = new DataTable();

            //Create elements to the Datatable programtically
            //dtWrite.Clear();

            dtWrite.Columns.Add("ID", typeof(Int64));
            dtWrite.Columns.Add("Nm");

            //Start reading input rows
            foreach (DataRow dr in dtRead.Rows)
            {
                //If 1st col from Read object = ID var 
                if (Int64.Parse(dr[9].ToString()) == 1) //P_Rnk = 1 
                {
                    DataRow newDR = dtWrite.NewRow();

                        newDR[0] = Int64.Parse(dr[0].ToString());
                        newDR[1] = dr[4].ToString();

                    //Write the row
                    dtWrite.Rows.Add(newDR);
                }
            }

            //Write the dataset back to the object variable
            Dts.Variables["User::ProcTbl"].Value = dtWrite;
            Dts.Variables.Unlock();

            Dts.TaskResult = (int)ScriptResults.Success;
        }

Создать TaskList из ProcList

Циклический обход ProcessID в цикле For Each

Собрать коллекцию TL

..и карта Варс

Создание сопоставлений TL Var

Build TL Script Это будет динамически строить вывод для вас (NB, это работает для меня, хотя я его тщательно не тестировал, поэтому, если он не работает... поиграйтесь с ним). Вы увидите, что я закомментировал некоторые вещи отладки.

public void Main()
    {   
        //Clone the copied table
        DataTable dtRead = (Dts.Variables["TblClone"].Value as DataTable).Copy();

        //Read the var to filter the records by
        var ID = Int64.Parse(Dts.Variables["User::ProcID"].Value.ToString());

        //Lock the output object variable
        Dts.VariableDispenser.LockForWrite("User::SubTbl");

        //Debug Test the ProcID being passed
        //MessageBox.Show(@"Start ProcID =  " + ID.ToString());
        //MessageBox.Show(@"TblCols =  " + dtRead.Columns.Count);

        //Create a data table to place the results into which we can write to the output object once finished
        DataTable dtWrite   = new DataTable();

        //Create elements to the Datatable programtically
        //dtWrite.Clear();
        foreach (DataColumn dc in dtRead.Columns)
        {
            dtWrite.Columns.Add(dc.ColumnName, dc.DataType);
        }

        MessageBox.Show(@"TblRows =  " + dtRead.Rows.Count); 
        //Start reading input rows
        foreach (DataRow dr in dtRead.Rows)
        {
            //If 1st col from Read object = ID var 
            if (ID == Int64.Parse(dr[0].ToString()))
            {
                DataRow newDR = dtWrite.NewRow();

                //Dynamically create data for each column
                foreach (DataColumn dc in dtRead.Columns)
                {
                    newDR[dc.ColumnName] = dr[dc.ColumnName];
                }
                //Write the row
                dtWrite.Rows.Add(newDR);

                //Debug
                //MessageBox.Show(@"ProcID =  " + newDR[0].ToString() + @"TaskID =  " + newDR[1].ToString() + @"Name = " + newDR[4].ToString());
            }

        }
        //Write the dataset back to the object variable
        Dts.Variables["User::SubTbl"].Value = dtWrite;
        Dts.Variables.Unlock();

        Dts.TaskResult = (int)ScriptResults.Success;
    }

Для каждого контейнера цикла

Коллекция FEL Cont Не забудьте сопоставить элементы в сопоставлениях переменных.

Теперь вы можете использовать записи и делать что-то с этими данными. Я включил сценарий Msg Loop для простой проверки данных ... на самом деле это сработает и вызовет другие процессы, но просто чтобы помочь вам в проверке данных, я бы включил его

Цикл сообщений

Скрипт цикла сообщений

public void Main()
        {
            // TODO: Add your code here
                MessageBox.Show("ID = " + Dts.Variables["User::ProcID"].Value + ", and val = " + Dts.Variables["User::TaskID"].Value, "Name = Result");

                Dts.TaskResult = (int)ScriptResults.Success;

        }

Надеюсь, что это поможет кому-то решить их проблему (я пытался решить это в течение рабочего дня или около того:/

person Nique    schedule 11.01.2019
comment
пожалуйста, отредактируйте, чтобы это выглядело так, как если бы вы отвечали кому-то другому. Не благодарите других, просто добавьте лучший/другой ответ к другим ответам? - person Jean-François Fabre; 11.01.2019