2010-04-15 102 views
13

是否有一種簡單的方法來將GROUP BY結果限制在頂端2.以下查詢返回所有結果。使用「限制2」將整個列表僅限於前兩項。MYSQL - 組限制

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

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

由於「GROUP BY」用於對相關數據執行集合函數,因此不太可能。 MySQL沒有看到6個波蘭,4個愛爾蘭和6個法國小組,它看到16個不同的組,沒有任何關聯它們。你想達到什麼目的?也許還有另一種方法來分組。 – Duncan 2010-04-15 07:27:43

+1

你能否提供表格結構和一些測試數據?我認爲有可能使用HAVING和子查詢來做到這一點。 – 2010-04-15 07:39:48

回答

10

我不認爲有MySQL中的簡單的方法前2結果的單一視圖。要做到這一點的一種方法是,通過爲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語法。當您的測試數據上運行

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 

結果:但是,您可以模擬ROW_NUMBER使用變量

 
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 
+0

嗨德拉科 - 我已經更新了帖子,包括表結構和數據。我很欣賞迄今爲止的所有反饋 - 謝謝。 – jono2010 2010-04-16 00:43:07

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 

需要注意的是,如果有一個以上的id_market具有相同的「好」計數相同rating_name,那麼你會得到兩個以上的記錄。例如,如果三個愛爾蘭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; 
+0

下午,所有非常感謝高度重視的反饋 - 非常感謝!關心喬恩 – jono2010 2010-04-19 04:34:11

0
SUBSTRING_INDEX(
    GROUP_CONCAT(expr1 ORDER BY expr2 SEPARATOR ";"), 
    ";", 
    2 /* the GROUP_LIMIT */ 
) 

表達式1可以像CONCAT(...)。參與REPLACE隱藏任何「;」。