2010-10-06 56 views
2

嘿大家。我相信這是一個'最大的n-per-group'問題,但即使在查看幾個關於StackOverflow的問題之後,我不確定如何將其應用於我的情況...MySQL最大 - 每組麻煩

我正在使用MySQL數據庫並有一個基本的博客類型的系統中設置了有關計算機應用......這些表是這樣的:

POSTS 
post_id 
post_created 
post_type  -- could be article, review, feature, whatever 
post_status -- 'a' approved or 'd' for draft 

APPS 
app_id 
app_name 
app_platform -- Windows, linux, unix, etc.. 

APP_TO_POST -- links my posts to its relevant application 
atp_id 
atp_app_id 
atp_post_id 

我用下面的基本查詢拉了一個名爲「Photoshop的應用程序的所有文章其中郵政類型爲'物品'且物品的狀態爲批准的'a':

SELECT apps.app_name, apps.app_platform, posts.post_created, posts.post_id 
FROM apps 
JOIN app_to_post ON app_to_post.atp_app_id = apps.app_id 
JOIN posts ON app_to_post.atp_post_id = posts.post_id 
WHERE apps.app_name = 'Photoshop' 
AND 
posts.post_type = 'Article' 
AND 
posts.post_status = 'a' 

它得到我這些預期結果:

app_name app_platform post_created  post_id 
Photoshop Windows  Oct. 20th, 2009 1 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

會有人能夠伸出援助之手,我怎麼可能會改變該查詢只拉每個應用平臺最近的文章?因此,例如,我想我的結果是這樣的:

app_name app_platform post_created  post_id 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

,並省略'Photoshop Windows'文章之一,因爲它不是最近的一次。

如果我簡單地使用MAX(post_created)GROUP BY app_platform,我的結果並不總是正確分組。從我的理解我需要執行子查詢的某種內部連接?

回答

0

你在正確的軌道上。

嘗試增加

group by app_name,app_platform 
having post_created=max(post_created) 

或者,如果你POST_ID是連續的,其中較高的值將始終反映以後的文章中,使用having子句:having post_id=max(post_id)

+1

我正在通過類似的問題,「有」的聲明並沒有解決它。 MySQL似乎報告了它爲每個分組行找到的第一個結果,並且所有「having」將會完全排除第一個結果與最大結果不匹配的任何行。 – 2011-06-22 15:12:41

4

既然你有足夠的JOIN S,我建議創建VIEW第一:

CREATE VIEW articles AS 
    SELECT a.app_name, a.app_platform, p.post_created, p.post_id 
    FROM  apps a 
    JOIN  app_to_post ap ON ap.atp_app_id = a.app_id 
    JOIN  posts p ON ap.atp_post_id = p.post_id 
    WHERE  p.post_type = 'Article' AND p.post_status = 'a'; 

然後你可以使用NULL自加入:

SELECT  a1.app_name, a1.app_platform, a1.post_created, a1.post_id 
FROM  articles a1 
LEFT JOIN articles a2 ON 
      a2.app_platform = a1.app_platform AND a2.post_created > a1.post_created 
WHERE  a2.post_id IS NULL; 

測試用例:

CREATE TABLE posts (
    post_id   int, 
    post_created  datetime, 
    post_type  varchar(30), 
    post_status  char(1) 
); 

CREATE TABLE apps (
    app_id   int, 
    app_name   varchar(40), 
    app_platform  varchar(40) 
); 

CREATE TABLE app_to_post (
    atp_id   int, 
    atp_app_id  int, 
    atp_post_id  int 
); 

