Поведение MySQL при многократном использовании ANY_VALUE - PullRequest
0 голосов
/ 24 сентября 2019

Я хочу получить случайную строку для каждой группы при использовании GROUP BY в MySQL 5.7.Самый чистый способ сделать это из моего исследования - сделать что-то вроде этого:

SELECT ANY_VALUE(column_1), ANY_VALUE(column_2), ..., ANY_VALUE(column_n)
FROM table
GROUP BY column

Поскольку нет синтаксиса для чего-то вроде ANY_VALUE(*) или ANY_VALUE(column_1, column2, ..., column_n), я не могу понять, что каждый из приведенных выше запросовзначение может быть получено из другой строки, или если все поля ANY_VALUE будут получены из одной строки.

Ответы [ 2 ]

1 голос
/ 24 сентября 2019

Предполагая следующую схему и пример данных:

create table tbl(
  id int auto_increment primary key,
  grp int not null,
  val int not null,
  index (grp)
);

insert into tbl (grp, val) values (1, 1);
insert into tbl (grp, val) values (1, 2);
insert into tbl (grp, val) values (1, 3);
insert into tbl (grp, val) values (2, 1);
insert into tbl (grp, val) values (2, 2);

Получить отдельные группы в производной таблице (или использовать базовую таблицу для групп, если есть).Получить случайный первичный ключ в подзапросе в предложении SELECT с помощью ORDER BY rand() LIMIT 1.Затем объедините результат как производную таблицу с базовой таблицей.

select t.*
from (
  select (
    select id
    from tbl t
    where t.grp = g.grp
    order by rand()
    limit 1
  ) as id
  from (select distinct grp from tbl) g
) r
join tbl t using (id);

Результат будет выглядеть примерно так:

| id  | grp | val |
| --- | --- | --- |
| 2   | 1   | 2   |
| 4   | 2   | 1   |

Просмотр в БД Fiddle

1 голос
/ 24 сентября 2019

Если вы хотите случайную строку, используйте row_number():

select t.*
from (select t.*,
             row_number() over (partition by column order by rand()) as seqnum
      from t
     ) t
where seqnum = 1;

Я предполагаю, что это также быстрее, чем group by, но вы можете проверить, так ли это.

В MySQL 5.7 вы можете использовать переменные:

select t.*
from (select t.*,
             (@rn := if(@c = column, @rn + 1,
                        if(@c := column, 1, 1)
                       )
             ) as rn
      from (select t.* from t order by column, rand) t cross join
           (select @c := '', @rn := 0) params
     ) t
where rn = 1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...