2010-01-02 4 views
36

У меня есть datatable с 4 столбцами A, B, C и D, так что конкретная комбинация значений для столбцов A, B и C уникальна в datatable.Datatable select with multiple conditions

Цель: Для того, чтобы найти значение столбца D, для заданной комбинации значений для столбца A, B и C.

Я думаю сквозные по множеству строк данных следует сделать это. Есть ли способ использовать Datatable.Select() для этого? Чтобы быть более конкретным - могу ли я иметь несколько условий в выбранном фильтре, то есть условия подключения логического И для каждого из столбцов A, B и C.

+0

Так Колонка D представляет собой вычисляемый столбец, основанный на A, B, и C? –

+0

вы считали, что выбрали это как запрос и позволили базе данных сделать то, для чего оно есть? –

ответ

88

Да, метод DataTable.Select поддерживает логические операторы таким же образом, что вы могли бы использовать их в «реальном» SQL заявление:

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

См DataColumn.Expression in MSDN для синтаксиса, поддерживаемого Select метода DataTable в.

31

Нужно ли использовать DataTable.Select()? Я предпочитаю писать запрос linq для такого рода вещей.

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"); 
+0

+1 для linq над строгим стилем Выберите выражение фильтра –

6

я обнаружили, что слишком много и был бы возвращать неверные результаты (для .NET 1.1 в любом случае)

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

В моем случае было 12 поле в таблице и выберите эффективно игнорировать ее.

Однако если бы я сделал

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

фильтр работал правильно!

+0

Это должно быть некоторая ошибка. Между вашими двумя примерами логической разницы нет. – Christian

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

Попробуйте это
Я думаю, это один из самых простых решений.

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

Удостоверьтесь, что комбинация значений для столбцов A, B и C уникальна в datatable.

+0

Ваше решение 'int rowIndex = ... [0]' может возвращать только первую строку, даже если запрос должен возвращать «уникальное» значение, могут быть несколько значений, которые затем просто игнорируются. Почему бы не 'int [] rowIndex = ...' и не возвращать никакого результата. Основное внимание в том, что, если так называемая уникальная комбинация не уникальна и существует ошибка данных, ее можно исправить. – LokizFenrir

1
Dim dr As DataRow() 


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

Где A, B, C являются имена столбцов где второй параметр является для выражения рода

0

Если вы действительно не хотите, чтобы запустить на множество досадных ошибок (DATEDIFF и такого не может оценивается в DataTable.Select среди других вещей, и даже если вы делаете, как было предложено использование DataTable.AsEnumerable вы будете иметь проблемы с оценкой DateTime полей) сделайте следующее:

1) Модель данных (создать класс с DataTable столбцов)

Пример

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

2) Добавить вспомогательный класс в код

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) Легко конвертировать DataTable (DT) в Список объектов с помощью следующего кода:

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

4) получайте удовольствие, используя Linq без раздражающего row.Field<type> бит, который вы должны использовать при использовании AsEnumerable

Пример

var personsBornOn1980 = persons.Where(x=>x.DateBorn.Year == 1980);