如何将 Where 子句子查询转换为 Ecto 连接?
How do I translate a Where clause subquery into an Ecto join?
我目前有两个具有 hasMany 关系的表:
customers [hasMany] items
在 items
中有一些 belongsTo
关系:
providers [belongsTo] items
statuses [belongsTo] items
types [belongsTo] items
我的目标是让 Ecto 查询 returns 列表 customers
至少有一个 items
记录,status_id
为 2 和任何其他items
这条 customers
记录有。
我还需要预加载 items
、providers
、statuses
和 types
我已在 SQL 中复制如下:
SELECT
distinct on (c0.id)
c0."id",
c0."inserted_at",
c0."updated_at",
c1."id",
c1."inserted_at",
c1."updated_at"
FROM "customers" AS c0
INNER JOIN "items" AS c1 ON c1."customer_id" = c0."id"
WHERE EXISTS (
SELECT *
FROM "items" c2
WHERE c2."customer_id" = c0."id"
AND c2.status_id = 2);
这是我当前 Ecto 查询的一些逆向工程:
Repo.all(
from(p in Customers,
inner_join: r in assoc(p, :items),
where: r.status_id == 2,
preload: [
items: r, items: :provider, items: :type, items: :status
],
)
)
这个 Ecto 查询向我提供了 status_id
为 2 的商品的客户,但它只有 returns 符合条件的商品记录。如果其中一条记录的 status_id
为 2,我希望获得与该客户关联的所有项目。
我尝试通过将子查询用作连接来实现此目的,如下所示:
Repo.all(
from(p in Customers,
inner_join: r in assoc(p, :items),
join: i in subquery(from(i in MyApp.Items, where: i.status_id == 2 )), on: p.id == i.id,
preload: [
items: r, items: :provider, items: :type, items: :status
]
)
)
然而这returns没有结果。我将非常感谢一些 Ecto 专家的任何见解。
编辑:看起来您还应该在 join: ...
中将 on: p.id == i.id,
替换为 on: p.id == i.customer_id,
像这样的东西应该按照这个文档工作 Ecto subquery
看起来我们可以通过连接过滤 status_id 为 2 的所有客户+项目,然后我们得到所有这些客户的列表,并预加载了他们的所有项目。
另请注意用于获取嵌套关联的更简单的预加载结构。
我在我的一个类似结构的数据库上测试成功,希望对你有用
import Ecto.Query
from(c in Customers,
join: i in subquery(
from(i in Items,
where: i.status_id == 2
)
),
on: i.customer_id == c.id,
preload: [items: [:provider, :type, :status]]
) |> Repo.all
我目前有两个具有 hasMany 关系的表:
customers [hasMany] items
在 items
中有一些 belongsTo
关系:
providers [belongsTo] items
statuses [belongsTo] items
types [belongsTo] items
我的目标是让 Ecto 查询 returns 列表 customers
至少有一个 items
记录,status_id
为 2 和任何其他items
这条 customers
记录有。
我还需要预加载 items
、providers
、statuses
和 types
我已在 SQL 中复制如下:
SELECT
distinct on (c0.id)
c0."id",
c0."inserted_at",
c0."updated_at",
c1."id",
c1."inserted_at",
c1."updated_at"
FROM "customers" AS c0
INNER JOIN "items" AS c1 ON c1."customer_id" = c0."id"
WHERE EXISTS (
SELECT *
FROM "items" c2
WHERE c2."customer_id" = c0."id"
AND c2.status_id = 2);
这是我当前 Ecto 查询的一些逆向工程:
Repo.all(
from(p in Customers,
inner_join: r in assoc(p, :items),
where: r.status_id == 2,
preload: [
items: r, items: :provider, items: :type, items: :status
],
)
)
这个 Ecto 查询向我提供了 status_id
为 2 的商品的客户,但它只有 returns 符合条件的商品记录。如果其中一条记录的 status_id
为 2,我希望获得与该客户关联的所有项目。
我尝试通过将子查询用作连接来实现此目的,如下所示:
Repo.all(
from(p in Customers,
inner_join: r in assoc(p, :items),
join: i in subquery(from(i in MyApp.Items, where: i.status_id == 2 )), on: p.id == i.id,
preload: [
items: r, items: :provider, items: :type, items: :status
]
)
)
然而这returns没有结果。我将非常感谢一些 Ecto 专家的任何见解。
编辑:看起来您还应该在 join: ...
on: p.id == i.id,
替换为 on: p.id == i.customer_id,
像这样的东西应该按照这个文档工作 Ecto subquery
看起来我们可以通过连接过滤 status_id 为 2 的所有客户+项目,然后我们得到所有这些客户的列表,并预加载了他们的所有项目。
另请注意用于获取嵌套关联的更简单的预加载结构。
我在我的一个类似结构的数据库上测试成功,希望对你有用
import Ecto.Query
from(c in Customers,
join: i in subquery(
from(i in Items,
where: i.status_id == 2
)
),
on: i.customer_id == c.id,
preload: [items: [:provider, :type, :status]]
) |> Repo.all