我需要对多个数据库表进行搜索。由于所有表都具有相同的结构(相同的列,它们实际上是同一个表的存档数据),我可以使用 UNION ALL 将它们全部组合起来。
但是,挑战是我需要获取用户名列的不同值,并且对于每个用户名值,我需要在对所有存档数据使用 UNION ALL 后找到最早的时间戳。
我浏览了文档并用 google 搜索了相当长的一段时间,但找不到令人满意的 MySQL 解决方案。
我能想到的唯一方法是编写一些外部代码来使用 UNION ALL 搜索每个用户名的值。并一一运行查询。知道数据库中列出了 100k 个不同的用户名,这将需要相当长的时间。我已经开始这个脚本了,但是感觉效率很低而且浪费资源。
SELECT * FROM table1 WHERE `USERNAME` LIKE 'USERNAMEXXX'
UNION ALL
SELECT * FROM table2 WHERE `USERNAME` LIKE 'USERNAMEXXX'
UNION ALL
SELECT * FROM table3 WHERE `USERNAME` LIKE 'USERNAMEXXX'
UNION ALL
SELECT * FROM table4 WHERE `USERNAME` LIKE 'USERNAMEXXX'
ORDER BY TIME_STAMP ASC
LIMIT 1
上面的 SQL 查询为我提供了每个用户名所需的内容,但我需要为每个不同的用户名迭代它。
补充一下,我还有另一个表,其中包含所有不同的用户名值。我使用该表来填充对我的外部代码解决方案的搜索。
有没有办法使用 native SQL 来实现此目的,而无需外部脚本?结合了不同、联合所有和按时间戳 asc 限制 1 排序的东西。
最佳答案
在 MySQL 8+ 中,您可以使用窗口函数:
SELECT t.*
FROM (SELECT t.*,
ROW_NUMBER() OVER (PARTITION BY username ORDER BY timestamp) as seqnum
FROM ((SELECT t.* FROM table1 t) UNION ALL
(SELECT t.* FROM table2 t) UNION ALL
(SELECT t.* FROM table3 t) UNION ALL
(SELECT t.* FROM table4 t)
) t
) t
WHERE seqnum = 1;
在早期版本中,您可以使用变量:
SELECT t.*
FROM (SELECT t.*,
(@rn := IF(@u = username, @rn + 1,
IF(@u := username, 1, 1)
)
) as seqnum
ROW_NUMBER() OVER (PARTITION BY username ORDER BY timestamp) as seqnum
FROM ((SELECT t.* FROM table1 t) UNION ALL
(SELECT t.* FROM table2 t) UNION ALL
(SELECT t.* FROM table3 t) UNION ALL
(SELECT t.* FROM table4 t)
ORDER BY username, timestamp
) t CROSS JOIN
(SELECT @u := '', @rn := 0) params
) t
WHERE seqnum = 1;
上面假设您需要所有列。如果您只想要最小时间戳和用户名,请使用聚合:
SELECT username, MIN(timestamp),
FROM ((SELECT t.* FROM table1 t) UNION ALL
(SELECT t.* FROM table2 t) UNION ALL
(SELECT t.* FROM table3 t) UNION ALL
(SELECT t.* FROM table4 t)
) t
GROUP BY username;
关于mysql - 联合mariadb中的n个表并根据时间戳找到不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56215737/