2014-07-07 40 views
3

我無法弄清楚如何構建SQL查詢。假設我們有一個User表和一個Pet表。每個用戶可以有許多寵物,並且Pet有一個品種欄。使用外連接和限制每個父級子記錄的SQL查詢

User: 

id | name 
______|________________ 
1  | Foo 
2  | Bar 

Pet: 

id | owner_id | name | breed | 
______|________________|____________|_____________| 
1  |  1  | Fido  | poodle  | 
2  |  2  | Fluffy | siamese | 

的最終目標是提供一個查詢,會給我所有的寵物在給定where子句匹配,同時允許使用sortlimit參數每個用戶。所以限制每個用戶的寵物說5並按名稱排序的能力。

我正在爲ORM動態構建這些查詢,所以我需要一個在MySQL和Postgresql中工作的解決方案(雖然它可以是兩個不同的查詢)。

我已經試過這樣的事情不工作:

SELECT "user"."id", "user"."name", "pet"."id", "pet"."owner_id", "pet"."name", 
    "pet"."breed" 
FROM "user" 
LEFT JOIN "pet" ON "user"."id" = "pet"."owner_id" 
WHERE "pet"."id" IN 
    (SELECT "pet"."id" FROM "pet" WHERE "pet"."breed" = 'poodle' LIMIT 5) 
+0

因此,這是你的RDBMS? MySQL或Postgres?究竟是哪個版本? –

+0

這些似乎是引號。 – Strawberry

+1

嗯,這是一個ORM,所以我最終需要一些適用於任何SQL數據庫的東西,但現在我只關注讓MySQL和PostgreSQL工作。相同的查詢不需要用於兩個數據庫。我可以做一個MySQL版本和一個Postgresql版本。至於哪個版本的postgresql或mysql,我會說我可以限制它到最新的穩定版本。 – particlebanana

回答

4

的Postgres(8.4或更高版本),在子查詢中使用window function row_number()

SELECT user_id, user_name, pet_id, owner_id, pet_name, breed 
FROM (
    SELECT u.id AS user_id, u.name AS user_name 
     , p.id AS pet_id, owner_id, p.name AS pet_name, breed 
     , row_number() OVER (PARTITION BY u.id ORDER BY p.name, pet_id) AS rn 
    FROM "user" u 
    LEFT JOIN pet p ON p.owner_id = u.id 
        AND p.breed = 'poodle' 
    ) sub 
WHERE rn <= 5 
ORDER BY user_name, user_id, pet_name, pet_id; 
  • 當使用LEFT JOIN,你不能結合起來,與在WHERE條件離開表。強行將LEFT JOIN轉換爲普通[INNER] JOIN(並可能從不想刪除的結果中刪除行)。將這些條件引入連接子句。
    我的方式,沒有寵物的用戶包含在結果中 - 而不是你的查詢存根。

  • ORDER BY子句中的附加id列應該打破非唯一名稱之間的可能聯繫。

  • 千萬不要使用reserved word like user作爲標識符。

  • 處理您的命名約定。 idname可怕的,非描述性的選擇,即使有些ORM提出這個廢話。正如你在查詢中看到的那樣,當加入幾個表時,它會導致複雜性,這是你在SQL中做的
    應該像pet_id,pet,user_id,username等東西開始。

  • 使用適當的命名約定,我們可以在子查詢中只需SELECT *

MySQL不支持窗口的功能,也有煩躁的替代品......

0
SELECT user.id, user.name, pet.id, pet.name, pet.breed, pet.owner_id, 
    SUBSTRING_INDEX(group_concat(pet.owner_id order by pet.owner_id DESC), ',', 5) 
    FROM user 
    LEFT JOIN pet on user.id = pet.owner_id GROUP BY user.id 

以上是粗糙/未經測試,但this source has exactly what you need,請參閱步驟還你不需要任何這些「 。的