【问题标题】:Paginating union_all query in Ecto Elixir在 Ecto Elixir 中分页 union_all 查询
【发布时间】:2021-08-26 21:46:33
【问题描述】:

我有 3 个表,我正在尝试对其进行 UNION_ALL 查询。这是查询。

compares =
  Compare
  |> join(:left, [comp], u in assoc(comp, :user))
  |> join(:left, [comp], c in assoc(comp, :camera))
  |> select([comp, u, c], %{
    title: comp.name,
    exid: comp.exid,
    table: "compares",
    requested_by: u.email,
    status: comp.status,
    camera_id: c.exid,
    created_at: comp.inserted_at
  })

timelapses =
  Timelapse
  |> join(:left, [tl], u in assoc(tl, :user))
  |> join(:left, [tl], c in assoc(tl, :camera))
  |> select([tl, u, c], %{
    title: tl.title,
    exid: tl.exid,
    table: "timelapses",
    requested_by: u.email,
    status: tl.status,
    camera_id: c.exid,
    created_at: tl.inserted_at
  })

Archive
|> join(:left, [a], u in assoc(a, :user))
|> join(:left, [a], c in assoc(a, :camera))
|> select([a, u, c], %{
  title: a.title,
  exid: a.exid,
  table: "archives",
  requested_by: u.email,
  status: a.status,
  camera_id: c.exid,
  created_at: a.created_at
})
|> union_all(^compares)
|> union_all(^timelapses)

这给了我所有的结果,但是由于数据很多,我想对其进行分页,我尝试使用scrivener_ecto,但由于出现这样的错误而失败

* (Postgrex.Error) ERROR 42601 (syntax_error) each UNION query must have the same number of columns 

    query: SELECT count('*') FROM "archives" AS a0 LEFT OUTER JOIN "users" AS u1 ON u1."id" = a0."requested_by" LEFT OUTER JOIN "cameras" AS c2 ON c2."id" = a0."camera_id" UNION ALL (SELECT c0."name", c0."exid", 'compares', u1."email", c0."status", c2."exid", c0."inserted_at" FROM "compares" AS c0 LEFT OUTER JOIN "users" AS u1 ON u1."id" = c0."requested_by" LEFT OUTER JOIN "cameras" AS c2 ON c2."id" = c0."camera_id") UNION ALL (SELECT t0."title", t0."exid", 'timelapses', u1."email", t0."status", c2."exid", t0."inserted_at" FROM "timelapses" AS t0 LEFT OUTER JOIN "users" AS u1 ON u1."id" = t0."user_id" LEFT OUTER JOIN "cameras" AS c2 ON c2."id" = t0."camera_id")
    (ecto_sql 3.6.1) lib/ecto/adapters/sql.ex:749: Ecto.A

是否有可能对union_all 查询应用分页以获得此类数据

%{
  from: 1,
  items: [],
  limit: 50,
  page: 1,
  to: 50,
  total: 3618
}

任何帮助将不胜感激,如果您在查询中看到任何令人担忧的内容或可以更改为更好的内容,请同时提出建议。谢谢。

【问题讨论】:

    标签: elixir ecto


    【解决方案1】:

    问题在于这个查询:

    SELECT count('*') FROM "archives" AS a0 LEFT OUTER JOIN "users" AS u1 ON u1."id" = a0."requested_by" LEFT OUTER JOIN "cameras" AS c2 ON c2."id" = a0."camera_id" UNION ALL (SELECT c0."name", c0."exid", 'compares', u1."email", c0."status", c2."exid", c0."inserted_at" FROM "比较" AS c0 左外连接 "用户" AS u1 ON u1."id" = c0."requested_by" 左外连接 "cameras" AS c2 ON c2."id" = c0."camera_id") UNION ALL (SELECT t0."title", t0."exid", 'timelapses', u1."email", t0."status", c2."exid", t0."inserted_at" FROM "timelapses" AS t0 LEFT OUTER JOIN "users " AS u1 ON u1."id" = t0."user_id" LEFT OUTER JOIN "cameras" AS c2 ON c2."id" = t0."camera_id")

    如您所见,第一个查询正在尝试获取计数,而最后两个查询正在尝试获取字段,并且由 UNION ALL 子句连接的查询选择的字段不匹配。形成的查询不正确。

    如果您使用的是scrivener_ecto 库,问题肯定出在其中。

    为了更清楚地说明这一点,大多数分页库通过了解从数据库中获取的确切行数来计算previous_page、@ 987654324@等要在API中返回。

    我不知道有任何 elixir 库可以处理这个问题,但这可以通过编写自定义查询来实现:

    Archive
    |> join(:left, [a], u in assoc(a, :user))
    |> join(:left, [a], c in assoc(a, :camera))
    |> select([a, u, c], %{
      title: a.title,
      exid: a.exid,
      table: "archives",
      requested_by: u.email,
      status: a.status,
      camera_id: c.exid,
      created_at: a.created_at
    })
    |> union_all(^compares)
    |> union_all(^timelapses)
    |> order_by(:created_at)
    |> limit(50)
    |> offset((page-1)*50)
    

    您将不得不期待一个额外的参数page。 您可以编写另一个查询来获取 total 参数的所有此类记录的计数。

    P.S.:除非确实需要,否则我会避免返回 total 参数的行数。当表中的行数增加时,使用如此多的连接和联合支持 count(*) 肯定会给您带来很多性能问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多