DataTable에서 DataColumn의 DataType을 변경하는 방법은 무엇입니까?


120

나는 가지고있다:

DataTable Table = new DataTable;
SqlConnection = new System.Data.SqlClient.SqlConnection("Data Source=" + ServerName + ";Initial Catalog=" + DatabaseName + ";Integrated Security=SSPI; Connect Timeout=120");

SqlDataAdapter adapter = new SqlDataAdapter("Select * from " + TableName, Connection);
adapter.FillSchema(Table, SchemaType.Source);
adapter.Fill(Table);

DataColumn column = DataTable.Columns[0];

내가하고 싶은 것은 :

현재 column.DataType.Name 이 "Double" 이라고 가정합니다 . 나는 그것이 "Int32" 가되기를 원한다 .

어떻게해야합니까?

답변:


269

Datatable이 데이터로 채워진 후에는 DataType을 변경할 수 없습니다. 그러나 아래와 같이 데이터 테이블을 복제하고 컬럼 유형을 변경하고 이전 데이터 테이블에서 복제 된 테이블로 데이터를로드 할 수 있습니다.

DataTable dtCloned = dt.Clone();
dtCloned.Columns[0].DataType = typeof(Int32);
foreach (DataRow row in dt.Rows) 
{
    dtCloned.ImportRow(row);
}

솔루션 사랑-우아함! 그러나 ImportRow ()는 문자열 값을 플로트 값으로 변환하지 않는 것 같습니다. 여기에 뭔가 빠졌나요?
— yangli.liy 2014 년

1
DataTable.ImportRow () (또는 기본 저장소)는 IConvertible 인터페이스를 사용하여 값을 변환합니다. DataTable.Locale 속성을 적절하게 설정해야합니다! (기본값은 CultureInfo.CurrentCulture)
— Sir Kill A Lot

작동하지 않습니다. db 오는 바이트 배열 열 대신 메모리 스트림 열을 만들려고합니다. System.ArgumentException : 값 유형이 열 유형과 일치하지 않습니다. DATA 열에 <System.Byte []>를 저장할 수 없습니다. 예상 유형은 MemoryStream
— Mert Serimer입니다.

28

DataTable를 채운 후에는 열 유형을 변경할 수 없지만 을 호출 한 후를 호출 FillSchema하기 전에 변경할 수 있습니다 Fill. 예를 들어, 3 열은 변환 할 하나라고 double에 Int32, 당신은 사용할 수 있습니다 :

adapter.FillSchema(table, SchemaType.Source);
table.Columns[2].DataType = typeof (Int32);
adapter.Fill(table);

1
어댑터의 명령이 저장 프로 시저의 경우이 작업에 나타나지 않습니다
— 마크 Sowul

1
Oracle.MangedDataAccess.Client.OracleDataAdapter저장 프로 시저로 이것을 테스트했습니다 . 작동합니다. 감사.
— 년

21

이전 게시물이지만 한 번에 하나의 열을 주어진 유형으로 변환 할 수있는 DataTable 확장을 사용하여 고려할 것이라고 생각했습니다.

public static class DataTableExt
{
    public static void ConvertColumnType(this DataTable dt, string columnName, Type newType)
    {
        using (DataColumn dc = new DataColumn(columnName + "_new", newType))
        {
            // Add the new column which has the new type, and move it to the ordinal of the old column
            int ordinal = dt.Columns[columnName].Ordinal;
            dt.Columns.Add(dc);
            dc.SetOrdinal(ordinal);

            // Get and convert the values of the old column, and insert them into the new
            foreach (DataRow dr in dt.Rows)
                dr[dc.ColumnName] = Convert.ChangeType(dr[columnName], newType);

            // Remove the old column
            dt.Columns.Remove(columnName);

            // Give the new column the old column's name
            dc.ColumnName = columnName;
        }
    }
}

그런 다음 다음과 같이 호출 할 수 있습니다.

