SQL查询使用外部联接和限制每个父级的子记录

时间:2014-07-07 21:42:11

标签: mysql sql postgresql

我无法弄清楚如何构建SQL查询。我们假设我们有一个User表和一个Pet表。每个用户可以拥有许多宠物,Pet有一个品种列。

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)

2 个答案:

答案 0 :(得分: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时,您无法将其与 left 表中的WHERE条件相结合。强制将LEFT JOIN转换为普通[INNER] JOIN(并可能从您不想删除的结果中删除行)。将这些条件拉入连接条款 我拥有它的方式,没有宠物的用户包含在结果中 - 而不是查询存根。

  • ORDER BY子句中的其他id列应该打破非唯一名称之间的可能联系。

  • 切勿使用reserved word like user作为标识符。

  • 处理您的命名约定。 idname可怕的,非描述性选择,即使某些ORM表明这是无意义的。正如您在查询中看到的那样,在连接几个表时会导致复杂化,这些表是您在SQL中执行的操作。 首先应该是pet_idpetuser_idusername等。

  • 通过适当的命名约定,我们可以在子查询中SELECT *

MySQL不支持窗口函数,有烦躁的替代品......

答案 1 :(得分: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,请参阅第4步。您也不需要其中任何一个&#34; &#39; S