2010-12-15 6 views
8

Tengo la siguiente consulta sql para encontrar el segundo salario máximo.Encontrar el segundo salario máximo usando linq

 

Select * From Employee E1 Where 
    (2) = (Select Count(Distinct(E2.Salary)) From Employee E2 Where 
     E2.Salary > E1.Salary) 

Quiero convertirlo en instrucción Linq.

+0

Usted quiere encontrar el empleado que tiene el segundo más alto salario? –

+0

@Ian: Sí, quiero encontrar el segundo salario más alto utilizando Linq –

Respuesta

18

Creo que lo que está preguntando es encontrar al empleado con el segundo salario más alto?

Si es así, eso sería algo así como

var employee = Employees 
    .OrderByDescending(e => e.Salary) 
    .Skip(1) 
    .First(); 

Si varios empleados pueden tener el mismo salario y desea devolver un IEnumerable de todos los empleados con el segundo salario más alto que podía hacer:

var employees = Employees 
    .GroupBy(e => e.Salary) 
    .OrderByDescending(g => g.Key) 
    .Skip(1) 
    .First(); 

(felicitaciones a @ diceguyd30 por sugerir esta última mejora)

+0

@Ian: Gracias por la respuesta. Tengo una pregunta más. Quiero generar la misma declaración sql (como publiqué en la pregunta) de Linq.Es ¿es posible? ¿Si es así, entonces cómo? –

+2

Diría que el SQL generado es una prerrogativa del proveedor de LINQ subyacente y, en general, no debería ser motivo de preocupación. Debería ser posible escribir consultas LINQ sin tener en cuenta qué SQL se generará (o si SQL se generará en absoluto). –

+0

Muchas gracias por la aclaración. –

2

Se puede definir la clase igualmente comparador como bramido:

public class EqualityComparer : IEqualityComparer<Employee > 
    { 
     #region IEqualityComparer<Employee> Members 
     bool IEqualityComparer<Employee>.Equals(Employee x, Employee y) 
     { 
      // Check whether the compared objects reference the same data. 
      if (Object.ReferenceEquals(x, y)) 
       return true; 

      // Check whether any of the compared objects is null. 
      if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) 
       return false; 

      return x.Salary == y.Salary; 
     } 

     int IEqualityComparer<Employee>.GetHashCode(Employee obj) 
     { 
      return obj.Salary.GetHashCode(); 
     } 
     #endregion 
    } 

y utilizarlo como abajo:

var outval = lst.OrderByDescending(p => p.Id) 
        .Distinct(new EqualityComparer()).Skip(1).First(); 

o hacerlo sin igualmente comparador (en dos líneas):

 var lst2 = lst.OrderByDescending(p => p.Id).Skip(1); 
     var result = lst2.SkipWhile(p => p.Salary == lst2.First().Salary).First(); 

Editar: Como Ani dijo a trabajar con sql debería hacer: var lst = myDataContext.Employees.AsEnumerable();, pero si es para software comercial, es mejor usar TSQL o encontrar otra forma de linq.

+1

+1 Una buena idea, pero no funcionará con LINQ to SQL.Tendrás que devolver todo al cliente y usar LINQ to Objects. No estoy seguro si el OP puede permitirse hacer esto. – Ani

+0

@Saeed: recibo este error "El operador de consulta 'SkipWhile' no es compatible.". Estoy usando C# 4.0 –

+0

@santosh, use el primero, comparador de igualdad. –

0

Usando LINQ, se encuentra el tercero más alto salario como esto:

// first use LINQ to sort by salary, then skip first 2 and get next 
var thirdHighestSalary= (from n in db.Employee order by n.salary descending select n).distinct().skip(2). FirstOrDefault() 
// write the result to console 
Console.WriteLine(Third Highest Salary is : {0},thirdHighestSalary.Salary); 
+0

Hola @MIltanMiltan! Cualquier posibilidad de que pueda editar su respuesta para formatearla con bloques de código, y explicar por qué su código resuelve el problema para que la persona que pregunta sepa cómo solucionarlo en el futuro (en lugar de simplemente entregar el código sin una explicación de por qué trabajos)? Gracias, y bienvenidos a SO! –

Cuestiones relacionadas