MariaDB 10.3.18:如何获得 2 条具有随机和不同值的记录?

MariaDB 10.3.18 : How to get 2 records with random and distinct value?

有一个 MySQL table 名为 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

我需要 select 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

如果您使用 MySQL >= 5.7[=15=,您可以 GROUP BY pack_id 和 select 随机选择相应的 device_name 或 ANY_VALUE() ]

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

的计算

在MySQL8.0中,可以在CTE中自加入table,随机找到一对满足条件的记录,然后用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

Demo on DB Fiddle:

运行 #1:

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

运行 #2:

| line_name1 | device_name1 | count1 |
| ---------- | ------------ | ------ |
| 1003       | 3548003      | 6      |
| 2002       | 3548005      | 3      |

在 MariaDB 10.3 中,您可以使用 ROW_NUMBER() OVER (ORDER BY RAND()) 为每个不同的 line_name 生成随机行号,然后 select 行号 = 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

Demo on dbfiddle

输出(几次运行)

line_name   device_name count
1003        3548003     6
3002        3548008     9

line_name   device_name count
2001        3548004     7
1003        3548003     6

我会简单地做:

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

不需要子查询,因为 window 函数在 order by 中被允许。

这可能不是最有效的方法。但是除非你的 table 很大,否则性能应该没问题。