Datatable select with multiple conditions
Asked Answered
C

8

61

I have a datatable with 4 columns A, B, C and D such that a particular combination of values for column A, B and C is unique in the datatable.

Objective: To find the value of column D, for a given combination of values for column A, B and C.

I guess looping over the set of data rows should do it. Is there a way to use Datatable.Select() to accomplish this? To be more specific - can I have multiple conditions in the select filter i.e. a logical AND operator connecting conditions for each of the columns A, B and C.

Callas answered 2/1, 2010 at 8:7 Comment(2)
So column D is a computed column, based on A, B, and C?Coinsure
have you considered emiting this as a query, and letting the database do what it's there for?Sweatt
H
140

Yes, the DataTable.Select method supports boolean operators in the same way that you would use them in a "real" SQL statement:

DataRow[] results = table.Select("A = 'foo' AND B = 'bar' AND C = 'baz'");

See DataColumn.Expression in MSDN for the syntax supported by DataTable's Select method.

Homologous answered 2/1, 2010 at 8:13 Comment(0)
R
47

Do you have to use DataTable.Select()? I prefer to write a linq query for this kind of thing.

var dValue=  from row in myDataTable.AsEnumerable()
             where row.Field<int>("A") == 1 
                   && row.Field<int>("B") == 2 
                   && row.Field<int>("C") == 3
             select row.Field<string>("D");
Racine answered 2/1, 2010 at 8:12 Comment(2)
+1 from me, too. It's better visible as programming language than as SQL command. Sincerely, I don't know which of them is faster, but I like this one more.Stacee
Linq is faster and recommended in cases like theseBindman
L
7

I found that having too many and's would return incorrect results (for .NET 1.1 anyway)

DataRow[] results = table.Select("A = 'foo' AND B = 'bar' AND C = 'baz' and D ='fred' and E = 'marg'"); 

In my case A was the 12th field in a table and the select was effectively ignoring it.

However if I did

DataRow[] results = table.Select("A = 'foo' AND (B = 'bar' AND C = 'baz' and D ='fred' and E = 'marg')"); 

The filter worked correctly!

Lundt answered 6/5, 2010 at 10:35 Comment(1)
That has to be some bug of sorts. There is no logically difference between your two examples.Superaltar
B
6

Try this,
I think ,this is one of the simple solutions.

int rowIndex = table.Rows.IndexOf(table.Select("A = 'foo' AND B = 'bar' AND C = 'baz'")[0]);
string strD= Convert.ToString(table.Rows[rowIndex]["D"]);

Make sure,combination of values for column A, B and C is unique in the datatable.

Benedictbenedicta answered 15/11, 2011 at 8:32 Comment(1)
Your solution int rowIndex = ... [0] can only return the first row matched, even though the request is to return a "unique" value, there might be multiple values which are then just ignored. Why not int[] rowIndex = ... and return any result. The focus being that if the so called unique combination is not unique and there is a data fault then it can be remedied.Downes
B
2
    protected void FindCsv()
    {
        string strToFind = "2";

        importFolder = @"C:\Documents and Settings\gmendez\Desktop\";

        fileName = "CSVFile.csv";

        connectionString= @"Driver={Microsoft Text Driver (*.txt; *.csv)};Dbq="+importFolder+";Extended Properties=Text;HDR=No;FMT=Delimited";
        conn = new OdbcConnection(connectionString);

        System.Data.Odbc.OdbcDataAdapter  da = new OdbcDataAdapter("select * from [" + fileName + "]", conn);
        DataTable dt = new DataTable();
        da.Fill(dt);

        dt.Columns[0].ColumnName = "id";

        DataRow[] dr = dt.Select("id=" + strToFind);

        Response.Write(dr[0][0].ToString() + dr[0][1].ToString() + dr[0][2].ToString() + dr[0][3].ToString() + dr[0][4].ToString() + dr[0][5].ToString());
    }
Bruno answered 23/8, 2011 at 20:11 Comment(0)
N
1
Dim dr As DataRow()


dr = dt.Select("A="& a & "and B="& b & "and C=" & c,"A",DataViewRowState.CurrentRows)

Where A,B,C are the column names where second parameter is for sort expression

Nowak answered 15/6, 2015 at 9:49 Comment(0)
L
0

If you really don't want to run into lots of annoying errors (datediff and such can't be evaluated in DataTable.Select among other things and even if you do as suggested use DataTable.AsEnumerable you will have trouble evaluating DateTime fields) do the following:

1) Model Your Data (create a class with DataTable columns)

Example

public class Person
{
public string PersonId { get; set; }
public DateTime DateBorn { get; set; }
}

2) Add this helper class to your code

