MariaDB 10.3.18: Как получить 2 записи со случайным и отличным значением? - PullRequest
3 голосов
/ 30 сентября 2019

Существует таблица MySQL с именем stat:

line_name  device_name count
1001    3548001  2
1002    3548002  3
1003    3548003  6
2001    3548004  7
2002    3548005  3
2003    3548006  4
3001    3548007  3
3002    3548008  9
3003    3548009  7

Мне нужно выбрать 2 записи, в которых первый символ в line_name отличается. Например:

1001    3548001  2
3003    3548009  7

или:

2002    3548005  3
3001    3548007  3

Я пробовал это:

SELECT DISTINCT(SUBSTRING(line_name,1,LENGTH(line_name)-3)) as pack_id, device_name, count 
from stat
order by rand()
limit 2;

, но время от времени я получаю одно и то же pack_id в наборе результатов

Ответы [ 4 ]

2 голосов
/ 30 сентября 2019

В MariaDB 10.3 вы можете использовать ROW_NUMBER() OVER (ORDER BY RAND()) для генерации случайного номера строки для каждого отдельного line_name, а затем выбрать случайную пару значений с номером строки = 1:

WITH cte AS 
(SELECT *, ROW_NUMBER() OVER (PARTITION BY LEFT(line_name, 1) ORDER BY RAND()) AS rn
 FROM stat)
SELECT `line_name`, `device_name`, `count`
FROM cte
WHERE rn = 1
ORDER BY RAND()
LIMIT 2

Демонстрация на dbfiddle

Вывод (для пары прогонов)

line_name   device_name count
1003        3548003     6
3002        3548008     9

line_name   device_name count
2001        3548004     7
1003        3548003     6
1 голос
/ 30 сентября 2019

В MySQL 8.0 вы можете самостоятельно объединить таблицу в CTE, чтобы найти случайную пару записей, которые удовлетворяют условию, а затем использовать UNION ALL, чтобы отменить результаты:

WITH cte AS (
    SELECT 
        t1.line_name line_name1,
        t1.device_name device_name1,
        t1.count count1,
        t2.line_name line_name2,
        t2.device_name device_name2,
        t2.count count2
    FROM stat t1
    INNER JOIN stat t2 ON LEFT(t1.line_name, 1) != LEFT(t2.line_name, 1)
    ORDER BY RAND()
    LIMIT 1
)
SELECT line_name1, device_name1, count1 FROM cte
UNION ALL
SELECT line_name2, device_name2, count2 FROM cte

Демонстрация на скрипте БД :

Прогон № 1:

| line_name1 | device_name1 | count1 |
| ---------- | ------------ | ------ |
| 3001       | 3548007      | 3      |
| 2001       | 3548004      | 7      |

Прогон № 2:

| line_name1 | device_name1 | count1 |
| ---------- | ------------ | ------ |
| 1003       | 3548003      | 6      |
| 2002       | 3548005      | 3      |
0 голосов
/ 30 сентября 2019

Я бы просто сделал:

select s.*
from stat s
order by row_number() over (partition by left(line_name, 1)
                            order by rand()
                           )
limit 2;

Никаких подзапросов не требуется, потому что в order by разрешены оконные функции.

Это может быть не самый эффективный метод. Но если у вас большой стол, производительность должна быть в порядке.

0 голосов
/ 30 сентября 2019

Вы можете GROUP BY pack_id и выбрать случайное имя соответствующего имени_устройства или ANY_VALUE(), если вы используете MySQL> = 5.7

SELECT 
  SUBSTR(line_name, 1, 1) AS pack_id,
  line_name,
  ANY_VALUE(device_name) AS device_name,
  count
FROM stat
GROUP BY pack_id
ORDER BY RAND()
LIMIT 2

Более старые версии MySQL

SELECT 
  SUBSTR(line_name, 1, 1) AS pack_id,
  line_name,
  device_name,
  count
FROM stat
GROUP BY pack_id
ORDER BY RAND()
LIMIT 2

http://sqlfiddle.com/#!9/2d466f2/1

Обратите внимание, что я также упростил вычисление pack_id

...