You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Ecto获取原生SQL返回的数据库值

解决Ecto原生查询结果转为键值对Map的问题

嘿,我完全懂你的困扰——写了复杂的原生SQL查询后,没法像用常规Ecto查询那样直接拿到键值对的Map结构,还要适配Phoenix模板展示,手动转换又怕麻烦对吧?别慌,这儿有两种通用又简便的方法,不用自己瞎折腾:

方法一:手动配对字段与值转Map

这是最直接的方式,利用Ecto返回结果里的columns(字段名列表)和rows(每行数值列表)来生成Map:

# 执行原生查询
results = Ecto.Adapters.SQL.query!(MyApp.Repo, "SELECT id, name, email FROM users WHERE active = $1", [true])

# 转换为键值对Map列表
map_results = Enum.map(results.rows, fn row ->
  Enum.zip(results.columns, row) |> Map.new()
end)

这样处理后,map_results里的每一项都是标准的Elixir Map,比如%{"id" => 1, "name" => "Alice", "email" => "alice@example.com"},直接就能在Phoenix模板里像遍历常规Ecto结果那样用,比如<%= for user <- @map_results do %><%= user["name"] %><% end %>。

方法二:用Ecto Schema映射结果(更规范)

如果你的原生查询返回结构固定,用Schema来映射会更靠谱,还能自动处理类型转换(比如数据库时间转Elixir的日期类型):

首先定义一个临时Schema(如果没有对应表的Schema):

defmodule MyApp.UserQueryResult do
  use Ecto.Schema

  @primary_key false  # 因为是查询结果,不需要主键
  schema "users" do
    field :id, :integer
    field :name, :string
    field :email, :string
    # 按需添加你查询返回的其他字段
  end
end

然后用Ecto的load/2方法把原生查询结果转成Schema结构体:

results = Ecto.Adapters.SQL.query!(MyApp.Repo, "SELECT id, name, email FROM users WHERE active = $1", [true])
{:ok, structured_results} = Ecto.Schema.load(MyApp.UserQueryResult, results, repo: MyApp.Repo)

这下structured_results里的每一项都是和常规Ecto查询一样的结构体,比如%MyApp.UserQueryResult{id: 1, name: "Alice", email: "alice@example.com"},在Phoenix模板里直接用user.name这种写法就行,和平时用Ecto的体验完全一致。

两种方法各有侧重:方法一灵活,适合字段不固定的复杂查询;方法二更规范,适合结构固定的场景,还能享受Ecto的类型处理能力。选哪种全看你的查询需求~

内容的提问来源于stack exchange,提问作者tajihiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 08:40:58