public static class Extensions
{
/// <summary>
/// Converts datatable to list<T> dynamically
/// </summary>
/// <typeparam name="T">Class name</typeparam>
/// <param name="dataTable">data table to convert</param>
/// <returns>List<T></returns>
public static List<T> ToList<T>(this DataTable dataTable) where T : new()
{
    var dataList = new List<T>();

    //Define what attributes to be read from the class
    const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

    //Read Attribute Names and Types
    var objFieldNames = typeof(T).GetProperties(flags).Cast<PropertyInfo>().
        Select(item => new
        {
            Name = item.Name,
            Type = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType
        }).ToList();

    //Read Datatable column names and types
    var dtlFieldNames = dataTable.Columns.Cast<DataColumn>().
        Select(item => new {
            Name = item.ColumnName,
            Type = item.DataType
        }).ToList();

    foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
    {
        var classObj = new T();

        foreach (var dtField in dtlFieldNames)
        {
            PropertyInfo propertyInfos = classObj.GetType().GetProperty(dtField.Name);

            var field = objFieldNames.Find(x => x.Name == dtField.Name);

            if (field != null)
            {

                if (propertyInfos.PropertyType == typeof(DateTime))
                {
                    propertyInfos.SetValue
                    (classObj, ConvertToDateTime(dataRow[dtField.Name]), null);
                }
                else if (propertyInfos.PropertyType == typeof(int))
                {
                    propertyInfos.SetValue
                    (classObj, ConvertToInt(dataRow[dtField.Name]), null);
                }
                else if (propertyInfos.PropertyType == typeof(long))
                {
                    propertyInfos.SetValue
                    (classObj, ConvertToLong(dataRow[dtField.Name]), null);
                }
                else if (propertyInfos.PropertyType == typeof(decimal))
                {
                    propertyInfos.SetValue
                    (classObj, ConvertToDecimal(dataRow[dtField.Name]), null);
                }
                else if (propertyInfos.PropertyType == typeof(String))
                {
                    if (dataRow[dtField.Name].GetType() == typeof(DateTime))
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToDateString(dataRow[dtField.Name]), null);
                    }
                    else
                    {
                        propertyInfos.SetValue
                        (classObj, ConvertToString(dataRow[dtField.Name]), null);
                    }
                }
            }
        }
        dataList.Add(classObj);
    }
    return dataList;
}

private static string ConvertToDateString(object date)
{
    if (date == null)
        return string.Empty;

    return HelperFunctions.ConvertDate(Convert.ToDateTime(date));
}

private static string ConvertToString(object value)
{
    return Convert.ToString(HelperFunctions.ReturnEmptyIfNull(value));
}

private static int ConvertToInt(object value)
{
    return Convert.ToInt32(HelperFunctions.ReturnZeroIfNull(value));
}

private static long ConvertToLong(object value)
{
    return Convert.ToInt64(HelperFunctions.ReturnZeroIfNull(value));
}

private static decimal ConvertToDecimal(object value)
{
    return Convert.ToDecimal(HelperFunctions.ReturnZeroIfNull(value));
}

private static DateTime ConvertToDateTime(object date)
{
    return Convert.ToDateTime(HelperFunctions.ReturnDateTimeMinIfNull(date));
}

}
public static class HelperFunctions
{

public static object ReturnEmptyIfNull(this object value)
{
    if (value == DBNull.Value)
        return string.Empty;
    if (value == null)
        return string.Empty;
    return value;
}
public static object ReturnZeroIfNull(this object value)
{
    if (value == DBNull.Value)
        return 0;
    if (value == null)
        return 0;
    return value;
}
public static object ReturnDateTimeMinIfNull(this object value)
{
    if (value == DBNull.Value)
        return DateTime.MinValue;
    if (value == null)
        return DateTime.MinValue;
    return value;
}
/// <summary>
/// Convert DateTime to string
/// </summary>
/// <param name="datetTime"></param>
/// <param name="excludeHoursAndMinutes">if true it will execlude time from datetime string. Default is false</param>
/// <returns></returns>
public static string ConvertDate(this DateTime datetTime, bool excludeHoursAndMinutes = false)
{
    if (datetTime != DateTime.MinValue)
    {
        if (excludeHoursAndMinutes)
            return datetTime.ToString("yyyy-MM-dd");
        return datetTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
    }
    return null;
}
}

3) Easily convert your DataTable (dt) to a List of objects with following code:

List<Person> persons = Extensions.ToList<Person>(dt);

4) have fun using Linq without the annoying row.Field<type> bit you have to use when using AsEnumerable

Example

var personsBornOn1980 = persons.Where(x=>x.DateBorn.Year == 1980);
Leffler answered 31/1, 2018 at 16:34 Comment(0)
G
0

Try This One:

class Program
{
    static void Main()
    {
        //  Create Your YourDataTableSample.
        //  And Add New columns and Some rows.
        DataTable YourDataTableSample = new DataTable("SampleDT");
        YourDataTableSample.Columns.Add(new DataColumn("ID", typeof(int)));
        YourDataTableSample.Columns.Add(new DataColumn("MyDate", typeof(DateTime)));
        YourDataTableSample.Rows.Add(100, new DateTime(2021, 1, 1));
        YourDataTableSample.Rows.Add(200, new DateTime(2022, 2, 1));
        YourDataTableSample.Rows.Add(300, new DateTime(2023, 3, 1));
        
        // Select by MyDate.
        DataRow[] TheResult = YourDataTableSample.Select("MyDate > #6/1/2021#");
        
        // Display The Result.
        foreach (DataRow TheRow in TheResult)
        {
            Console.WriteLine(TheRow["ID"]);
        }
    }
}
Guenna answered 15/11, 2021 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.