INSERT INTO posts VALUES (1, '2010-10-06 05:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (2, '2010-10-06 06:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (3, '2010-10-06 07:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (4, '2010-10-06 08:00:00', 'Article', 'a'); 
INSERT INTO posts VALUES (5, '2010-10-06 09:00:00', 'Article', 'a'); 

INSERT INTO apps VALUES (1, 'Photoshop', 'Windows'); 
INSERT INTO apps VALUES (2, 'Photoshop', 'Macintosh'); 

INSERT INTO app_to_post VALUES (1, 1, 1); 
INSERT INTO app_to_post VALUES (1, 1, 2); 
INSERT INTO app_to_post VALUES (1, 2, 3); 
INSERT INTO app_to_post VALUES (1, 2, 4); 
INSERT INTO app_to_post VALUES (1, 1, 5); 

結果:

+-----------+--------------+---------------------+---------+ 
| app_name | app_platform | post_created  | post_id | 
+-----------+--------------+---------------------+---------+ 
| Photoshop | Macintosh | 2010-10-06 08:00:00 |  4 | 
| Photoshop | Windows  | 2010-10-06 09:00:00 |  5 | 
+-----------+--------------+---------------------+---------+ 
2 rows in set (0.00 sec) 

作爲一個側面說明,一般你不需要爲您junction table一個surrogate key。你還不如建立一個複合主鍵(理想外鍵引用的表):

CREATE TABLE app_to_post (
    atp_app_id  int, 
    atp_post_id  int, 
    PRIMARY KEY (atp_app_id, atp_post_id), 
    FOREIGN KEY (atp_app_id) REFERENCES apps (app_id), 
    FOREIGN KEY (atp_post_id) REFERENCES posts (post_id) 
) ENGINE=INNODB; 
+0

這個空聯接爲我解決了類似的問題。 – 2011-06-22 15:18:44

+1

這是一個高效的查詢嗎?您將所有內容加入到文章中,然後將所有內容加入其中。這對我來說很昂貴。 – marc40000 2012-02-02 01:16:51

2

我們先考慮如何從查詢結果中獲得最大價值的行和你的理想的結果:

您的結果:(我們稱之爲表T)

app_name app_platform post_created  post_id 
Photoshop Windows  Oct. 20th, 2009 1 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

結果你想要的:

app_name app_platform post_created  post_id 
Photoshop Windows  Dec. 1, 2009  3 
Photoshop Macintosh  Nov. 10th, 2009 2 

爲了得到結果,你應該:

  1. 計算每個平臺的最大POST_ID爲表T
  2. 加入最大結果與原點表T在該行的其他列獲取值。

查詢低於:

SELECT 
    t1.app_name,t1.app_platform,t1.post_created,t1.post_id 
FROM 
    (SELECT app_platform, MAX(post_created) As MaxPostCreated 
    FROM T 
    GROUP BY app_platform) AS t2 JOIN 
    T AS t1 
WHERE 
    t1.app_platform = t2.app_platform1 
    AND t2.MaxPostCreated = t1.post_created 

在該查詢中,子查詢執行的第一步驟,和加入執行第二步驟。

最終的結果與你的部分答案結合低於(有圖)表示:

CREATE VIEW T 
    SELECT a.app_name, a.app_platform, p.post_created, p.post_id 
    FROM  apps a 
    JOIN  app_to_post ap ON ap.atp_app_id = a.app_id 
    JOIN  posts p ON ap.atp_post_id = p.post_id 
    WHERE  p.post_type = 'Article' AND p.post_status = 'a'; 

SELECT 
    t1.app_name,t1.app_platform,t1.post_created,t1.post_id 
FROM 
    (SELECT app_platform, MAX(post_created) As MaxPostCreated 
    FROM T 
    GROUP BY app_platform) AS t2 JOIN 
    T AS t1 
WHERE 
    t1.app_platform = t2.app_platform1 
    AND t2.MaxPostCreated= t1.post_created 

順便說一句,我們的團隊實際上是正在開發的工具嘗試自動幫助用戶編寫查詢,以及用戶可以爲該工具提供輸入輸出示例,該工具將生成一個查詢。 (查詢的第一部分實際上是由工具生成的!我們原型的鏈接是https://github.com/Mestway/Scythe

希望這能幫助你。 :)