假设我有这两个表,为了解决问题而进行了简化:
CREATE TABLE merchandises
(
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price INT NOT NULL
)
CREATE TABLE gifts
(
id BIGSERIAL NOT NULL PRIMARY KEY,
from_user VARCHAR(255) REFERENCES users(id),
to_user VARCHAR(255) REFERENCES users(id),
with_merchandise BIGINT REFERENCES merchandises(id)
)
商品
表列出了可用的商品。 gifts
表显示用户将商品作为礼物发送给另一个用户的记录(有适当的索引以避免重复)。
我想查询的是一个用户可以发送给另一个用户的商品
列表,前提是这些商品之前不应该被赠送。
这是一个可行的查询,但我希望能找到一个没有嵌套查询的查询,认为由于 POSTGRESQL 的优化器,它可能会提供更好的性能。
SELECT DISTINCT ON (m.id) m.id, m.name, m.description
FROM merchandises m
WHERE m.id NOT IN (
SELECT g.with_merchandise
FROM gifts g
WHERE g.from_user = 'some_user_id' AND g.to_user = 'some_other_user_id'
)
ORDER BY m.id ASC
LIMIT 20 OFFSET 0
在之前的尝试中,我有过这样的查询,但我发现它不起作用:
SELECT DISTINCT ON (m.id) m.id, m.name, m.description
FROM merchandises m
LEFT JOIN gifts g
ON m.id = g.with_merchandise
WHERE g.id IS NULL
OR g.from_user <> 'some_user_id' AND g.to_user <> 'some_other_user_id'
ORDER BY m.id ASC
LIMIT 20 OFFSET 0
此查询不起作用,因为即使 WHERE 子句过滤掉两个特定用户的礼物条目,其他两个用户也可能使用相同的商品(相同的 Mercury_id)赠送了礼物。
最佳答案
即使您要求删除子查询,使用 not contains
子查询可能会比 not in
运行得更快,尤其是在 not in
查询的情况下返回很多值:
SELECT m.id, m.name, m.description
FROM merchandises m
WHERE NOT EXISTS (
SELECT 1
FROM gifts g
WHERE g.with_merchandise = m.id
AND g.from_user = 'some_user_id'
AND g.to_user = 'some_other_user_id'
)
此查询可以利用 gifts(with_merchandise,from_user,to_user)
如果您仍然倾向于使用 left join
,则将 from_user
和 to_user
的条件从 where
移走到 on
子句
SELECT m.id, m.name, m.description
FROM merchandises m
LEFT JOIN gifts g ON m.id = g.with_merchandise
AND g.from_user = 'some_user_id' AND g.to_user = 'some_other_user_id'
WHERE g.id IS NULL
ORDER BY m.id ASC
LIMIT 20 OFFSET 0
关于sql - 使用 NOT IN 展平 WHERE 子句中的嵌套查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33447891/