Jak wybrać każdy n-ty wiersz z mysql

79

Mam szereg wartości w bazie danych, które muszę pobrać, aby utworzyć wykres liniowy. Ponieważ nie wymagam wysokiej rozdzielczości, chciałbym ponownie próbkować dane, wybierając co piąty wiersz z bazy danych.

Corban Brook
źródło

Odpowiedzi:

84
SELECT * 
FROM ( 
    SELECT 
        @row := @row +1 AS rownum, [column name] 
    FROM ( 
        SELECT @row :=0) r, [table name] 
    ) ranked 
WHERE rownum % [n] = 1 
Taylor Leese
źródło
5
Czy ktoś może podać więcej informacji o tym, jak to działa? Na przykład pytanie zadane w co piątym wierszu i brak wzmianki o 5 w odpowiedzi.
Crazometer
4
@Crazometer zamień [n]w zapytaniu na 5, aby uzyskać co piąty wiersz.
Benjamin Manns
Aby to rozwinąć, co by było, gdybyś nie chciał zaczynać od pierwszego rzędu, ale na przykład od drugiego?
HPWD
@HPWD chcesz wymienić @row :=0z@row :=2
binär sieci
@BinarWeb nie, należy zmienić = 1na= 2
ysth
55

Możesz wypróbować mod 5, aby uzyskać wiersze, w których identyfikator jest wielokrotnością 5. (Zakładając, że masz jakąś kolumnę identyfikatora, która jest sekwencyjna).

select * from table where table.id mod 5 = 0;
piekarnik
źródło
19
Zakładając również, że nie masz przerw w sekwencji, spowodowanych usunięciem lub wycofaniem.
Bill Karwin
3
To działałoby w większości przypadków, ale nie uwzględnia usuniętych wierszy.
Corban Brook
2
Proste i genialne do testów :-)
Rickard Liljeberg
1
Ma to sens, jeśli Twój wybór pobiera wszystkie dane. Jeśli masz dodatkowe kryteria w swoim wyborze, trudno byłoby powiedzieć, jakie dane (jeśli w ogóle) zostaną odzyskane.
j_kubik
24

Ponieważ powiedziałeś, że używasz MySQL, możesz użyć zmiennych użytkownika, aby utworzyć ciągłą numerację wierszy. Musisz jednak umieścić to w tabeli pochodnej (podzapytaniu).

SET @x := 0;
SELECT *
FROM (SELECT (@x:=@x+1) AS x, mt.* FROM mytable mt ORDER BY RAND()) t
WHERE x MOD 5 = 0;

Dodałem, ORDER BY RAND()aby uzyskać próbkowanie pseudolosowe, zamiast pozwalać co piąty wiersz nieuporządkowanej tabeli na próbkę za każdym razem.


Anonimowy użytkownik próbował to edytować, aby zmienić x MOD 5 = 0na x MOD 5 = 1. Zmieniłem go z powrotem na mój oryginał.

Dla przypomnienia, w tym stanie można użyć dowolnej wartości z zakresu od 0 do 4 i nie ma powodu, aby preferować jedną wartość nad inną.

Bill Karwin
źródło
Aktualizowałem swoją odpowiedź na to, a ty mnie pokonałeś! Dobre myślenie.
Josh Stodola
1
niestety spowalnia to wykonanie co najmniej x100 przy pracy z wieloma wpisami
phil294
10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;
Andrey Kon
źródło
Działa to świetnie w przypadku partycjonowania dowolnej tabeli tylko do odczytu w celu równoległego przetwarzania wierszy, a składnia jest bardzo łatwa do odczytania i zrozumienia. Wystarczy dodać ORDER BY w kolumnie klucza podstawowego, aby każdy wiersz był zwracany tylko raz.
humbads
2

Szukałem czegoś takiego. Odpowiedź Taylora i Billa skłoniła mnie do udoskonalenia ich pomysłów.

