假设我有这两个表,为了问题的目的而简化:
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)
)
merchandises
表列出了可用的商品。 gifts
表显示用户已将商品作为礼物发送给其他用户的记录(适当的索引已到位以避免重复)。
我想要查询的是用户可以发送给其他用户的merchandises
列表,前提是这些商品之前不应该赠送。
这是一个有效的查询,但我希望我能找到一个没有嵌套查询的查询,认为由于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子句过滤掉来自两个特定用户的礼品条目,其他两个用户也可能使用相同商品(相同商品_id)赠送礼品。
答案 0 :(得分:2)
这使用左外连接,应该表现良好。
SELECT m.*
FROM merchandises m
LEFT OUTER JOIN (SELECT with_merchandise FROM gifts WHERE from_user = 'some_user_id' AND to_user = 'some_other_user_id' GROUP BY with_merchandise) g ON m.id = g.with_merchandise
WHERE g.with_merchandise IS NULL
ORDER BY m.id ASC
LIMIT 20 OFFSET 0
答案 1 :(得分:2)
即使您要求删除子查询,使用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
条款
x-connection-id