2011-04-19 70 views
4

說我有2個表,一個叫做類別,一個叫做cat_pages。MYSQL加入唯一的結果行

類別表具有列ID,標題和時間戳。例如:

CREATE TABLE categories (
    id INT UNSIGNED PRIMARY KEY, 
    title VARCHAR(32), 
    `timestamp` TIMESTAMP, 
    INDEX (title) 
) Engine=InnoDB; 

的cat_pages有2列,CAT_ID和PAGE_ID:

CREATE TABLE cat_pages (
    cat_id INT UNSIGNED 
     REFERENCES categories (id) 
     ON DELETE CASCADE ON UPDATE CASCADE, 
    page_id INT UNSIGNED 
     REFERENCES pages (id) 
     ON DELETE CASCADE ON UPDATE CASCADE, 
    UNIQUE INDEX (cat_id, page_id), 
    INDEX (page_id, cat_id), 
) Engine=InnoDB; 

我想加盟與該ID的cat_pages表分類表,這樣

  1. 僅檢索category_pages表中具有id的類別
  2. 每個類別僅在結果集中顯示一次

查詢:

SELECT * FROM categories as c 
    LEFT JOIN cat_pages as p ON c.id = p.cat_id 

產生具有類別重複多次(因爲有在cat_pages表多個匹配的結果集。我需要什麼才能讓每個類別只顯示一次,而如果cat_pages表格中沒有匹配,則根本不顯示?

+0

從你的查詢中左鍵落地實現第一點 – Dalen 2011-04-19 08:05:39

+0

代碼爲王。描述表的最好方法是給出表創建語句,以及樣本數據的'INSERT'語句。你提供的'SELECT'查詢在描述你想要的內容時非常有幫助。 – outis 2011-04-19 08:20:22

回答

9

如果您不希望類別不在cat_pages中,請勿使用左連接;使用內部連接。左連接包括左表中的每一行,即使右表中沒有匹配的行(缺少的字段爲NULL值)。右連接類似,但包含右表中的所有行。一個外部聯接包括左右表中的所有行,它們將具有匹配項的行連接起來,並將沒有匹配空值的行連接起來。相反,內部連接只包含匹配的行。換句話說,左右連接是一個內連接;他們的聯盟是一個外部聯盟。 Jeff Atwood發佈了一些不錯的Venn diagrams describing joins,但應該注意的是,圓圈中的集合不是左右表格的恰當位置,而是左右表格的左右連接的結果。

爲了獲得不同的行,你可以使用一個DISTINCT修改:

SELECT DISTINCT c.* 
    FROM categories AS c 
    INNER JOIN cat_pages AS cp ON c.id = cp.cat_id 

至於SELECT * ...,請參閱「What is the reason not to use select *?

以獲得不同行的另一種方法是使用一個EXISTS條款或IN運算符,但加入可能更高性能(儘管只有EXPLAIN會告訴你一定)。只要確保你有適當的指數設置。

+0

很好的回答,DISTINCT正是我所期待的......我不知道爲什麼我沒有進行內部連接。感謝您選擇*的人。 – tgriesser 2011-04-19 08:19:39

-2

爲什麼不使用Inner Join?

SELECT * FROM categories as c INNER JOIN cat_pages as p ON c.id = p.cat_id 

或者

SELECT * FROM categories as c LEFT JOIN cat_pages as p ON c.id = p.cat_id WHERE p.cat_id IS NOT NULL 

左連接左表中選擇所有和比賽上右表。