Как изменить структуру DataTable, чтобы значения столбцов находились в нескольких столбцах?

1

Если у меня есть datatable со структурой вроде этого:

emp_num name  status  session_id

  22    john     0       4

  22    john     0       5

  34    moh      1       3

  35    Ran      0       3

  35    Ran      0       4

Как преобразовать его в datatable следующим образом:

emp_num name  status  session_id1  session_id2  session_id3  session_id4 session_id5 

  22    john     0       0             0               0            1          1

  34    moh      1       0             0               1            0          0   

  35    Ran      0       0             0               1            1          0

Я пытаюсь создать таблицу пользовательских данных с циклом, но это не является общим, я хочу что-то такое обобщенное, поэтому, если я добавлю больше столбцов или количество сеансов увеличится, я получаю исключения вне диапазона.

  • 1
    Я думаю, что с вашим подходом что-то в корне не так. Если между вашими сотрудниками и сессиями существует отношение один ко многим, вам нужно иметь две таблицы. одна таблица для сотрудников, где есть одна строка для каждого сотрудника, и другая таблица для сеансов, где есть одна строка для каждого сеанса. Каждая запись сеанса должна иметь emp_num, чтобы связать ее с сотрудником.
  • 0
    @Keith:yea да, есть две таблицы, и я делаю соединение между этими двумя таблицами и устанавливаю результат в datatable.now, мне нужен отчет со следующей структурой emp_num name status session_id1 session_id2 session_id3 ... количество столбцов зависит от значение session_id
Теги:
linq
collections
datatable
transpose

1 ответ

2
Лучший ответ
using System.Data;
public static class DataTableExtensionMethods
{
    public static DataTable TransposeIntegerColumnIntoColumns(this DataTable dt, int indexColumnToEstablishDuplicateRows, int integerColumnIdToTranspose, string transposedColumnName)
    {
        //Protection if the column to transpose is not an integer or doesn't exist
        if (integerColumnIdToTranspose >= dt.Columns.Count) return null;
        var columnDataType = dt.Columns[integerColumnIdToTranspose].DataType;
        if (columnDataType != typeof(int)) return null;

        //Get max sessions number
        int maxColumnNumber = 0;
        foreach (DataRow dr in dt.Rows)
        {
            int? number = dr.Field<int?>(integerColumnIdToTranspose);
            if (number != null)
            {
                maxColumnNumber = Math.Max(maxColumnNumber, (int)number);
            }
        }

        //Protection if there are zero rows or the maxColumnNumber is 0
        if (dt.Rows.Count == 0 || maxColumnNumber == 0) return null;

        //Make a copy of the table so we can remove duplicate rows and add the transposed columns
        DataTable result = dt.Copy();

        //Add columns to store the session_ids
        for (int i = 1; i <= maxColumnNumber; i++)
        {
            DataColumn dc = new DataColumn(transposedColumnName + i.ToString(), typeof(int));
            dc.DefaultValue = 0;
            //Possibly make an overloaded method that supports inserting columns
            result.Columns.Add(dc);
        }

        //Remove rows with duplicated employees
        for (int i = 0; i < result.Rows.Count; i++)
        {
            int duplicateRow = GetRowIndexById(result, indexColumnToEstablishDuplicateRows, result.Rows[i][indexColumnToEstablishDuplicateRows].ToString(), i + 1);
            if (duplicateRow > -1)
            {
                result.Rows.RemoveAt(duplicateRow);
            }
        }

        //Populate the transposed columns with values in the integer Column To Transpose
        foreach (DataRow dr in dt.Rows)
        {
            int? sessionNumber = dr.Field<int?>(integerColumnIdToTranspose);
            if (sessionNumber == null) continue;
            int rowIndex = GetRowIndexById(result, indexColumnToEstablishDuplicateRows, dr[indexColumnToEstablishDuplicateRows].ToString(), 0);

            result.Rows[rowIndex][transposedColumnName + sessionNumber.ToString()] = 1; //or +=1 if you want to increment the number
        }

        //Remove the integerColumnIdToTranspose (again overload this method if you want to keep this column)
        result.Columns.RemoveAt(integerColumnIdToTranspose);

        return result;
    }

   //Net 4 implementation with optional parameter
   //private static int GetRowIndexById(DataTable dt, int indexColumnToEstablishDuplicateRows, string id, int startLookAtRow = 0)
    private static int GetRowIndexById(DataTable dt, int indexColumnToEstablishDuplicateRows, string id, int startLookAtRow)
    {
        for (int i = startLookAtRow; i < dt.Rows.Count; i++)
        {
            if (dt.Rows[i][indexColumnToEstablishDuplicateRows].ToString() == id) return i;
        }
        return -1;
    }
}

Код звонка:

private void button1_Click(object sender, EventArgs e)
{
    DataTable dt = GetData();
    DataTable result = dt.TransposeIntegerColumnIntoColumns(0, 3, "session_id");
}

private DataTable GetData()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("emp_num", typeof(int));
    dt.Columns.Add("name");
    dt.Columns.Add("status", typeof(int));
    dt.Columns.Add("session_id", typeof(int));

    DataRow dr = dt.NewRow();
    dr["emp_num"] = 22;
    dr["name"] = "John";
    dr["status"] = 0;
    dr["session_id"] = 4;
    dt.Rows.Add(dr);

    dr = dt.NewRow();
    dr["emp_num"] = 22;
    dr["name"] = "John";
    dr["status"] = 0;
    dr["session_id"] = 5;
    dt.Rows.Add(dr);

    dr = dt.NewRow();
    dr["emp_num"] = 34;
    dr["name"] = "Moh";
    dr["status"] = 1;
    //dr["session_id"] = null;
    dt.Rows.Add(dr);

    dr = dt.NewRow();
    dr["emp_num"] = 35;
    dr["name"] = "Ran";
    dr["status"] = 0;
    dr["session_id"] = 3;
    dt.Rows.Add(dr);

    dr = dt.NewRow();
    dr["emp_num"] = 35;
    dr["name"] = "Ran";
    dr["status"] = 0;
    dr["session_id"] = 4;
    dt.Rows.Add(dr);

    return dt;
}

Результат:

Изображение 174551

  • 0
    Большое вам спасибо за эти усилия. но я использую .net 3.5, поэтому я сталкиваюсь с этой ошибкой Default parameter specifiers are not permitted во втором методе private static int GetRowIndexById(DataTable dt, int indexColumnToEstablishDuplicateRows, string id, int startLookAtRow = 0)
  • 1
    Хорошо, скопируйте / вставьте код из класса метода расширения DataTable в ваш проект, я сделал его совместимым с .Net 3.5 :)
Показать ещё 10 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню