我在弄清楚如何构造SQL查询时遇到了麻烦.假设我们有一个User表和一个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)
解决方法:
在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;
>使用左联接时,不能将其与左侧表的WHERE条件结合使用.这会强制将LEFT JOIN转换为普通的[INNER] JOIN(并可能从您不想删除的结果中删除行).将此类条件拉入join子句.
按照我的方式,结果是包括没有宠物的用户-与您的查询存根相反.
> ORDER BY子句中的其他id列应该打破非唯一名称之间的可能联系.
>切勿使用reserved word like user
作为标识符.
>按照您的命名约定进行工作. id或name是可怕的,非描述性的选择,即使某些ORM提出了这种废话.正如您在查询中看到的那样,当连接几个表时,这会导致复杂化,这是您在sql中所做的.
首先应该是pet_id,pet,user_id,用户名等.
>使用适当的命名约定,我们可以仅在子查询中选择*.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。