tabela data1 ma pola read_date, wartość, którą chcemy wybrać co 2d rekord z zapytania ograniczoną zakresem read_date nazwa tabeli pochodnej jest dowolna i tutaj nazywa się DT

pytanie:

 SET @row := 0;
  SELECT * FROM  ( SELECT @row := @row +1 AS rownum, read_date, value  FROM data1  
  WHERE  read_date>= 1279771200 AND read_date <= 1281844740 ) as DT WHERE MOD(rownum,2)=0
Mark Richards
źródło
Dzięki, szukałem tego. Musiałem jakoś sprawdzić, czy określona kolumna w tabeli dziennika dla procedur składowanych ma tę samą wartość za każdym razem. Na przykład „początek proc”, „koniec proc”. Poniższy sql da 1, jeśli wszystko jest w porządku. SET @row := 0; SELECT count(distinct Message) FROM ( SELECT @row := @row +1 AS rownum, Message FROM operations.EventLog WHERE LogTime > now() - interval 6 hour and ProcedureName = 'Do_CDR' ) as DT WHERE MOD(rownum,2)=0;
eigil
1

Możesz użyć tego zapytania,

set @n=2; <!-- nth row -->
select * from (SELECT t.*, 
       @rowid := @rowid + 1 AS ID
  FROM TABLE t, 
       (SELECT @rowid := 0) dummy) A where A.ID mod @n = 0;

lub możesz zastąpić n swoją n-tą wartością

Mohideen bin Mohammed
źródło
1
SELECT *
FROM ( 
    SELECT @row := @row +1 AS rownum, posts.*
    FROM (
        SELECT @row :=0) r, posts
    ) ranked
WHERE rownum %3 = 1

gdzie posty to mój stół.

Gor
źródło
1

Jeśli używasz MariaDB 10.2, MySQL 8 lub nowszego, możesz to zrobić bardziej wydajnie i myślę jaśniej, używając typowych wyrażeń tabelowych i funkcji okien .

WITH ordering AS (
  SELECT ROW_NUMBER() OVER (ORDER BY name) AS n, example.* 
    FROM example ORDER BY name
)
SELECT * FROM ordering WHERE MOD(n, 5) = 0;

Koncepcyjnie tworzy to tymczasową tabelę z zawartością exampletabeli uporządkowaną według namepola, dodaje dodatkowe pole o nazwie, nktóra jest numerem wiersza, a następnie pobiera tylko te wiersze o liczbach, które są dokładnie podzielne przez 5, czyli co 5 wiersz. W praktyce silnik bazy danych często jest w stanie lepiej to zoptymalizować. Ale nawet jeśli nie optymalizuje go dalej, myślę, że jest to bardziej przejrzyste niż iteracyjne używanie zmiennych użytkownika, tak jak to miało miejsce we wcześniejszych wersjach MySQL.

Richarda Smitha
źródło
0

Jeśli nie potrzebujesz numeru wiersza w zestawie wyników, możesz uprościć zapytanie.

SELECT 
    [column name] 
FROM
    (SELECT @row:=0) temp, 
    [table name] 
WHERE (@row:=@row + 1) % [n] = 1 

Zastąp następujące symbole zastępcze:

  1. Zastąpić [column name] listą kolumn, które chcesz pobrać.
  2. Zastąp [table name]nazwą swojego stołu.
  3. Zastąp [n]liczbą. np. jeśli potrzebujesz co piąty wiersz, zamień go na 5
Dharman
źródło
Dzięki, już blisko, ale lepiej to zrobić: wybierz nazwę z (SELECT @row: = - 1) temp, t gdzie (@row: = @ row + 1)% 1 = 0; Ma to dwie zalety. Po pierwsze, niezależnie od n, zawsze otrzymujesz pierwszy wiersz, a drugi, jeśli zrobisz n = 1, otrzymasz wszystkie wartości, a nie żadną. (Dwie zmiany: -1 w rzędzie: = - 1 i n = 0 zamiast n = 1)
Bruce