Як вибрати кожен 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.
Кразометр

4
@Crazometer замініть [n]у запиті на 5, щоб отримати кожен 5-й рядок.
Бенджамін Меннс,

Щоб розширити це, що робити, якщо ви не хочете починати з першого рядка, а з другого, наприклад?
HPWD

@HPWD, який би ви замінили @row :=0на@row :=2
Binar 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
на жаль, це уповільнює виконання щонайменше на x100 при роботі з багатьма записами
phil294,

10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;

Це чудово працює для розділення довільної таблиці, доступної лише для читання, для паралельної обробки рядків, а синтаксис надзвичайно зручний для читання та розуміння. Вам просто потрібно додати ORDER BY у стовпці первинного ключа, щоб забезпечити повернення кожного рядка лише один раз.
humbads

2

Я шукав щось подібне. Відповідь Тейлора та Білла змусила мене вдосконалити свої ідеї.

таблиця 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

Дякую, я це шукав. Мені потрібно було якось перевірити, чи певний стовпець у таблиці журналу для збережених процедур мав однакове значення кожного другого разу. Як "proc старту", "proc закінчення". У нижченаведеному 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 де (@row: = @ row + 1)% 1 = 0; Це має дві переваги. По-перше, незалежно від n, ви завжди отримуєте перший рядок, а друге, якщо ви зробите n = 1, ви отримаєте всі значення, а не жодне. (Дві зміни: -1 в рядку: = - 1 і n = 0 замість n = 1)
Брюс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.