Как выбрать каждую n-ю строку из mysql

79

У меня есть ряд значений в базе данных, которые мне нужно извлечь, чтобы создать линейную диаграмму. Поскольку мне не требуется высокое разрешение, я хотел бы пересчитать данные, выбирая каждую 5-ю строку из базы данных.

Корбан Брук
источник

Ответы:

84
SELECT * 
FROM ( 
    SELECT 
        @row := @row +1 AS rownum, [column name] 
    FROM ( 
        SELECT @row :=0) r, [table name] 
    ) ranked 
WHERE rownum % [n] = 1 
Тейлор Лиз
источник
5
Может ли кто-нибудь предоставить дополнительную информацию о том, как это работает? Например, вопрос задается для каждой 5-й строки, и в ответе нет упоминания 5.
Crazometer
4
@Crazometer замените [n]в запросе 5, чтобы получить каждую 5-ю строку.
Бенджамин Маннс
Что, если вы хотите начать не с первой строки, а, например, со второй?
HPWD
@HPWD вы бы заменить @row :=0с@row :=2
Бинар Web
@BinarWeb нет, вы бы изменить = 1к= 2
ysth
55

Вы можете попробовать мод 5, чтобы получить строки, в которых идентификатор кратен 5. (Предполагая, что у вас есть какой-то столбец идентификатора, который является последовательным.)

select * from table where table.id mod 5 = 0;
Оуэн
источник
19
Также при условии, что у вас нет пробелов в последовательности из-за удаления или отката.
Билл Карвин,
3
Это будет работать по большей части, но не учитывает удаленные строки.
Корбан Брук,
2
Просто и блестяще для некоторых тестов :-)
Рикард Лильеберг
1
Это имеет смысл, если ваш выбор извлекает все данные. Если у вас есть дополнительные критерии в вашем выборе, будет трудно сказать, какие данные (если таковые имеются) он будет извлекать.
j_kubik
24

Поскольку вы сказали, что используете MySQL, вы можете использовать пользовательские переменные для создания непрерывной нумерации строк. Однако вы должны поместить это в производную таблицу (подзапрос).

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

Я добавил, ORDER BY RAND()чтобы получить псевдослучайную выборку, вместо того, чтобы позволять каждой пятой строке неупорядоченной таблицы быть в выборке каждый раз.


Анонимный пользователь попытался изменить это, чтобы изменить x MOD 5 = 0на x MOD 5 = 1. Я вернул его обратно к своему оригиналу.

Для записи в этом состоянии можно использовать любое значение от 0 до 4, и нет причин предпочитать одно значение другому.

Билл Карвин
источник
Я обновлял свой ответ на этот вопрос, и вы меня опередили! Хорошая мысль.
Джош Стодола
1
к сожалению, это замедляет выполнение как минимум в 100 раз при работе со многими записями
phil294 04
10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;
Андрей Кон
источник
Это отлично подходит для разделения произвольной таблицы, доступной только для чтения, для параллельной обработки строк, а синтаксис очень прост для чтения и понимания. Вам просто нужно добавить ORDER BY в столбец первичного ключа, чтобы каждая строка возвращалась только один раз.
humbads
2

Я искал что-то подобное. Ответ Тейлора и Билла побудил меня улучшить их идеи.

table data1 имеет поля read_date, значение, которое мы хотим выбрать каждую 2d запись из запроса, ограниченного диапазоном read_date, имя производной таблицы произвольно и здесь называется DT

запрос:

 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
Марк Ричардс
источник
Спасибо, я это искал. Мне нужно было как-то проверять, имеет ли определенный столбец в таблице журнала для хранимых процедур одно и то же значение каждый второй раз. Например, «начало процесса», «окончание процесса». Приведенный ниже sql приведет к 1, если все в порядке. 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

Вы можете использовать этот запрос,

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;

или вы можете заменить n своим n-м значением

Мохидин бин Мохаммед
источник
1
SELECT *
FROM ( 
    SELECT @row := @row +1 AS rownum, posts.*
    FROM (
        SELECT @row :=0) r, posts
    ) ranked
WHERE rownum %3 = 1

где посты - моя таблица.

Гор
источник
1

Если вы используете MariaDB 10.2, MySQL 8 или новее, вы можете сделать это более эффективно, и я думаю более ясно, используя общие табличные выражения и оконные функции .

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;

По сути, это создает временную таблицу с содержимым exampleтаблицы, упорядоченным по nameполю, добавляет дополнительное поле, называемое nномером строки, а затем выбирает только те строки с номерами, которые точно делятся на 5, то есть каждую 5-ю строку. На практике движок базы данных часто может оптимизировать это лучше, чем это. Но даже если он не оптимизирует его дальше, я думаю, это понятнее, чем итеративное использование пользовательских переменных, как это было в более ранних версиях MySQL.

Ричард Смит
источник
0

Если вам не требуется номер строки в наборе результатов, вы можете упростить запрос.

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

Замените следующие заполнители:

  1. Замените [column name]списком столбцов, которые вам нужно получить.
  2. Замените [table name]именем своей таблицы.
  3. Замените [n]цифрой. например, если вам нужна каждая 5-я строка, замените ее на 5
Дхарман
источник
Спасибо, это близко, но вам лучше сделать это: выберите имя из (SELECT @row: = - 1) temp, t where (@row: = @ row + 1)% 1 = 0; У этого есть два преимущества. Во-первых, независимо от n, вы всегда получаете первую строку и вторую, если вы сделаете n = 1, вы получите все значения, а не ни одного. (Два изменения: -1 в строке: = - 1 и n = 0 вместо n = 1)
Брюс