2010-11-17 45 views
15

¿Alguien sabe cómo escribir una instrucción LINQ to SQL para devolver cada enésima fila de una tabla? Necesito obtener el título del artículo en la parte superior de cada página en una cuadrícula de datos paginada para un rápido escaneo del usuario. Así que si quería el primer registro, y luego cada 3 que después de eso, a partir de los siguientes nombres:LINQ to SQL cada enésima fila de la tabla

Amy, Eric, Jason, Joe, John, Josh, Maribel, Paul, Steve, Tom

Me gustaría tener a Amy, Joe, Maribel y Tom.

Sospecho que esto se puede hacer ... Las declaraciones LINQ a SQL ya invocan la función SQL ROW_NUMBER() junto con la ordenación y la paginación. Simplemente no sé cómo recuperar cada enésimo artículo. La instrucción SQL sería algo así como WHERE ROW_NUMBER MOD 3 = 0, pero no sé la instrucción LINQ que se utilizará para obtener el SQL correcto.

+0

No sé si esto se podría hacer con LINQ a SQL generada SQL – hunter

+0

Realmente (No, en serio) no parece ser una forma de llegar a la solución básica de la respuesta aceptada utilizando LINQ puro a SQL. He usado un par de alternativas. 1) Cree una vista que materialice la tabla original más el número de fila usando la ordenación deseada, luego use LINQ to SQL para consultar esa vista donde el número de fila es mod cero para n en "tomar cada n filas". 2) Use la respuesta aceptada y ExecuteQuery. Prefiero la primera solución si sé que la clasificación previa a la modificación siempre debe ser la misma. –

Respuesta

8

A veces, TSQL es el camino a seguir. Me gustaría utilizar ExecuteQuery<T> aquí:

var data = db.ExecuteQuery<SomeObjectType>(@" 
SELECT * FROM 
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS [__row] 
FROM [YourTable]) x WHERE (x.__row % 25) = 1"); 

También puede intercambiar el n:

var data = db.ExecuteQuery<SomeObjectType>(@" 
DECLARE @n int = 2 
SELECT * FROM 
(SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS [__row] 
FROM [YourTable]) x WHERE (x.__row % @n) = 1", n); 
1

No parece realmente ser una manera fácil de hacer esto:

How do I add ROW_NUMBER to a LINQ query or Entity?

How to find the ROW_NUMBER() of a row with Linq to SQL

Pero siempre hay:

peopleToFilter.AsEnumerable().Where((x,i) => i % AmountToSkipBy == 0) 

NOTA: Esto todavía ¡no se ejecuta en el lado de la base de datos!

+0

Lamentablemente, la sobrecarga de 'Dónde' no es compatible con LINQ-to-SQL – Stephan

+0

Ahhh ... Lamentablemente tiene razón ... – diceguyd30

+0

Cambié mi respuesta a algo útil (léase: realmente funciona) – diceguyd30

1

Simplemente buscando en Google un poco No he encontrado (o experimentado) una opción para Linq a SQL para soportar esto directamente.

La única opción que puedo ofrecer es que escriba un procedimiento almacenado con la consulta SQL adecuada escrita y luego llame al sproc a través de Linq a SQL. No es la mejor solución, especialmente si tiene algún tipo de filtrado complejo en marcha.

+0

esto no responde – hunter

+0

A veces, como parece en este caso, la única respuesta es que no hay respuesta. Sin una forma directa de usuario 'ROW_NUMBER()' de SQL, este tipo de selección es probablemente imposible. – Stephan

+0

Creo que hay una manera como lo que escribí, solo debería pensar de otra manera. –

1

esto va a hacer el truco, pero no es la consulta más eficiente del mundo:

var count = query.Count(); 
var pageSize = 10; 
var pageTops = query.Take(1); 
for(int i = pageSize; i < count; i += pageSize) 
{ 
    pageTops = pageTops.Concat(query.Skip(i - (i % pageSize)).Take(1)); 
} 
return pageTops; 

Se construye dinámicamente una consulta para tirar de la (enésima, 2 * n, 3 * n, etc.) valor de la consulta dada. Si usa esta técnica, probablemente desee crear un límite de tal vez diez o veinte nombres, similar a la página de resultados de Google (1-10, y Siguiente), para evitar obtener una expresión tan grande que la base de datos se niegue a intentar analizarlo

Si necesita un mejor rendimiento, probablemente tendrá que usar un procedimiento almacenado o una vista para representar su consulta e incluir el número de fila como parte de los resultados del proceso almacenado o los campos de la vista.

3

Aquí es una opción que funciona, pero podría valer la pena comprobar que no tiene ningún problema de rendimiento en la práctica:

var nth = 3; 
var ids = Table 
      .Select(x => x.Id) 
      .ToArray() 
      .Where((x, n) => n % nth == 0) 
      .ToArray(); 

var nthRecords = Table 
        .Where(x => ids.Contains(x.Id)); 
+2

Esto tendrá problemas cuando la tabla exceda las 7000 filas, ya que se alcanzará el límite de parámetros del servidor SQL. –

4

Había una vez, no había tal cosa como ROW_NUMBER, y sin embargo, tales consultas fueron posibles. ¡Mirad!

var query = 
    from c in db.Customers 
    let i = (
    from c2 in db.Customers 
    where c2.ID < c.ID 
    select c2).Count() 
    where i%3 == 0 
    select c; 

Esto genera el código SQL siguiente

SELECT [t2].[ID], [t2]. --(more fields) 
FROM (
    SELECT [t0].[ID], [t0]. --(more fields) 
(
     SELECT COUNT(*) 
     FROM [dbo].[Customer] AS [t1] 
     WHERE [t1].[ID] < [t0].[ID] 
     ) AS [value] 
    FROM [dbo].[Customer] AS [t0] 
    ) AS [t2] 
WHERE ([t2].[value] % @p0) = @p1 
+0

su código no se pudo compilar, ¿qué es? –

+0

El código compila bien en C#. –

+0

Puede ser su compilador diferente para nosotros como su ... –