[英]MYSQL - Group by limit
有沒有一種簡單的方法將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
結果如下: -
\n 波蘭78 48 24 12 < - 保持\n 波蘭1 15 5 0 < - 保持\n 波蘭23 12 6 3\n 波蘭2 5 0 0\n 波蘭3 0 5 0\n 波蘭4 0 0 5\n 愛爾蘭1 9 3 0 < - 保持\n 愛爾蘭2 3 0 0 < - 保持\n 愛爾蘭3 0 3 0\n 愛爾蘭4 0 0 3\n 法國12 24 12 6 < - 保持\n 法國1 3 1 0 < - 保持\n 法國231 1 0 0\n 法國2 1 0 0\n 法國4 0 0 1\n 法國3 0 1 0\n
謝謝喬恩
根據要求,我附上了表格結構和一些測試數據的副本。 我的目標是創建一個包含每個唯一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);
我不認為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
這仍然可以通過單個查詢,但它有點長,並且有一些警告,我將在查詢后解釋。 雖然,它們在查詢中不是缺陷,而是“前兩個”意味着什么含糊不清。
這是查詢:
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;
SUBSTRING_INDEX(
GROUP_CONCAT(expr1 ORDER BY expr2 SEPARATOR ";"),
";",
2 /* the GROUP_LIMIT */
)
expr1可以像CONCAT(...)。 讓REPLACE隱藏任何“;”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.