给定以下架构,我想计算:games_won /:games_played,将其填充到:percentage_won并按:percentage_won进行排序。如果使用select_merge并省略了“ AS”,我设法计算出该值,但是如何在中引用此计算列order_by?
schema "players" do
field :name, :string
field :games_played, :integer
field :games_won, :integer
field :percentage_won, :float, virtual: true
timestamps()
end
Run Code Online (Sandbox Code Playgroud)
我尝试了以下查询:
def list_players(sort_by, sort_order) do
query =
from(p in Player,
select_merge: %{percentage_won: fragment("(?::decimal / NULLIF(?,0)) AS ?", p.games_won, p.games_played, p.percentage_won)},
order_by: [{^sort_order, field(p, ^String.to_atom(sort_by))}])
Repo.all(query)
end
Run Code Online (Sandbox Code Playgroud)
但是打电话list_players("percentage_won", :asc)给我以下错误:
** (Ecto.QueryError) ...:28: field `percentage_won` in `select` is a virtual field in schema Player in query:
from p0 in Player,
order_by: [asc: p0.name],
select: merge(p0, %{percentage_won: fragment("(?::decimal / NULLIF(?,0)) AS ?", p0.games_won, p0.games_played, p0.percentage_won)})
Run Code Online (Sandbox Code Playgroud)
Thiago Henrique已经回答了为什么virtual在这里不起作用的问题,但是根据您的基础数据库,我想提出另一个解决方案:Generated Columns
从PostgreSQL版本12开始,生成的列在PostgreSQL中可用,并允许创建基于其他列值的列(这非常适合您的用例!)。您将获得数据库的所有优点,并且无需virtual在应用程序层中创建字段。
要将其放入数据库,可以编写原始SQL迁移,例如:
def up do
execute """
ALTER TABLE players ADD percentage_won numeric GENERATED ALWAYS AS (games_won::decimal / NULLIF(games_played,0)) STORED
"""
end
Run Code Online (Sandbox Code Playgroud)
您的架构如下所示:
schema "players" do
field :name, :string
field :games_played, :integer
field :games_won, :integer
field :percentage_won, :float
timestamps()
end
Run Code Online (Sandbox Code Playgroud)
每次您插入/更新播放器行之一时,percentage_won都会计算新值,并且也会插入/更新该值。现在,您还可以像普通列一样在ecto查询中使用该值!
| 归档时间: |
|
| 查看次数: |
115 次 |
| 最近记录: |