我需要获取每个国家前两个姓名的列表(从账户和国家表中)。我已经搜索了很多并找到了一些有效的答案,但无法获得正确的结果。
请在此处查看我的SQL Fiddle:
http://sqlfiddle.com/#!9/cd1296/5
CREATE TABLE IF NOT EXISTS `country` (
`id` int(6) unsigned NOT NULL,
`iso` varchar(3) NOT NULL,
`country_name` varchar(24) NOT NULL,
PRIMARY KEY (id)
) DEFAULT CHARSET=utf8;
INSERT INTO `country` (`id`, `iso`,`country_name`) VALUES
('1', 'DEU','Germany'),
('2', 'USA','United States'),
('3', 'CAN','Canada'),
('4', 'JPN','Japan');
CREATE TABLE IF NOT EXISTS `accounts` (
id int(6) unsigned NOT NULL,
name varchar(50) NOT NULL,
iso3 varchar(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `accounts` (`id`,`name`, `iso3`) VALUES
('1', 'Hans', 'DEU'),
('2', 'Willi', 'DEU'),
('3', 'Peter', 'DEU'),
('4', 'Susanne', 'DEU'),
('5', 'John', 'USA'),
('6', 'Jane', 'USA'),
('7', 'Peter', 'USA'),
('8', 'Paul', 'USA'),
('9', 'Mary', 'USA'),
('10', 'Gerard', 'CAN'),
('11', 'Mirelle', 'CAN'),
('12', 'Hiko', 'JPN'),
('13', 'Miko', 'JPN'),
('14', 'Susanne', 'DEU'),
('15', 'Peter', 'DEU'),
('16', 'John', 'USA'),
('17', 'Paul', 'USA'),
('18', 'Susanne', 'DEU'),
('19', 'Bob', 'DEU'),
('20', 'John', 'USA'),
('21', 'Paul', 'USA'),
('33', 'Gerard', 'CAN'),
('22', 'Maribelle', 'CAN'),
('23', 'Gerd', 'CAN'),
('24', 'Mira', 'CAN'),
('25', 'Huko', 'JPN'),
('26', 'Hako', 'JPN'),
('27', 'Hiko', 'JPN'),
('28', 'Jon', 'USA'),
('29', 'Jim', 'USA'),
('30', 'John', 'USA'),
('31', 'JJ', 'USA'),
('32', 'Bob', 'USA'),
('34', 'Bob', 'USA'),
('35', 'Miko', 'JPN'),
('36', 'Miko', 'JPN');
使用这个语句可以使列表按正确顺序排列,但不会在第二个结果后停止:
SELECT country_name, iso, name, COUNT(name) AS name_count
FROM accounts
JOIN country ON country.iso = accounts.iso3
GROUP BY country.iso, name
ORDER BY country.iso ASC, name_count DESC;
如其他问题/答案所建议的那样,解决方案可能是使用“MySQL会话变量”(基于https://www.databasejournal.com/features/mysql/selecting-the-top-n-results-by-group-in-mysql.html)。
我的问题: country_rank没有正确生成,因此无法得到正确的结果。我做错了什么?
SET @current_country = "";
SET @country_rank = 0;
SELECT country_name, name, name_count, rank
FROM
(
SELECT country_name, iso, name, COUNT(name) AS name_count,
@country_rank := IF( @current_country = iso,
@country_rank + 1,
1
) AS rank,
@current_country := iso
FROM accounts
JOIN country ON country.iso = accounts.iso3
GROUP BY country.iso, name
ORDER BY country.iso ASC, name_count DESC
) AS ranked
WHERE rank<=2;