MyTable.ConvertColumnType("MyColumnName", typeof(int));

물론 열의 각 값을 실제로 새 유형으로 변환 할 수있는 한 원하는 유형을 사용합니다.


"개체가 IConvertible을 구현해야합니다."오류를 제공합니다. Byte []를 문자열 유형 열로 변환하는 동안.
— Harshad Vekariya

그냥 몇 가지 제네릭을 추가 public static void ConvertColumnType<T>(this DataTable dt, string columnName, TnewType) where T : Type, IConvertible
— TM

3
나는이 그냥 DBNulls, 예를 들면 변환하지 않도록, 가장 우아한 솔루션입니다 생각 dr[dc.ColumnName] = dr[columnName] == DBNull.Value ? DBNull.Value : Convert.ChangeType(dr[columnName], newType);
— miboper

8

반환 유형 변경도 고려하십시오.

select cast(columnName as int) columnName from table

8
Dim tblReady1 As DataTable = tblReady.Clone()

'' convert all the columns type to String 
For Each col As DataColumn In tblReady1.Columns
  col.DataType = GetType(String)
Next

tblReady1.Load(tblReady.CreateDataReader)

8

나는 약간 다른 접근 방식을 취했습니다. OA 날짜 형식의 Excel 가져 오기에서 datetime을 구문 분석해야했습니다. 이 방법론은 기본적으로 구축하기에 충분히 간단합니다.

  1. 원하는 유형의 열 추가
  2. 값을 변환하는 행을 찢어
  3. 원래 열을 삭제하고 이전 열과 일치하도록 새 열로 이름을 바꿉니다.

    private void ChangeColumnType(System.Data.DataTable dt, string p, Type type){
            dt.Columns.Add(p + "_new", type);
            foreach (System.Data.DataRow dr in dt.Rows)
            {   // Will need switch Case for others if Date is not the only one.
                dr[p + "_new"] =DateTime.FromOADate(double.Parse(dr[p].ToString())); // dr[p].ToString();
            }
            dt.Columns.Remove(p);
            dt.Columns[p + "_new"].ColumnName = p;
        }

감사! 내가 찾던 바로 그것.
— Rahul Singh

4

DataTable가 채워 지면 열 유형을 변경할 수 없습니다.

이 시나리오에서 가장 좋은 방법은 채우기 전에에 Int32열을 추가하는 DataTable것입니다.

dataTable = new DataTable("Contact");
dataColumn = new DataColumn("Id");
dataColumn.DataType = typeof(Int32);
dataTable.Columns.Add(dataColumn);

그런 다음 원본 테이블의 데이터를 새 테이블로 복제 할 수 있습니다.

DataTable dataTableClone = dataTable.Clone();

자세한 내용 은 다음과 같은 게시물입니다 .


4

예를 들어 문자열에서 int32로 변경하려는 경우 Expression 속성을 사용할 수 있습니다.

DataColumn col = new DataColumn("col_int" , typeof(int));
table.Columns.Add(col);
col.Expression = "table_exist_col_string"; // digit string convert to int  

좋은 대답! foreach (...) 및 null 값을 확인할 필요가 없습니다 .
— Behzad Ebrahimi

2

DataTable의 열 유형을 변경할 수있는 확장 함수를 만들었습니다. 전체 테이블을 복제하고 모든 데이터를 가져 오는 대신 열을 복제하고 값을 구문 분석 한 다음 원본을 삭제합니다.

    /// <summary>
    /// Changes the datatype of a column. More specifically it creates a new one and transfers the data to it
    /// </summary>
    /// <param name="column">The source column</param>
    /// <param name="type">The target type</param>
    /// <param name="parser">A lambda function for converting the value</param>
    public static void ChangeType(this DataColumn column, Type type, Func<object, object> parser)
    {
        //no table? just switch the type
        if (column.Table == null)
        {
            column.DataType = type;
            return;
        }

        //clone our table
        DataTable clonedtable = column.Table.Clone();

        //get our cloned column
        DataColumn clonedcolumn = clonedtable.Columns[column.ColumnName];

        //remove from our cloned table
        clonedtable.Columns.Remove(clonedcolumn);

        //change the data type
        clonedcolumn.DataType = type;

        //change our name
        clonedcolumn.ColumnName = Guid.NewGuid().ToString();

        //add our cloned column
        column.Table.Columns.Add(clonedcolumn);

        //interpret our rows
        foreach (DataRow drRow in column.Table.Rows)
        {
            drRow[clonedcolumn] = parser(drRow[column]);
        }

        //remove our original column
        column.Table.Columns.Remove(column);

        //change our name
        clonedcolumn.ColumnName = column.ColumnName;
    }
}

