使用NOT IN

时间:2015-10-31 03:56:43

标签: sql postgresql

假设我有这两个表,为了问题的目的而简化:

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)赠送礼品。

2 个答案:

答案 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_userwhere的条件从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