2012-03-26 7 views
11

Tengo la siguiente declaración SQL que funciona como deseada/esperada. Sin embargo, me gustaría traducirlo a una declaración LINQ (¿Lambda?) Para que encaje con el resto de mi DAL. Sin embargo, no puedo ver cómo se simula Rank() en LINQ.Conversión de SQL Rank() a LINQ, o alternativa

La razón por la que lo publiqué aquí, que tal vez sea un error, es para ver si alguien tiene una alternativa a la declaración Rank() para que pueda cambiarla. Alternativamente, si hay una manera de representar Rank() en LINQ que también se apreciaría.

USE CMO 

SELECT  vp.[PersonID] AS [PersonId] 
      ,ce.[EnrollmentID] 
      ,vp.[FirstName] 
      ,vp.[LastName] 
      ,ce.[EnrollmentDate] 
      ,ce.[DisenrollmentDate] 
      ,wh.WorkerCategory 

FROM [dbo].[vwPersonInfo] AS vp 
      INNER JOIN 
      (
        [dbo].[tblCMOEnrollment] AS ce 
        LEFT OUTER JOIN 
         (
           SELECT * 
              ,RANK()OVER(PARTITION BY EnrollmentID ORDER BY CASE WHEN EndDate IS NULL THEN 1 ELSE 2 END, EndDate DESC, StartDate DESC) AS whrank 
           FROM [dbo].[tblWorkerHistory] 
           WHERE WorkerCategory = 2 
         ) AS wh 
           ON ce.[EnrollmentID] = wh.[EnrollmentID] AND wh.whrank = 1 
      ) 
        ON vp.[PersonID] = ce.[ClientID] 

WHERE (vp.LastName NOT IN ('Client','Orientation','Real','Training','Matrix','Second','Not')) 
AND (
      (wh.[EndDate] <= GETDATE()) 
      OR wh.WorkerCategory IS NULL 
    ) 
AND (
      (ce.[DisenrollmentDate] IS NULL) 
      OR (ce.[DisenrollmentDate] >= GetDate()) 
    ) 
+0

@closer: demasiado localizada? –

+0

Estaba pensando que tal vez debería volver a trabajar para simplemente preguntar cómo restar importancia al Sub-Seleccionar con Rango(). ¿Eso haría una mejor pregunta? –

+0

Puede usar una vista con la cláusula de rango, a la espera de que alguien más sepa si es posible con Linq sin formato. –

Respuesta

10

Aquí hay un ejemplo que muestra cómo iba a simular Rango() en LINQ:

var q = from s in class.student 
       orderby s.Age descending 
       select new { 
        Name = s.name, 
        Rank = (from o in class.student 
          where o.mark > s.mark 
          select o).Count() + 1 
       }; 
+1

Para mí, esto se siente como E = mc^2 ..una solución increíblemente simple para un problema relativamente complejo – Ody

+2

En lo que respecta a mis pruebas, parece que estoy creando una consulta por cada resultado en la consulta externa. Esto se vuelve problemático incluso para unos pocos miles de resultados, por lo que este método parece limitado. –

+1

¡Me gusta su forma de pensar para esta solución! Nunca pensé mirarlo de esa manera. ¡Bien hecho! Terminé usando la aplicación Lamda pero basado en el mismo concepto: var = rankedData data.Select (s => nuevos { \t \t \t \t \t \t de Ranking = data.Count (x => s> x.Value .value) 1, \t \t \t \t \t \t Name = s.Key, \t \t \t \t \t \t Puntuación = s.Value}); –

2

Si desea simular rango, puede utilizar siguiente consulta LINQ.

 var q = (from s in class.student 
       select new 
       { 
        Name = s.Name, 
        Rank = (from o in class.student 
          where o.Mark > s.Mark && o.studentId == s.studentId 
          select o.Mark).Distinct().Count() + 1 
       }).ToList(); 

puede utilizar orden como:

 var q = (from s in class.student 
       orderby s.studentId 
       select new 
       { 
        Name = s.Name, 
        Rank = (from o in class.student 
          where o.Mark > s.Mark && o.studentId == s.studentId 
          select o.Mark).Distinct().Count() + 1 
       }).ToList(); 

pero por fin no importa en esta consulta.

+0

@Refracted Paladin si su problema se resuelve, marque como respuesta. –

+0

¿Por qué '.Distinct()'? La definición de la función 'RANK()' requerirá que omita eso. Su respuesta coincide con la salida de 'DENSE_RANK()' –

7

LINQ tiene funcionalidad de rango integrada, pero no en la sintaxis de la consulta. Cuando se usa la sintaxis del método, la mayoría de las funciones de linq vienen en dos versiones: la normal y la siguiente con un rango provisto.

Un ejemplo sencillo de seleccionar solamente cada otro estudiante y luego añadiendo el índice en la secuencia resultante al resultado:

var q = class.student.OrderBy(s => s.studentId).Where((s, i) => i % 2 == 0) 
.Select((s,i) => new 
{ 
    Name = s.Name, 
    Rank = i 
} 
+3

¿No es estrictamente para listas materializadas, o realmente genera SQL que corresponde a la clasificación? –

+2

Cuando trato de usar esto, sigo recibiendo el mensaje "LINQ no reconoce el método ..." hasta que elimine la cláusula where. No parece que le gusten los 2 parámetros entre paréntesis. – Bpainter

+0

¡Esta debería ser la respuesta aceptada, la aceptada es de terrible rendimiento! –

0

Basado en respuesta de @Totero pero con una aplicación lambda. Puntaje más alto = rango más alto.

var rankedData = data.Select(s => new{ 
        Ranking = data.Count(x => x.Value > s.Value)+1, 
        Name = s.Key, 
        Score = s.Value}); 

Para esta entrada:

{ 100, 100, 98, 97, 97, 97, 91, 50 } 

Usted recibirá esta salida:

  • Puntuación: Rango
  • 100: 1
  • 100: 1
  • 98: 3
  • 97: 4
  • 97: 4
  • 97: 4
  • 91: 6
  • 50: 7