2010-11-17 12 views
15

Ktoś wie, jak napisać LINQ do instrukcji SQL, aby zwrócić każdy n-ty wiersz z tabeli? Potrzebuję uzyskać tytuł przedmiotu na górze każdej strony w siatce stronicowanej z powrotem do szybkiego skanowania użytkownika. Więc gdybym chciał pierwszy rekord, a następnie co 3 jeden po tym, z następującymi nazwami:LINQ do SQL Każdy N wiersz z tabeli

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

Dostałbym Amy, Joe, Maribel i Tom.

Podejrzewam, że można to zrobić ... LINQ do instrukcji SQL już wywołują funkcję SQL ROW_NUMBER() w połączeniu z sortowaniem i stronicowaniem. Po prostu nie wiem, jak odzyskać każdy n-ty przedmiot. Oświadczenie SQL byłoby czymś w rodzaju WHERE ROW_NUMBER MOD 3 = 0, ale nie znam instrukcji LINQ do użycia w celu uzyskania odpowiedniego kodu SQL.

+0

ja nie wiem, czy można to zrobić z wygenerowanym LINQ to SQL sql – hunter

+0

tam naprawdę (Nie, naprawdę) nie wydaje się być sposobem na znalezienie rozwiązania podstawowego przyjętej odpowiedzi przy użyciu czystego LINQ do SQL. Użyłem kilku alternatyw. 1) Utwórz widok, który zmaterializuje oryginalną tabelę plus numer wiersza za pomocą żądanego sortowania, a następnie użyj LINQ do SQL, aby wysłać zapytanie do tego widoku, gdzie numer wiersza to mod zero dla n w "weź co n wierszy". 2) Użyj zaakceptowanej odpowiedzi i ExecuteQuery. Preferuję pierwsze rozwiązanie, jeśli wiem, że sortowanie wstępne powinno zawsze być takie samo. –

Odpowiedz

8

Czasami TSQL jest do zrobienia. użyłbym ExecuteQuery<T> tutaj:

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

Można też zamienić się z 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

Tam naprawdę nie wydaje się być łatwym sposobem, aby to zrobić:

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

Ale zawsze:

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

UWAGA: nadal nie wykonuje się po stronie bazy danych!

+0

Niestety, przeciążenie 'Where' nie jest obsługiwane w LINQ-SQL SQL – Stephan

+0

Ahhh ... Niestety masz rację ... – diceguyd30

+0

Zmieniono moją odpowiedź na coś użytecznego (czytaj: faktycznie działa) – diceguyd30

1

Po prostu trochę googling Nie znalazłem (ani nie doświadczyłem) opcji Linq do SQL, aby bezpośrednio wesprzeć to.

Jedyną opcją, którą mogę zaoferować, to napisanie procedury składowanej z odpowiednim zapytaniem SQL wypisanym, a następnie wywołanie sproc przez Linq do SQL. Nie jest to najlepsze rozwiązanie, zwłaszcza jeśli masz do czynienia ze skomplikowanym filtrowaniem.

+0

to nie jest odpowiedź – hunter

+0

Czasami, jak się wydaje w tym przypadku, jedyną odpowiedzią jest to, że nie ma odpowiedzi. Bez sposobu bezpośredniego użytkownika 'ROW_NUMBER()' z SQL ten typ selekcji jest prawdopodobnie niemożliwy. – Stephan

+0

Myślę, że istnieje sposób, jak to, co napisałem, po prostu powinien myśleć o tym w inny sposób. –

1

to załatwi, ale to nie jest najbardziej efektywny zapytania w świecie:

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; 

Dynamicznie tworzy zapytanie do ciągnięcia (n-ty, 2 * n-ty, 3 * n-ty, etc) wartość z danego zapytania. Jeśli użyjesz tej techniki, prawdopodobnie zechcesz utworzyć limit około dziesięciu do dwudziestu nazw podobnych do strony wyników Google (1-10 i Next), aby uniknąć wyrażenia tak dużego, że baza danych odmawia spróbuj go przeanalizować.

Jeśli potrzebujesz lepszej wydajności, prawdopodobnie będziesz musiał użyć procedury składowanej lub widoku do reprezentowania zapytania, a także podać numer wiersza jako część zapisanych wyników proc lub pól widoku.

3

Oto opcja, że ​​działa, ale może warto sprawdzić, że nie ma żadnych problemów z wydajnością w praktyce:

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

Będzie to miało problemy, gdy tabela przekroczy 7000 wierszy, ponieważ zostanie osiągnięty limit parametrów serwera sql. –

4

Dawno, dawno temu, nie było czegoś takiego jak row_number, a jednak takie zapytania były możliwe. Ujrzeć!

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; 

ta generuje następujące SQL

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

Twój kod nie mógł zostać skompilowany, co ja mam? –

+0

Kod kompiluje dobrze wC#. –

+0

Może być Twój kompilator różni się od nas jak twój ... –