126

I have a datable generated with the content of a csv file. I use other information to map some column of the csv (now in the datatable) to information the user is required to fill.

In the best world the mapping would be alway possible. But this is not reality... So before I try to map the datatable column value I would need to check if that column even exist. If I don't do this check I have an ArgumentException.

Of course I can check this with some code like this :

try
{
    //try to map here.
}
catch (ArgumentException)
{ }

but I have for now 3 columns to map and some or all might be existing/missing

Is there a good way to check if a column exist in a datatable?

adinas
  • 4,150
  • 3
  • 37
  • 47
Rémi
  • 3,867
  • 5
  • 28
  • 44
  • Are you dealing with a `DataSet`/`DataTable`? If so, you can look at the table's Column collection for a list of all columns in the table. – asawyer Jul 17 '13 at 17:28
  • Yes, @asawyer the content of the csv is dumped in a datatable. I will have a look in this direction. – Rémi Jul 17 '13 at 17:29

8 Answers8

249

You can use operator Contains,

private void ContainColumn(string columnName, DataTable table)
{
    DataColumnCollection columns = table.Columns;        
    if (columns.Contains(columnName))
    {
       ....
    }
}

MSDN - DataColumnCollection.Contains()

Kilian Stinson
  • 2,376
  • 28
  • 33
Aghilas Yakoub
  • 28,516
  • 5
  • 46
  • 51
  • are you sure this is linq? I don't have any reference to linq in my code and this work – Rémi Jul 17 '13 at 17:37
  • it's operator simple of columns – Aghilas Yakoub Jul 17 '13 at 17:38
  • This is not a linq extension method, rather a member of the DataColumnCollection type, but would also work nicely. – asawyer Jul 17 '13 at 17:39
  • 5
    @AghilasYakoub Sure is, I forgot about that one. Probably the better way to go in this case as well. One thing though, "You can use operator Contains" - It's not an operator, it's a member method. – asawyer Jul 17 '13 at 17:41
94
myDataTable.Columns.Contains("col_name")
adinas
  • 4,150
  • 3
  • 37
  • 47
8

For Multiple columns you can use code similar to one given below.I was just going through this and found answer to check multiple columns in Datatable.

 private bool IsAllColumnExist(DataTable tableNameToCheck, List<string> columnsNames)
    {
        bool iscolumnExist = true;
        try
        {
            if (null != tableNameToCheck && tableNameToCheck.Columns != null)
            {
                foreach (string columnName in columnsNames)
                {
                    if (!tableNameToCheck.Columns.Contains(columnName))
                    {
                        iscolumnExist = false;
                        break;
                    }
                }
            }
            else
            {
                iscolumnExist = false;
            }
        }            
        catch (Exception ex)
        {

        }
        return iscolumnExist;
    }
lokendra jayaswal
  • 298
  • 1
  • 6
  • 19
5

It is much more accurate to use IndexOf:

If dt.Columns.IndexOf("ColumnName") = -1 Then
    'Column not exist
End If

If the Contains is used it would not differentiate between ColumName and ColumnName2.

Update:

If ds.Tables("TableName").Columns.IndexOf("ColumnName") = -1 Then
    'Column not exist
End If
supercrash10
  • 73
  • 1
  • 5
  • 2
    Contains does not have the behavior you describe. it's not like a string.contains. It's more "does my collection contains a column with this name?" and not "does my collection contains a column with a name containing this name?" – Rémi Dec 01 '20 at 14:44
  • How can we specified the table name? for example if ColumnName exist in Table1... – Flash Mar 03 '22 at 20:47
  • Yes. I have modified my answer. – supercrash10 Mar 21 '22 at 08:48
2

Base on accepted answer, I made an extension method to check column exist in table as

I shared for whom concern.

 public static class DatatableHelper
 {
        public static bool ContainColumn(this DataTable table, string columnName)
        {
            DataColumnCollection columns = table.Columns;
            if (columns.Contains(columnName))
            {
                return true;
            }

            return false;
        }
}

And use as dtTagData.ContainColumn("SystemName")

Hien Nguyen
  • 24,551
  • 7
  • 52
  • 62
1
DataColumnCollection col = datatable.Columns;        
if (!columns.Contains("ColumnName1"))
{
   //Column1 Not Exists
}

if (columns.Contains("ColumnName2"))
{
   //Column2 Exists
}
Boopathi.Indotnet
  • 1,280
  • 15
  • 18
0

You can look at the Columns property of a given DataTable, it is a list of all columns in the table.

private void PrintValues(DataTable table)
{
    foreach(DataRow row in table.Rows)
    {
        foreach(DataColumn column in table.Columns)
        {
            Console.WriteLine(row[column]);
        }
    }
}

http://msdn.microsoft.com/en-us/library/system.data.datatable.columns.aspx

asawyer
  • 17,642
  • 8
  • 59
  • 87
0

Worth pointing out that Contains(...) and IndexOf(...) >= 0 are both case-insensitive.

Good advise is to disallow multiple columns having the same name which differ only by case! But if you do, then Contains displays some odd behaviour:

// In all tests below, "IndexOf(...) >= 0" gives the same result
DataTable dt1 = new DataTable();
dt1.Columns.Add("Test");

dt1.Columns.Contains("Test"); // true, and same result with "IndexOf >= 0"
dt1.Columns.Contains("test"); // true...surprise!
dt1.Columns.Contains("TEST"); // true...surprise again!

DataTable dt2 = new DataTable();
dt2.Columns.Add("Test");
dt2.Columns.Add("test"); // works, but not recommended!
// Note: Adding a 2nd column with the same case, i.e. "Test", is not allowed

dt2.Columns.Contains("test"); // true
dt2.Columns.Contains("Test"); // true
dt2.Columns.Contains("TEST"); // false...huh?

The performance profile of Contains is also strange. Both dt1.Columns.Contains("Test"); and dt1.Columns.Contains("test"); return TRUE. Careful timing shows that when the column name exists with the same case, Contains is super-fast, almost like HashSet::Contains. But when the column name exists with different case (e.g. "test"), the performance is much slower, almost like every column is checked...and then the return is TRUE anyway!

These odd behaviours appear to be a feature of DataTable::Columns::Contains. If you need explicit case-sensitivity, or to get more consistent behaviour where you may have column names differing only by case, consider:

private bool ContainsCaseSensitive(DataTable dt, string colName)
{
    foreach (DataColumn col in dt.Columns)
    {
        if (col.ColumnName.Equals(colName))
            return true;
    }
    
    return false;
}

The performance of ContainsCaseSensitive is similar to Contains when the column you are searching for has a low Ordinal position, or does not exist, in the DataTable. For columns with a high Ordinal position, then ContainsCaseSensitive is a bit slower than Contains or IndexOf >= 0.

AlainD
  • 5,413
  • 6
  • 45
  • 99