Làm thế nào để thay đổi kiểu dữ liệu của một cột dữ liệu trong một bảng dữ liệu?


120

Tôi có:

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];

Điều tôi muốn làm là:

Giả sử hiện tại column.DataType.Name"Double" . Tôi muốn nó trở thành "Int32" .

Làm cách nào để đạt được điều này?

Câu trả lời:


269

Bạn không thể thay đổi DataType sau khi Datatable chứa đầy dữ liệu. Tuy nhiên, bạn có thể sao chép bảng Dữ liệu, thay đổi kiểu cột và tải dữ liệu từ bảng dữ liệu trước đó sang bảng sao chép như hình dưới đây.

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

Yêu thích giải pháp - Thanh lịch! Tuy nhiên ImportRow () dường như không chuyển đổi giá trị chuỗi thành giá trị float đối với tôi. Am i thiếu cái gì ở đây?
yangli.liy

1
DataTable.ImportRow () (hay đúng hơn là bộ nhớ cơ bản của nó) chuyển đổi các giá trị bằng cách sử dụng giao diện IConvertible. Đảm bảo đặt thuộc tính DataTable.Locale cho phù hợp! (mặc định là CultureInfo.CurrentCulture)
Sir Kill A Lot

Điều này không hoạt động. Tôi đang cố gắng tạo cột dòng bộ nhớ thay vì cột mảng byte sắp tới db. Nó cung cấp cho System.ArgumentException: Kiểu giá trị không khớp với kiểu cột Không thể lưu trữ <System.Byte []> trong Cột DATA. Loại dự kiến ​​là MemoryStream
Mert Serimer

28

Mặc dù đúng là bạn không thể thay đổi loại cột sau khi DataTableđiền, bạn có thể thay đổi nó sau khi gọi FillSchema, nhưng trước khi gọi Fill. Ví dụ: giả sử cột thứ 3 là cột bạn muốn chuyển đổi doublesang Int32, bạn có thể sử dụng:

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

1
Lưu ý rằng điều này không xuất hiện để làm việc nếu lệnh của bộ chuyển đổi của bạn là một thủ tục lưu trữ
Đánh dấu Sowul

1
Tôi đã thử nghiệm điều này Oracle.MangedDataAccess.Client.OracleDataAdaptervới một quy trình được lưu trữ. Nó đang hoạt động. Cảm ơn.
3

21

Bài cũ, nhưng tôi nghĩ tôi sẽ cân nhắc, với tiện ích mở rộng DataTable có thể chuyển đổi một cột tại một thời điểm, thành một loại nhất định:

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;
        }
    }
}

Sau đó nó có thể được gọi như thế này:

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

Tất nhiên bằng cách sử dụng bất kỳ kiểu nào bạn muốn, miễn là mỗi giá trị trong cột thực sự có thể được chuyển đổi sang kiểu mới.


Đưa ra lỗi "Đối tượng phải triển khai IConvertible." trong khi chuyển Byte [] sang cột kiểu chuỗi.
Harshad Vekariya

Chỉ cần thêm một số thông tin chung vào nó public static void ConvertColumnType<T>(this DataTable dt, string columnName, TnewType) where T : Type, IConvertible
TM

3
Tôi nghĩ rằng đây là giải pháp thanh lịch nhất, chỉ cần tránh chuyển đổi DBNulls, ví dụ: dr[dc.ColumnName] = dr[columnName] == DBNull.Value ? DBNull.Value : Convert.ChangeType(dr[columnName], newType);
miboper

8

Cũng nên xem xét việc thay đổi kiểu trả về:

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

Tôi đã thực hiện một chút cách tiếp cận khác. Tôi cần phân tích cú pháp ngày giờ từ một lần nhập excel có định dạng ngày tháng OA. Phương pháp luận này đủ đơn giản để xây dựng từ ... về bản chất,

  1. Thêm cột loại bạn muốn
  2. Rip qua các hàng chuyển đổi giá trị
  3. Xóa cột ban đầu và đổi tên thành cột mới để khớp với cột cũ

    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;
        }

Cảm ơn! Chính xác những gì tôi đang tìm kiếm.
Rahul Singh

4

Khi một DataTableđã được điền, bạn không thể thay đổi loại cột.

Tùy chọn tốt nhất của bạn trong trường hợp này là thêm một Int32cột vào DataTabletrước khi điền nó:

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

Sau đó, bạn có thể sao chép dữ liệu từ bảng gốc của mình sang bảng mới:

DataTable dataTableClone = dataTable.Clone();

Đây là một bài đăng với nhiều chi tiết hơn .


4

nếu bạn chỉ muốn thay đổi một cột. ví dụ từ chuỗi thành int32, bạn có thể sử dụng thuộc tính Biểu thức:

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

câu trả lời tốt! không cần foreach (...) và kiểm tra các giá trị null.
Behzad Ebrahimi

2

Tôi đã tạo một hàm mở rộng cho phép thay đổi kiểu cột của DataTable. Thay vì sao chép toàn bộ bảng và nhập tất cả dữ liệu, nó chỉ sao chép cột, hãy phân tích cú pháp giá trị và sau đó xóa bản gốc.

    /// <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;
    }
}

Bạn có thể sử dụng nó như vậy:

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;  
    });
}

Đoạn mã trên thay đổi tất cả các cột thập phân thành gấp đôi.


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

Tôi đã kết hợp hiệu quả của giải pháp Mark - vì vậy tôi không cần phải có .Clonetoàn bộ DataTable - với tính tổng quát và khả năng mở rộng, vì vậy tôi có thể xác định chức năng chuyển đổi của riêng mình . Đây là những gì tôi đã kết thúc với:

/// <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;
}

Bằng cách này, cách sử dụng đơn giản hơn rất nhiều, đồng thời có thể tùy chỉnh:

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 chưng cất, luego copiar los datos y khửr 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
Bạn nên thêm một số ngữ cảnh để bạn trả lời, câu trả lời chỉ có mã không có giá trị vì chúng được coi là chất lượng thấp.
Nawed Nabi Zada
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.