Копировать datatable как столбцы в другой datatable

У меня есть пара DataTable, и мне нужно скопировать их в другой DataTable. Например, как вы можете видеть на прилагаемом рисунке, мне нужно взять все данные из исходной таблицы 1 и скопировать их в первые 2 столбца таблицы Dest, скопировать исходную таблицу 2 в следующие 2 столбца и так далее. Как этого можно легко достичь?

enter image description here

Edit: Я должен прочитать несколько файлов excel (я храню каждый файл в datatable), и я не буду знать точно, сколько исходной таблицы у меня будет, поэтому это должно быть сделано динамически каким-то образом.

5 ответов


предполагая, что ваши исходные таблицы имеют ту же структуру, которую вы можете использовать таблица.Copy () чтобы создать таблицу dest, а затем скопировать данные в цикл:

List<DataTable> sourceTables = getYourSourceTablesMethod();
if (sourceTables.Length>0)
{
    DataTable destTable = sourceTables[0].Copy();  

    for (int i = 1; i < sourceTables; i++) 
    {
       foreach (DataRow drow in sourceTables[i].Rows) 
       destTable.Rows.Add(drow.ItemArray);
    }
}

вы можете использовать метод слияния, который предоставляется framework, для использования и дополнительной информации см. Microsoft Datatable Merge


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

insert into destTable( 
select s1.col1, s1.col2, s2.col3, s2.col4, s3.col5, s3.col6, s4.col7, s4.col8 
from sourcetable1 s1, sourcetable2 s2, sourcetable3 s3, sourcetable4 s4 
where s1.id = s2.id and s2.id = s3.id and s3.id = s4.id) 

вы можете запускать такие запросы, как:

select col1,col2 into sourcetable1 from destTable
union
select col3,col4 into sourcetable2 from destTable
union
select col5,col6 into sourcetable3 from destTable
union
select col7,col8 into sourcetable4 from destTable

или, может следовать технике упомянутой над здесь.

в случае, если строк данных, это может быть:

foreach (DataRow row in DestTable)
{
    SourceTable1.ImportRow(row);
}

вы можете сначала создать целевую таблицу, добавить ее столбцы (суммируя количество столбцов во всех входных таблицах), а затем добавить ее строки, объединяя отдельные массивы значений для каждой строки во входных таблицах.

конечно, строки в результирующем DataTable будет содержать значения, как они появляются в направлении сверху вниз для каждой входной таблицы (выровнены сверху). Это также означает, что количество результирующих строк - это количество строк в самом большом входе таблица.

Сначала мы инициализируем и заполняем List<DataTable> переменная, затем мы выполним соединение, используя эту переменную в качестве параметра метода:

#region table collection initialization
List<DataTable> dts = new List<DataTable>();
var dt = new DataTable();
dt.Columns.Add("Test0", typeof(string));
dt.Rows.Add(1);
dt.Rows.Add(2);
dts.Add(dt);

dt = new DataTable();
dt.Columns.Add("Test1", typeof(int));
dt.Rows.Add(2);
dts.Add(dt);

dt = new DataTable();
dt.Columns.Add("Test3", typeof(int));
dt.Columns.Add("Test4");
dt.Columns.Add("Test5", typeof(int));
dt.Rows.Add(3, "a", 1);
dt.Rows.Add(4);
dt.Rows.Add(5, "a");
dt.Rows.Add(null, "a");
dts.Add(dt);

dt = new DataTable();
dt.Columns.Add("Test6", typeof(DateTime));
dt.Columns.Add("Test7", typeof(int));
dt.Rows.Add(DateTime.Now);
dts.Add(dt);
#endregion

// sample method usage
var result = GetJoinedTable(dts);

создать GetJoinedTableметод, который вернется в result переменная результирующая объединенная таблица:

private DataTable GetJoinedTable(List<DataTable> dts)
{
    var dest = new DataTable();

    //will be used if you have non-unique column names
    int counter = 0;

    foreach (var column in dts
        .SelectMany<DataTable, DataColumn>(t =>
            t.Columns.Cast<DataColumn>()))
    {
        dest.Columns.Add(column.ColumnName, column.DataType);

        // if you have non-unique column names use the following instead
        //dest.Columns.Add(String.Format("column_{0}", counter++), 
        //    column.DataType);
    }

    List<object> rowItems;

    for (int i = 0; i < dts.Max(t => t.Rows.Count); i++)
    {
        rowItems = new List<object>();
        for (int j = 0; j < dts.Count; j++)
        {
            if (dts[j].Rows.Count > i)
            {
                var r = dts[j].Rows[i].ItemArray
                    .Select((v, index) =>
                        (v == null || v == System.DBNull.Value)
                            ? GetDefault(dts[j].Columns[index].DataType) : v);
                rowItems.AddRange(r);
            }
            else
            {
                for (int c = 0; c < dts[j].Columns.Count; c++)
                {
                    rowItems.Add(GetDefault(dts[j].Columns[c].DataType));
                }
            }
        }
        dest.Rows.Add(rowItems.ToArray());
    }

    return dest;
}

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

object GetDefault(Type t)
{
    if (t.IsValueType)
    {
        return Activator.CreateInstance(t);
    }
    else
    {
        return null;
    }
}