迁移查询至Ecto时,如何实现PostgreSQL默认LEFT JOIN(LEFT INNER JOIN)效果以过滤匿名帖子
解决Ecto中获取非匿名帖子的查询问题
嘿,先帮你理清一个容易混淆的概念:在PostgreSQL里,LEFT JOIN和LEFT OUTER JOIN是完全等价的——你写的原生SQL其实也会返回匿名帖子,这并不是Ecto的问题,而是对SQL连接类型的理解偏差。你想要的“仅包含非匿名帖子”的需求,其实需要的是内连接(INNER JOIN),而不是左连接。
正确的Ecto查询写法
Ecto中默认的join:操作就是INNER JOIN,刚好匹配你的需求。把left_join:换成join:即可:
nonanonymous_posts = from p in Post, join: u in User, on: p.creator_id == u.id, select: %{ id: p.id, title: p.title, body: p.body, creator_name: u.name, creator_avatar: u.avatar }
这个查询生成的SQL会是标准的INNER JOIN,只会返回那些存在对应创作者(creator_id有效且关联到users表记录)的帖子,自动排除匿名帖子。
为什么你的原写法不对?
你之前用left_join:时,Ecto生成的LEFT OUTER JOIN会保留posts表的所有记录——包括creator_id为NULL或者在users表中找不到匹配的匿名帖子,这就是结果里出现不需要内容的原因。
补充:如果一定要用左连接但过滤无匹配记录
如果你出于某些原因必须用左连接,但又要排除没有对应创作者的帖子,可以在查询里加上where条件过滤掉users表字段为NULL的记录:
nonanonymous_posts = from p in Post, left_join: u in User, on: p.creator_id == u.id, where: not is_nil(u.id), select: %{ id: p.id, title: p.title, body: p.body, creator_name: u.name, creator_avatar: u.avatar }
不过这种写法和直接用INNER JOIN效果完全一致,而且INNER JOIN的语义更贴合你的需求,可读性也更强,所以更推荐第一种写法。
内容的提问来源于stack exchange,提问作者user13528444
相关产品推荐
相关产品推荐

