我无法弄清楚如何构建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
子句匹配的所有宠物,同时允许使用sort
和limit
参数。因此,能够限制每个用户的宠物说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 :(得分: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
作为标识符。
处理您的命名约定。 id
或name
是可怕的,非描述性选择,即使某些ORM表明这是无意义的。正如您在查询中看到的那样,在连接几个表时会导致复杂化,这些表是您在SQL中执行的操作。
首先应该是pet_id
,pet
,user_id
,username
等。
通过适当的命名约定,我们可以在子查询中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