Как рассчитывается rand () при использовании в запросе с GROUP BY - PullRequest
0 голосов
/ 22 октября 2018

У меня есть несколько SQL, где мне нужно сгруппировать несколько строк в запросе и использовать случайное значение для каждой строки после группировки, чтобы случайное значение было равномерно распределено для каждой строки после группировки, но я не уверен, какmySql обрабатывает этот

, см. этот очень упрощенный пример:

 CREATE TABLE IF NOT EXISTS soldier (
     unit VARCHAR(255) NOT NULL,
     name VARCHAR(255) NOT NULL,
     personal_number INT
 ) 

select unit, count(name), rand()
   from soldier
   group by unit

, поэтому я попытался ввести 3 солдата из одного подразделения и одного солдата из другого, и случайный столбец, кажется, распределен довольноаналогично в наборе результатов.но я подозреваю, что может случиться так, что, возможно, значение для сгруппированной строки всегда берется из строки солдат с наименьшим значением или из наибольшей, и тогда распределение будет искажено.если OTOH он берется случайным образом от любого из сгруппированных солдат, или усредняется, или вычисляется после группировки, я в порядке (насколько я могу судить).Кто-нибудь знает, как rand () рассчитывается в таких случаях?

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

У меня нет ссылки на документацию для этого, но эмпирически я смог определить, что MySQL, по-видимому, оценивает rand() после того, как агрегат GROUP BY завершен.То есть он оценивает rand() один раз для группы , а не один раз для каждой записи в таблице.Я настроил следующий тест:

WITH yourTable AS (
    SELECT 1 AS id, 3 AS val UNION ALL
    SELECT 1, 5 UNION ALL
    SELECT 2, 10
)

SELECT id, SUM(val) AS val_sum, rand()
FROM yourTable
GROUP BY id;

Демо

Чтобы убедиться, что режим ONLY_FULL_GROUP_BY был включен, я изменил запрос на этоти это не удалось:

SELECT id, SUM(val) AS val_sum, rand(), val   -- non aggregate column = failure
FROM yourTable
GROUP BY id;

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

0 голосов
/ 22 октября 2018

Я забыл об основах.Ваш запрос оценивается в следующем порядке :

FROM, GROUP BY, COUNT, SELECT

В вашем примере MySQL создает две группы перед выбором:

  • Юнит 1 с 3 солдатами
  • Блок 2 с 1 солдатом

Функция RAND() будет вызываться один раз для каждой строки после группировки .Ваш запрос в его текущей форме является правильным.

Обратите внимание, что RAND() можно безопасно использовать внутри SELECT, потому что это функция, а не ссылка на столбец.И просто чтобы быть уверенным, я заменил его UDF, который записывает, сколько раз он был вызван;он был вызван дважды для вашего примера.

0 голосов
/ 22 октября 2018

Вы можете использовать перекрестное соединение и подзапрос, например:

    select a.unit, a.num, t.rand
    from (
    select unit, count(name) as num, t.rand
       from soldier
       group by unit
    ) a
    cross join (
        select rand() as rand 
        from dual
    ) t 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...