MySQL 个表之间的 JOIN 行数限制
LIMIT number of rows in a JOIN between MySQL tables
我有什么
我在 MySQL 数据库(版本 5.6.35)中有以下两个 table。
CREATE TABLE `Runs` (
`Name` varchar(200) NOT NULL,
`Run` varchar(200) NOT NULL,
`Points` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Runs` (`Name`, `Run`, `Points`) VALUES
('John', 'A08', 12),
('John', 'A09', 3),
('John', 'A01', 15),
('Kate', 'A02', 92),
('Kate', 'A03', 1),
('Kate', 'A04', 33),
('Peter', 'A05', 8),
('Peter', 'A06', 14),
('Peter', 'A07', 5);
CREATE TABLE `Users` (
`Name` varchar(500) NOT NULL,
`NumberOfRun` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Users` (`Name`, `NumberOfRun`) VALUES
('John', 2),
('Kate', 1),
('Peter', 3);
ALTER TABLE `Runs`
ADD PRIMARY KEY (`Run`);
我的目标是什么
- John 有
Users.NumberOfRun=2
,所以我将从 Runs
table 中提取前 2 条记录
- Kate 有
Users.NumberOfRun=1
,所以我将从 Runs
table 中提取 1 个最高记录
- Peter 有
Users.NumberOfRun=3
,所以我将从 Runs
table 中提取前 3 条记录
我想得出以下结果
+-------+-----+--------+
| Name | Run | Points |
+-------+-----+--------+
| John | A01 | 15 |
| John | A08 | 12 |
| Kate | A02 | 92 |
| Peter | A06 | 14 |
| Peter | A05 | 8 |
| Peter | A07 | 5 |
+-------+-----+--------+
我试过的
首先,如果它是 SQL 服务器,我会使用 ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ) AS [rn]
函数运行 table,然后用 [=22= 创建一个 JOIN
] table 在 Users.NumberOfRun<=[rn]
.
我已阅读 this 文档,但似乎 MySQL 中的 PARTITONING
自版本 8.X 起可用,但我使用的是 5.6.X 版本.
最后,我尝试了这个查询,基于 this Whosebug answer:
SELECT t0.Name,t0.Run
FROM Runs AS t0
LEFT JOIN Runs AS t1 ON t0.Name=t1.Name AND t0.Run=t1.Run AND t1.Points>t0.Points
WHERE t1.Points IS NULL;
但它没有给我行号,这对我来说基本上是如上所述进行 JOIN。
'group_concat' 和 'find_in_set' 的组合,然后使用 'find_in_set' 返回的位置进行过滤将为您完成这项工作。
GROUP_CONCAT会先将数据按点数降序排列。
GROUP_CONCAT(Run ORDER BY Points DESC)
FIND_IN_SET 然后将检索您要包含在结果中的行数。
FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
以下查询应该适合您。
SELECT
Runs.*
FROM
Runs
INNER JOIN (
SELECT
Name, GROUP_CONCAT(Run ORDER BY Points DESC) grouped_run
FROM
Runs
GROUP BY Name
) group_max ON Runs.Name = group_max.Name
INNER JOIN Users ON Users.Name = Runs.Name
WHERE FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
ORDER BY
Runs.Name Asc, Runs.Points DESC;
我有什么
我在 MySQL 数据库(版本 5.6.35)中有以下两个 table。
CREATE TABLE `Runs` (
`Name` varchar(200) NOT NULL,
`Run` varchar(200) NOT NULL,
`Points` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Runs` (`Name`, `Run`, `Points`) VALUES
('John', 'A08', 12),
('John', 'A09', 3),
('John', 'A01', 15),
('Kate', 'A02', 92),
('Kate', 'A03', 1),
('Kate', 'A04', 33),
('Peter', 'A05', 8),
('Peter', 'A06', 14),
('Peter', 'A07', 5);
CREATE TABLE `Users` (
`Name` varchar(500) NOT NULL,
`NumberOfRun` int(11) NOT NULL
) DEFAULT CHARSET=latin1;
INSERT INTO `Users` (`Name`, `NumberOfRun`) VALUES
('John', 2),
('Kate', 1),
('Peter', 3);
ALTER TABLE `Runs`
ADD PRIMARY KEY (`Run`);
我的目标是什么
- John 有
Users.NumberOfRun=2
,所以我将从Runs
table 中提取前 2 条记录
- Kate 有
Users.NumberOfRun=1
,所以我将从Runs
table 中提取 1 个最高记录
- Peter 有
Users.NumberOfRun=3
,所以我将从Runs
table 中提取前 3 条记录
我想得出以下结果
+-------+-----+--------+
| Name | Run | Points |
+-------+-----+--------+
| John | A01 | 15 |
| John | A08 | 12 |
| Kate | A02 | 92 |
| Peter | A06 | 14 |
| Peter | A05 | 8 |
| Peter | A07 | 5 |
+-------+-----+--------+
我试过的
首先,如果它是 SQL 服务器,我会使用 ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ) AS [rn]
函数运行 table,然后用 [=22= 创建一个 JOIN
] table 在 Users.NumberOfRun<=[rn]
.
我已阅读 this 文档,但似乎 MySQL 中的 PARTITONING
自版本 8.X 起可用,但我使用的是 5.6.X 版本.
最后,我尝试了这个查询,基于 this Whosebug answer:
SELECT t0.Name,t0.Run
FROM Runs AS t0
LEFT JOIN Runs AS t1 ON t0.Name=t1.Name AND t0.Run=t1.Run AND t1.Points>t0.Points
WHERE t1.Points IS NULL;
但它没有给我行号,这对我来说基本上是如上所述进行 JOIN。
'group_concat' 和 'find_in_set' 的组合,然后使用 'find_in_set' 返回的位置进行过滤将为您完成这项工作。
GROUP_CONCAT会先将数据按点数降序排列。
GROUP_CONCAT(Run ORDER BY Points DESC)
FIND_IN_SET 然后将检索您要包含在结果中的行数。
FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
以下查询应该适合您。
SELECT
Runs.*
FROM
Runs
INNER JOIN (
SELECT
Name, GROUP_CONCAT(Run ORDER BY Points DESC) grouped_run
FROM
Runs
GROUP BY Name
) group_max ON Runs.Name = group_max.Name
INNER JOIN Users ON Users.Name = Runs.Name
WHERE FIND_IN_SET(Run, grouped_run) BETWEEN 1 AND Users.NumberOfRun
ORDER BY
Runs.Name Asc, Runs.Points DESC;