【问题标题】:How to join and filter between 3 tables with ecto query expressions如何使用 ecto 查询表达式在 3 个表之间加入和过滤
【发布时间】:2019-12-23 06:30:31
【问题描述】:

我有 3 个架构:PostAuthorAssistant

Postbelongs_to :author

Author has_many :posts 和 has_one :assistant

Assistantbelongs_to :author

我想构建一个只获取Posts 的查询,其中Author 具有Assistant

到目前为止,我只能将Author 加入Post。我不知道如何根据AuthorAssistant 的存在来查询Posts。

Post
|> join(:inner, [p], a in assoc(p, :author))
|> Repo.all()

编辑 1

我想我已经取得了一些进展,这个查询似乎正在处理我现在在数据库中的几条记录,但不确定它是否是传统方式。

Post
|> join(:inner, [p], a in assoc(p, :author), as: :author)
|> join(:left, [author: a], asst in assoc(a, :assistant), as: :assistant)
|> where([assistant: asst], not is_nil(asst.id)))
|> Repo.all()

【问题讨论】:

    标签: postgresql elixir ecto


    【解决方案1】:

    在这种特殊情况下,这可能有点矫枉过正,但将此类查询解耦到 subqueries 总是更容易。

    authors_with_assistants =
      from a in Author, where: not is_nil(a.assistant_id)
    

    authors_with_assistants =
      from a in Author,
      left_join: asst in assoc(a, :assistant)
    

    posts =
      from p in Post,
        join: a in subquery(authors_with_assistants),
        on: p.author_id == a.id
    
    Repo.all(posts)
    

    此外,在后者上使用条件链接也可以工作(这意味着您在 Edit1 部分中的查询看起来不错。)

    【讨论】:

    • 感谢您的帮助。 “authors”表没有assistant_id 列,但“assistants”表有一个author_id 列。
    • 然后做一个子查询作为内连接authorsassistants,它在方法上没有太大区别。这正是我建议解耦的原因:无论您如何构建子查询,结果查询都保持不变。
    【解决方案2】:

    我认为这种情况下不需要左连接。您应该能够对所有表进行内部联接,因为内部联接将指示存在助手并排除在没有助手的情况下获得作者的任何可能性。你应该可以这样写:

    query = from(p in Post,
      join: a in Author,
      on: a.id == p.author_id,
      join: ast in Assistant,
      on: ast.author_id == a.id,
      # See notes below about the distinct
      distinct: p.id
    )
    
    Repo.all(query)
    

    因为您在所有表上进行了内部联接,所以它表明帖子必须有作者,并且作者必须有助手才能成为此查询中的结果行。如果你想做一些事情,比如找出作者没有助手的所有帖子,你会想离开加入。

    注意distinct

    如果您在数据库中为某个作者分配了多个助手(这表明数据不正确)并且结果集中的帖子将被重复,我会放置 distinct 子句。这是因为has_one 关系只是一个受约束的has_many。如果assistants 表中的author_id 列上有唯一索引,则不需要 distinct 子句。如果您没有唯一索引,则可以在迁移中编写:

    create unique_index("assistants", :author_id)
    

    您可能应该为所有has_one 关系执行此操作。

    干杯!

    【讨论】:

      猜你喜欢
      • 2023-04-09
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-04
      • 2020-08-29
      • 1970-01-01
      相关资源
      最近更新 更多