【问题标题】:Using Postgres UPDATE ... FROM in Ecto without raw SQL在没有原始 SQL 的情况下在 Ecto 中使用 Postgres UPDATE ... FROM
【发布时间】:2018-08-08 17:23:46
【问题描述】:

基于 Elixir thread from last year,我能够编写一个原始 SQL 查询来使用不相关表中的值批量更新记录。但是,我希望能够使用 Ecto 生成此查询。

在下面的例子中,假设有两个表,cats 和 dogs,cats 表有一个外键(dog_id)。我想把狗和猫联系起来。

下面的代码是我如何使用 Elixir 和原始 SQL 手动执行此操作的:

cat_ids = [1,2,3] # pretend these are uuids
dog_ids = [4,5,6] # ... uuids

values =
  cat_ids
  |> Enum.zip(dog_ids)
  |> Enum.map(fn {cat_id, dog_id} ->
    "('#{cat_id}'::uuid, '#{dog_id}'::uuid)"
  end)
  |> Enum.join(", ")

sql = """
UPDATE cats as a
SET dog_id = c.dog_id
from (values #{values}) as c(cat_id, dog_id)
where c.cat_id = a.id;
"""

Repo.query(sql)

有没有办法把它移到 Repo.update_all 或使用一些片段,这样我就不用手动构建查询了?

【问题讨论】:

    标签: postgresql elixir ecto


    【解决方案1】:

    当然,您可以使用 Ecto 语法,但在我看来并没有太大的不同,您必须使用 Schema,例如在我的应用程序中,我有一个用户身份验证,这就是我们更新令牌的方式:

    def update_token(user_id, token) do
      Repo.transaction(fn ->
                from(t in UserAuthentication, where: t.user_id == ^to_string(user_id))
                |> Repo.update_all(set: [token: token])
    end
    

    UserAuthentication 架构看起来或多或少像:

    defmodule MyApp.UserAuthentication do
      use Ecto.Schema
      import Ecto.Changeset
    
      schema "user_authentication" do
        field(:user_id, :integer)
        field(:token, :string)
        timestamps()
      end
    
      def changeset(%__MODULE__{} = user, attrs) do
        user
        |> cast(attrs, [:user_id, :token])
        |> validate_required([:user_id, :token])
      end
    end
    

    这对于数据验证很有用,并且适用于您附加的任何数据库。

    【讨论】:

      猜你喜欢
      • 2016-10-27
      • 1970-01-01
      • 2015-05-26
      • 1970-01-01
      • 1970-01-01
      • 2021-03-13
      • 2020-09-07
      • 1970-01-01
      相关资源
      最近更新 更多