2010-01-02 21 views
36

Tengo una tabla de datos con 4 columnas A, B, C y D de manera que una combinación particular de valores para la columna A, B y C es única en la tabla de datos.Selección de tabla de datos con múltiples condiciones

Objetivo: Para hallar el valor de la columna D, para una combinación dada de valores para la columna A, B y C.

supongo bucle sobre el conjunto de filas de datos debe hacerlo. ¿Hay alguna manera de usar Datatable.Select() para lograr esto? Para ser más específico, ¿puedo tener varias condiciones en el filtro de selección, es decir, un operador AND lógico que conecta las condiciones para cada una de las columnas A, B y C.

+0

Así columna D es una columna calculada, basado en A, B, y C? –

+0

¿Ha considerado emitir esto como una consulta, y dejar que la base de datos haga lo que está ahí? –

Respuesta

88

Sí, el método DataTable.Select soporta operadores booleanos de la misma manera que utilizaría en un comunicado "real" SQL:

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

Ver DataColumn.Expression in MSDN para la sintaxis soportada por el método de DataTable Select.

31

¿Debe utilizar DataTable.Select()? Prefiero escribir una consulta de linq para este tipo de cosas.

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 para linq sobre el estilo fibroso Seleccione la expresión de filtro –

6

He encontrado que el tener demasiadas y volvería de resultados incorrectos (para .NET 1.1 de todos modos)

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

En mi caso A fue el campo 12 en una tabla y seleccione la estaba ignorando efectivamente.

Sin embargo si lo hiciera

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

El filtro funcionaba correctamente!

+0

Eso tiene que ser algún tipo de error. No hay diferencia lógica entre tus dos ejemplos. – 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

Prueba de esto,
pienso, esta es una de las soluciones simples.

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

Asegúrese, combinación de valores para la columna A, B y C es único en la tabla de datos.

+0

Su solución 'int rowIndex = ... [0]' solo puede devolver la primera fila coincidente, aunque la solicitud sea para devolver un valor "único", puede haber varios valores que luego se ignoran. ¿Por qué no? Int [] rowIndex = ... 'y devuelve cualquier resultado. El enfoque es que si la llamada combinación única no es única y hay una falla de datos, entonces puede remediarse. – LokizFenrir

1
Dim dr As DataRow() 


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

Donde A, B, C son los nombres de las columnas donde segundo parámetro es para expresión de ordenación

0

Si realmente no quiere encontrarse con un montón de errores molestos (datediff y así no puede ser evaluada en DataTable.Select entre otras cosas, e incluso si lo hace como el uso sugerido DataTable.AsEnumerable tendrá problemas para evaluar campos DateTime) haga lo siguiente:

1) modelo de datos (crear una clase con columnas DataTable)

Ejemplo

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

2) Añadir esta clase de ayuda a su código

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) convertir fácilmente su DataTable (dt) a una lista de objetos con código siguiente:

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

4) el uso de LINQ divertirse sin el molesto row.Field<type> poco tiene que usar cuando se utiliza AsEnumerable

Ejemplo

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