【问题标题】:How to migrate data from an associated table's column to an hstore column?如何将数据从关联表的列迁移到 hstore 列?
【发布时间】:2014-11-10 23:25:08
【问题描述】:

我正在开展一个项目,通过创建具有 localename 字段的关联 *_locales 表来完成本地化。我正在迁移它以使用 hstore 列(使用 Postgres),但我的语法不太正确。

现在的结构是这样的

table: thingy_locales
  locale :string
  name   :string
  thingy_id : integer


table: thingies
  name_translations :hstore

在迁移中,我希望将 thingy_locales 表中的所有数据移动到带有 'en' 键的 name_translations 字段中(因为目前 thingy_locales 表中只有“en”语言环境。)

所以我试过了

execute "UPDATE thingies t SET name_translations=(select (\"'en'\" => \"'|name|'\")::hstore from thingy_locales where thingy_id = t.id);"

但这给了我

PG::UndefinedColumn: ERROR:  column "'en'" does not exist
LINE 1: ...ort_categories loc SET name_translations=(select ("'en'" => ...
                                                             ^

我做错了什么?

【问题讨论】:

    标签: ruby-on-rails postgresql hstore


    【解决方案1】:

    我不知道执行此操作的自动 SQL 命令,但您可能想要进行多次迁移:

    • 将 hstore 列添加到thingies
    • 遍历所有thingy_locales,将它们读入一个散列/散列。然后做Thingy.create!(name_translations: {'en' => hash})
    • 删除thingy_locales

    Rails 中的迁移可以包含任意代码。由于这是您将要转换数据的实例,因此在 Ruby 中执行此操作可能是您最安全的选择。

    如果速度是一个问题,那么您可能需要优化 SQL 查询,但坦率地说,如果您不担心速度,请不要为难自己。

    【讨论】:

    • 谢谢,这不是一个坏主意。我会看看一些 PostGres 天才会想出什么,因为在我的情况下,有一个度量标准的湿数据,所以速度很重要。
    【解决方案2】:

    其实只要再看一遍你的代码,假设你有这个关联:

    class Thingy
      has_many :thingy_locales
    end
    
    class ThingyLocale
      belongs_to :thingy
    end
    

    看起来你想做这样的事情:

    Thingy.all.each do |thingy|
      name = thingy.thingy_locales.where(locale: 'en').first.select(:name)
      thingy.name_translations = {'en' => name}
      thingy.save!
    end
    

    【讨论】:

    • 是的-应该可以。 (我刚刚做了一个小模组,就像在 Locale 模型中 locale:name 配对是独一无二的)
    【解决方案3】:

    好的,我开始工作了。

    execute "UPDATE thingies t SET name_translations=hstore('en', (select name from thingy_locales where thingy_id = t.id));"
    

    完美地完成了这项工作

    【讨论】:

      【解决方案4】:

      不要试图通过 Ruby 处理大量数据,而是在数据库内部进行。立即想到两种方法:

      1. 在 UPDATE 中使用相关子查询:

        connection.execute(%q{
          update thingies
          set name_translations = (
            select hstore(array_agg(locale), array_agg(name))
            from thingy_locales
            where thingy_id = thingies.id
          )
        })
        
      2. 在 UPDATE 中加入派生表:

        connection.execute(%q{
          update thingies
          set name_translations = dt.h
          from (
            select hstore(array_agg(locale), array_agg(name)) as h, thingy_id
            from thingy_locales
            group by thingy_id
          ) as dt
          where id = dt.thingy_id
        })
        

      两者的核心是使用hstore(text[], text[]) function构建hstorearray_agg function构建hstore(text[], text[])想要的键值数组。

      不要害怕在迁移中将 SQL 放入 connection.execute 调用中。在 Rails 应用程序中,假装你的数据库太笨,不能做任何有趣的事情在意识形态上可能是纯粹的,但这是一种非生产性和不专业的态度。从长远来看,通过学习 SQL 和数据库的工作原理,您会得到更好的服务。

      【讨论】:

      • 完全同意你的观点 mu-is-too-short 我只是想进行快速的 n'dirty hack,但如果数据集足够大,最好还是使用 SQL。跨度>
      猜你喜欢
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      • 2016-10-25
      • 1970-01-01
      • 2019-05-06
      • 2020-12-11
      相关资源
      最近更新 更多