是否有一种简单的方法将GROUP BY结果限制在前2位。以下查询返回所有结果。使用“LIMIT 2”仅将整个列表减少到前2个条目。
select distinct(rating_name),
id_markets,
sum(rating_good) 'good',
sum(rating_neutral)'neutral',
sum(rating_bad) 'bad'
from ratings
where rating_year=year(curdate()) and rating_week= week(curdate(),1)
group by rating_name,id_markets
order by rating_name, sum(rating_good)
desc
结果如下: -
poland 78 48 24 12 <- keep poland 1 15 5 0 <- keep poland 23 12 6 3 poland 2 5 0 0 poland 3 0 5 0 poland 4 0 0 5 ireland 1 9 3 0 <- keep ireland 2 3 0 0 <- keep ireland 3 0 3 0 ireland 4 0 0 3 france 12 24 12 6 <- keep france 1 3 1 0 <- keep france 231 1 0 0 france 2 1 0 0 france 4 0 0 1 france 3 0 1 0
由于 乔恩
根据要求,我附上了表格结构和一些测试数据的副本。我的目标是创建一个包含每个唯一rating_name
的前2个结果的视图CREATE TABLE `zzratings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_markets` int(11) DEFAULT NULL,
`id_account` int(11) DEFAULT NULL,
`id_users` int(11) DEFAULT NULL,
`dateTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`rating_good` int(11) DEFAULT NULL,
`rating_neutral` int(11) DEFAULT NULL,
`rating_bad` int(11) DEFAULT NULL,
`rating_name` varchar(32) DEFAULT NULL,
`rating_year` smallint(4) DEFAULT NULL,
`rating_week` tinyint(4) DEFAULT NULL,
`cash_balance` decimal(9,6) DEFAULT NULL,
`cash_spend` decimal(9,6) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `rating_year` (`rating_year`),
KEY `rating_week` (`rating_week`),
KEY `rating_name` (`rating_name`)
) ENGINE=MyISAM AUTO_INCREMENT=2166690 DEFAULT CHARSET=latin1;
INSERT INTO `zzratings` (`id`,`id_markets`,`id_account`,`id_users`,`dateTime`,`rating_good`,`rating_neutral`,`rating_bad`,`rating_name`,`rating_year`,`rating_week`,`cash_balance`,`cash_spend`)
VALUES
(63741, 1, NULL, 100, NULL, 1, NULL, NULL, 'poland', 2010, 15, NULL, NULL),
(63742, 1, NULL, 101, NULL, 1, NULL, NULL, 'poland', 2010, 15, NULL, NULL),
(1, 2, NULL, 102, NULL, 1, NULL, NULL, 'poland', 2010, 15, NULL, NULL),
(63743, 3, NULL, 103, NULL, NULL, 1, NULL, 'poland', 2010, 15, NULL, NULL),
(63744, 4, NULL, 104, NULL, NULL, NULL, 1, 'poland', 2010, 15, NULL, NULL),
(63745, 1, NULL, 105, NULL, 1, NULL, NULL, 'poland', 2010, 15, NULL, NULL),
(63746, 1, NULL, 106, NULL, NULL, 1, NULL, 'poland', 2010, 15, NULL, NULL),
(63747, 5, NULL, 100, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63748, 5, NULL, 101, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63749, 2, NULL, 102, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63750, 3, NULL, 103, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63751, 4, NULL, 104, NULL, NULL, NULL, 1, 'ireland', 2010, 15, NULL, NULL),
(63752, 1, NULL, 105, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63753, 1, NULL, 106, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63754, 1, NULL, 100, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63755, 1, NULL, 101, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63756, 2, NULL, 102, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63757, 34, NULL, 103, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63758, 34, NULL, 104, NULL, NULL, NULL, 1, 'ireland', 2010, 15, NULL, NULL),
(63759, 34, NULL, 105, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63760, 34, NULL, 106, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63761, 21, NULL, 100, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63762, 21, NULL, 101, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63763, 21, NULL, 102, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63764, 21, NULL, 103, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63765, 4, NULL, 104, NULL, NULL, NULL, 1, 'ireland', 2010, 15, NULL, NULL),
(63766, 1, NULL, 105, NULL, 1, NULL, NULL, 'ireland', 2010, 15, NULL, NULL),
(63767, 1, NULL, 106, NULL, NULL, 1, NULL, 'ireland', 2010, 15, NULL, NULL),
(63768, 1, NULL, 100, NULL, 1, NULL, NULL, 'france', 2010, 15, NULL, NULL),
(63769, 1, NULL, 101, NULL, 1, NULL, NULL, 'france', 2010, 15, NULL, NULL),
(63770, 2, NULL, 102, NULL, 1, NULL, NULL, 'france', 2010, 15, NULL, NULL),
(63771, 3, NULL, 103, NULL, NULL, 1, NULL, 'france', 2010, 15, NULL, NULL),
(63772, 4, NULL, 104, NULL, NULL, NULL, 1, 'france', 2010, 15, NULL, NULL);
答案 0 :(得分:10)
我认为MySQL中没有一种简单的方法。一种方法是通过按rating_name为组划分的每一行生成行号,然后仅选择row_number为2或更小的行。在大多数数据库中,您可以使用以下内容执行此操作:
SELECT * FROM (
SELECT
rating_name,
etc...,
ROW_NUMBER() OVER (PARTITION BY rating_name ORDER BY good) AS rn
FROM your_table
) T1
WHERE rn <= 2
不幸的是,MySQL不支持ROW_NUMBER
语法。但是,您可以使用变量模拟ROW_NUMBER
:
SELECT
rating_name, id_markets, good, neutral, bad
FROM (
SELECT
*,
@rn := CASE WHEN @prev_rating_name = rating_name THEN @rn + 1 ELSE 1 END AS rn,
@prev_rating_name := rating_name
FROM (
SELECT
rating_name,
id_markets,
SUM(COALESCE(rating_good, 0)) AS good,
SUM(COALESCE(rating_neutral, 0)) AS neutral,
SUM(COALESCE(rating_bad, 0)) AS bad
FROM zzratings
WHERE rating_year = YEAR(CURDATE()) AND rating_week = WEEK(CURDATE(), 1)
GROUP BY rating_name, id_markets
) AS T1, (SELECT @prev_rating_name := '', @rn := 0) AS vars
ORDER BY rating_name, good DESC
) AS T2
WHERE rn <= 2
ORDER BY rating_name, good DESC
运行测试数据时的结果:
france 1 2 0 0 france 2 1 0 0 ireland 1 4 2 0 ireland 21 3 1 0 poland 1 3 1 0 poland 2 1 0 0
答案 1 :(得分:4)
这仍然可以通过单个查询,但它有点长,并且有一些警告,我将在查询后解释。尽管如此,它们在查询中并不存在缺陷,而在“前两者”的含义中存在一些含糊之处。
以下是查询:
SELECT ratings.* FROM
(SELECT rating_name,
id_markets,
sum(rating_good) 'good',
sum(rating_neutral)'neutral',
sum(rating_bad) 'bad'
FROM zzratings
WHERE rating_year=year(curdate()) AND rating_week = week(curdate(),1)
GROUP BY rating_name,id_markets) AS ratings
LEFT JOIN
(SELECT rating_name,
id_markets,
sum(rating_good) 'good',
sum(rating_neutral)'neutral',
sum(rating_bad) 'bad'
FROM zzratings
WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1)
GROUP BY rating_name,id_markets) AS ratings2
ON ratings2.good <= ratings.good AND
ratings2.id_markets <> ratings.id_markets AND
ratings2.rating_name = ratings.rating_name
LEFT JOIN
(SELECT rating_name,
id_markets,
sum(rating_good) 'good',
sum(rating_neutral)'neutral',
sum(rating_bad) 'bad'
FROM zzratings
WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1)
GROUP BY rating_name,id_markets) AS ratings3
ON ratings3.good >= ratings2.good AND
ratings3.id_markets <> ratings.id_markets AND
ratings3.id_markets <> ratings2.id_markets AND
ratings3.rating_name = ratings.rating_name
WHERE (ratings2.good IS NULL OR ratings3.good IS NULL) AND
ratings.good IS NOT NULL
ORDER BY ratings.rating_name, ratings.good DESC
需要注意的是,如果同一个rating_name有多个id_market具有相同的“good”计数,那么您将获得两个以上的记录。例如,如果有三个爱尔兰id_markets的“好”数为3,那么最高,那你怎么能显示前两个?你不能。因此查询将显示所有三个。
另外,如果有一个“3”,最高和两个“2”的计数,你就无法显示前两个,因为你有第二名并列,所以查询显示所有三个
如果您先创建一个包含聚合结果集的临时表,那么查询会更简单。
CREATE TEMPORARY TABLE temp_table
SELECT rating_name,
id_markets,
sum(rating_good) 'good',
sum(rating_neutral)'neutral',
sum(rating_bad) 'bad'
FROM zzratings
WHERE rating_year=year(curdate()) AND rating_week= week(curdate(),1;
SELECT ratings.*
FROM temp_table ratings
LEFT JOIN temp_table ratings2
ON ratings2.good <= ratings.good AND
ratings2.id_markets <> ratings.id_markets AND
ratings2.rating_name = ratings.rating_name
LEFT JOIN temp_table ratings3
ON ratings3.good >= ratings2.good AND
ratings3.id_markets <> ratings.id_markets AND
ratings3.id_markets <> ratings2.id_markets AND
ratings3.rating_name = ratings.rating_name
WHERE (ratings2.good IS NULL OR ratings3.good IS NULL) AND
ratings.good IS NOT NULL
ORDER BY ratings.rating_name, ratings.good DESC;
答案 2 :(得分:0)
SUBSTRING_INDEX(
GROUP_CONCAT(expr1 ORDER BY expr2 SEPARATOR ";"),
";",
2 /* the GROUP_LIMIT */
)
expr1可以像CONCAT(...)。让REPLACE隐藏任何“;”。