다음과 같이 사용할 수 있습니다.

List<DataColumn> lsColumns = dtData.Columns
    .Cast<DataColumn>()
    .Where(i => i.DataType == typeof(decimal))
    .ToList()

//loop through each of our decimal columns
foreach(DataColumn column in lsColumns)
{
    //change to double
    column.ChangeType(typeof(double),(value) =>
    {
        double output = 0;
        double.TryParse(value.ToString(), out output);
        return output;  
    });
}

위의 코드는 모든 10 진수 열을 두 배로 변경합니다.


1
DataTable DT = ...
// Rename column to OLD:
DT.Columns["ID"].ColumnName = "ID_OLD";
// Add column with new type:
DT.Columns.Add( "ID", typeof(int) );
// copy data from old column to new column with new type:
foreach( DataRow DR in DT.Rows )
{ DR["ID"] = Convert.ToInt32( DR["ID_OLD"] ); }
// remove "OLD" column
DT.Columns.Remove( "ID_OLD" );

1

Mark의 솔루션의 효율성을 결합하여 전체 DataTable 이 필요하지 않습니다..Clone 제네릭 및 확장 성과 함께 자체 변환 함수를 정의 할 수 있습니다 . 이것이 내가 끝낸 것입니다.

/// <summary>
///     Converts a column in a DataTable to another type using a user-defined converter function.
/// </summary>
/// <param name="dt">The source table.</param>
/// <param name="columnName">The name of the column to convert.</param>
/// <param name="valueConverter">Converter function that converts existing values to the new type.</param>
/// <typeparam name="TTargetType">The target column type.</typeparam>
public static void ConvertColumnTypeTo<TTargetType>(this DataTable dt, string columnName, Func<object, TTargetType> valueConverter)
{
    var newType = typeof(TTargetType);

    DataColumn dc = new DataColumn(columnName + "_new", newType);

    // Add the new column which has the new type, and move it to the ordinal of the old column
    int ordinal = dt.Columns[columnName].Ordinal;
    dt.Columns.Add(dc);
    dc.SetOrdinal(ordinal);

    // Get and convert the values of the old column, and insert them into the new
    foreach (DataRow dr in dt.Rows)
    {
        dr[dc.ColumnName] = valueConverter(dr[columnName]);
    }

    // Remove the old column
    dt.Columns.Remove(columnName);

    // Give the new column the old column's name
    dc.ColumnName = columnName;
}

이렇게하면 사용이 훨씬 더 간단하면서도 사용자 정의가 가능합니다.

DataTable someDt = CreateSomeDataTable();
// Assume ColumnName is an int column which we want to convert to a string one.
someDt.ConvertColumnTypeTo<string>('ColumnName', raw => raw.ToString());

0

Puedes agregar una columna con tipo de dato distinto, luego copiar los datos y eliminar la columna anterior

TB.Columns.Add("columna1", GetType(Integer))    
TB.Select("id=id").ToList().ForEach(Sub(row) row("columna1") = row("columna2"))    
TB.Columns.Remove("columna2")

1
답변에 컨텍스트를 추가해야합니다. 코드 전용 답변은 품질이 낮기 때문에 가치가 없습니다.
— Nawed Nabi Zada
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.