कैसे एक 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 है "डबल" । मैं चाहता हूं कि यह "Int32" बन जाए ।

मुझे यह कैसे हासिल होगा?

जवाबों:


269

डेटाटेबल डेटा से भर जाने के बाद आप डेटाटाइप को नहीं बदल सकते। हालाँकि, आप डेटा तालिका को क्लोन कर सकते हैं, स्तंभ प्रकार को बदल सकते हैं और पिछले डेटा तालिका से क्लोन तालिका में डेटा लोड कर सकते हैं जैसा कि नीचे दिखाया गया है।

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

समाधान प्यार - सुरुचिपूर्ण! हालाँकि ImportRow () स्ट्रिंग मानों को मेरे लिए फ्लोट मानों में परिवर्तित नहीं करता है। क्या मुझसे कोई चूक हो रही है?
yangli.liy

1
DataTable.ImportRow () या (इसके बजाय इसका अंतर्निहित भंडारण) IConvertible इंटरफ़ेस का उपयोग करके मानों को परिवर्तित करता है। तदनुसार संपत्ति DataTable.Locale सेट करने के लिए सुनिश्चित करें! (डिफॉल्ट है कल्चरइन्फो.कोर्टकल्चर)
सर किल ए लॉट

यह काम नहीं करता। मैं db आने वाले बाइट सरणी कॉलम के बजाय एक मेमोरीस्ट्रीम कॉलम बनाने की कोशिश कर रहा हूं। यह System.ArgumentException देता है: प्रकार का मान स्तंभ प्रकार के साथ एक बेमेल है जो DATA स्तंभ में <System.Byte []> संग्रहीत करता है। अपेक्षित प्रकार
मेमोरीस्ट्रीम है

28

हालांकि यह सच है कि आप कॉलम के प्रकार DataTableको भरने के बाद नहीं बदल सकते FillSchema, आप कॉल करने के बाद इसे बदल सकते हैं , लेकिन कॉल करने से पहले Fill। उदाहरण के लिए, 3 स्तंभ एक आप से परिवर्तित करना चाहते है doubleकरने के लिए Int32, आप इस्तेमाल कर सकते हैं:

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

1
ध्यान दें कि यह काम नहीं करता है यदि आपके एडेप्टर की कमांड एक संग्रहीत प्रक्रिया है
मार्क सोउल

1
मैं Oracle.MangedDataAccess.Client.OracleDataAdapterएक संग्रहीत प्रक्रिया के साथ इस पर परीक्षण किया है। यह काम कर रहा है। धन्यवाद।
3per

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 को लागू करना चाहिए।" बाइट [] को स्ट्रिंग टाइप कॉलम में परिवर्तित करते समय।
हर्षद वेकारिया

बस इसमें कुछ जेनेरिक जोड़ें 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

मैंने कुछ अलग तरीका अपनाया है। मुझे एक एक्सेल आयात से एक डेटाइम को पार्स करने की आवश्यकता थी जो ओए तारीख प्रारूप में था। इस पद्धति का निर्माण करने के लिए काफी सरल है ... संक्षेप में,

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

धन्यवाद! ठीक वही जो मेरे द्वारा खोजा जा रहा था।
राहुल सिंह

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 तक आप अभिव्यक्ति की संपत्ति का उपयोग कर सकते हैं:

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

अच्छा उत्तर! कोई जरूरत नहीं है (...) और अशक्त मूल्यों की जाँच करने के लिए।
बेहजाद अब्रहिमी २५'१

2

मैंने एक एक्सटेंशन फ़ंक्शन बनाया, जो डेटाटेबल के कॉलम प्रकार को बदलने की अनुमति देता है। संपूर्ण तालिका को क्लोन करने और सभी डेटा आयात करने के बजाय यह केवल कॉलम को क्लोन करता है, मान को पार्स करता है और फिर मूल को हटा देता है।

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

उपरोक्त कोड सभी दशमलव कॉलम को डबल्स में बदल देता है।


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

मैंने मार्क के समाधान की दक्षता को जोड़ दिया - इसलिए मुझे पूरे डेटाटेबल के लिए नहीं है.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 लॉस लॉस डेटोस y एलिमार ला कोलुम्ना पूर्वकाल

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

1
आपको उत्तर देने के लिए कुछ संदर्भ जोड़ना चाहिए, कोड केवल उत्तर का कोई मूल्य नहीं है क्योंकि उन्हें निम्न गुणवत्ता के रूप में देखा जाता है।
नवाब नबी ज़ादा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.