Вопрос по ado.net, c# – C # DataTable Внутреннее соединение с динамическими столбцами

6

Я пытаюсь соединить две таблицы данных вместе, как в этом вопросе:

Внутреннее объединение DataTables в C #

Я пытаюсь получить вывод, чтобы он был единым "объединенным" таблица с колонками из обеих исходных таблиц. У них обоих будет общий столбец с датой.

Данный ответ хорош для DataTables с фиксированными столбцами, но что если они создаются динамически и могут иметь любое количество столбцов, как я могу присоединиться к ним?

например

T1 (datestamp, t1Column1, t1Column2, t1ColumnN...)
T2 (datestamp, t2Column1, t2Column2, t2ColumnN...)

Я хотел бы присоединиться, чтобы создать следующее:

J1 (datestamp, t1Column1, t1Column2, t1ColumnN, ..., t2Column1, t2Column2, t2ColumnN...)

Это возможно?

Хорошо, но можете заставить меня сделать это, пожалуйста, не могли бы вы привести пример с двумя данными и результатами, которые вы хотите. andres descalzo
Я не думаю, что Linq - это вариант, так как вам нужно знать имена столбцов, в которые вы пытались спроецировать. finoutlook
Не могли бы вы привести пример некоторых данных, которые будут результатом, который вы хотите получить? andres descalzo
Можете ли вы использовать & quot; linq & quot ;? andres descalzo

Ваш Ответ

3   ответа
7

которое не основано на циклическом прохождении столбцов.

Он использует «слияние»; метод, который я ранее отклонил, поскольку я думал, что обе таблицы требуют одинаковой структуры.

Сначала вам нужно создать первичный ключ для двух таблиц данных:

// set primary key
T1.PrimaryKey = new DataColumn[] { T1.Columns["DateStamp"] };
T2.PrimaryKey = new DataColumn[] { T2.Columns["DateStamp"] };

Затем добавьте обе таблицы в набор данных, чтобы можно было добавить взаимосвязь:

// add both data-tables to data-set
DataSet dsContainer = new DataSet();
dsContainer.Tables.Add(T1);
dsContainer.Tables.Add(T2);

Затем добавьте связь между двумя ключевыми столбцами в наборе данных:

// add a relationship between the two timestamp columns
DataRelation relDateStamp = new DataRelation("Date", new DataColumn[] { T1.Columns["DateStamp"] }, new DataColumn[] { T2.Columns["DateStamp"] });
dsContainer.Relations.Add(relDateStamp);

Наконец, теперь вы можете скопировать первую таблицу данных в новый «комбинированный»; версия, а затем объединить во второй:

// populate combined data
DataTable dtCombined = new DataTable();
dtCombined = T1.Copy();
dtCombined.Merge(T2, false, MissingSchemaAction.Add);

Примечание. Метод Merge требует, чтобы второй аргумент был равен false, иначе он копирует структуру, но не данные второй таблицы.

Это тогда объединит следующие таблицы:

T1 (2012-05-09, 111, 222)
T2 (2012-05-09, 333, 444, 555)

в комбинированную версию на основе первичного ключа:

J1 (2012-05-09, 111, 222, 333, 444, 555)
1

как я устал видеть все эти функции внутреннего соединения, которые не надежно эмулируют SQL, я решил сделать здесь свою собственную:

private DataTable JoinDataTables(DataTable t1, DataTable t2, params Func<DataRow, DataRow, bool>[] joinOn)
{
    DataTable result = new DataTable();
    foreach (DataColumn col in t1.Columns)
    {
        if (result.Columns[col.ColumnName] == null)
            result.Columns.Add(col.ColumnName, col.DataType);
    }
    foreach (DataColumn col in t2.Columns)
    {
        if (result.Columns[col.ColumnName] == null)
            result.Columns.Add(col.ColumnName, col.DataType);
    }
    foreach (DataRow row1 in t1.Rows)
    {
        var joinRows = t2.AsEnumerable().Where(row2 =>
            {
                foreach (var parameter in joinOn)
                {
                    if (!parameter(row1, row2)) return false;
                }
                return true;
            });
        foreach (DataRow fromRow in joinRows)
        {
            DataRow insertRow = result.NewRow();
            foreach (DataColumn col1 in t1.Columns)
            {
                insertRow[col1.ColumnName] = row1[col1.ColumnName];
            }
            foreach (DataColumn col2 in t2.Columns)
            {
                insertRow[col2.ColumnName] = fromRow[col2.ColumnName];
            }
            result.Rows.Add(insertRow);
        }
    }
    return result;
}

Пример того, как вы можете использовать это:

var test = JoinDataTables(transactionInfo, transactionItems,
               (row1, row2) =>
               row1.Field<int>("TransactionID") == row2.Field<int>("TransactionID"));
Отлично сработано. Есть ли способ изменить его, чтобы иметь возможность указать оператор И или ИЛИ между несколькими & quot; присоединиться к & quot; условия?
1

что вы можете адаптировать ответ в связанном вопросе, чтобы использоватьиндекс столбца, а не имя столбца. Или вы можете просто просмотреть элементы в каждой строке, например так:

foreach(DataRow row in table.Rows)
{
    foreach(DataColumn column in table.Columns)
    {
        object value = row[column]; // add this to your combined table
    }
}
Спасибо - я надеялся избежать зацикливания всех столбцов, поскольку у меня уже есть несколько вложенных циклов для настройки исходных таблиц. Это может быть довольно сложно, если данные в таблицах содержат много разных дат / ключей. finoutlook

Похожие вопросы