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 열은 변환 할 하나라고 doubleInt32, 당신은 사용할 수 있습니다 :

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.