【问题标题】:dynamically create mysql columns in Rails在 Rails 中动态创建 mysql 列
【发布时间】:2017-08-02 07:09:52
【问题描述】:

我正在开发一个私有 api,它将我们的许多数据库/供应商数据统一到一个 sql 数据库中。

我们的 ESP 面临挑战,我们的营销人员总是在更改/添加新列。我们希望此应用能够随着这些列更改而扩展,并且不需要在每次更改名称或添加新属性时都对列进行按摩。

我需要使用 Rails 动态创建列列表(我们不想在 Mysql 中 100% 执行此操作,因为我们正在重命名映射中的某些列)。

table = "customer"
attrs = ["vendor_cm_name_d", "vendor_cm_email address_d", "vendor_cm_date added_d", "vendor_cm_extid_d" ]

attrs.each_with_index do |attr, i|
  connection = ActiveRecord::Base.connection
  connection.execute( "ALTER TABLE #{table}  ADD COLUMN #{attr} VARCHAR(15);"  )
  # this didnt work :-( connection.close 
end

此方法适用于单个列,但在数组中有多个元素时失败。阅读日志(粘贴在下面)似乎试图将整个语句作为一个调用运行,而不是事务性的。我尝试在每个循环结束之前添加 connection.close ,但这也不起作用。欢迎所有指针。

Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'address_d VARCHAR(15)' at line 1: ALTER TABLE customer  ADD COLUMN vendor_cm_email address_d VARCHAR(15);
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'address_d VARCHAR(15)' at line 1: ALTER TABLE customer  ADD COLUMN vendor_cm_email address_d VARCHAR(15);

【问题讨论】:

  • 这可能是一个非常糟糕的主意。为什么不转向无模式类型设计? MySQL 5.7 支持 JSON 列,这些列非常适合这类事情,但缺点是它们不能被轻松索引或操作。 Postgres 为 JSON 提供了出色的支持,您可以很容易地对其进行索引和操作,这可能值得考虑作为一个选项。还有更多像 MongoDB 这样的纯文档存储完全采用了这个概念。
  • 另一种更纯粹的 RDBMS 方法是为您的行数据创建一个键/值表对。这可能会变得非常混乱,并且通常被认为是一种反模式,但它可以让你摆脱这样的困境,你真的不知道需要容纳哪些数据。更改大型表可能会使您的服务器瘫痪,并可能导致大规模的严重服务中断。这是您不情愿地做的事情,而不是设计。
  • @tadman 是的,我同意。除了我们的数据仓库的私有 API,我永远不会在其他任何地方这样做。
  • 如果您是专门为仓储做的,Star Schema 可以简化实施。
  • 抱歉@tadman 提前提交了。升级 sql 版本或使用序列化列会破坏交易。我们对 SQL 的投资太多,不值得在这里讨论,我们需要能够逐列地通过 sql 进行查询。完全理解你的观点/方法,感谢到目前为止的笔记!

标签: mysql ruby-on-rails ruby


【解决方案1】:

您的sql 不起作用,因为列名有空格。用引号将生成的 sql 中的列名括起来。

attrs.each_with_index do |x, i|
  connection = ActiveRecord::Base.connection
  connection.execute "ALTER TABLE #{table}  ADD COLUMN \"#{x}\" VARCHAR(15);" 
# this didnt work :-( connection.close 
end

虽然我宁愿不走自己写 sql 的路。相反,您可以创建这样的服务:

class DbService < ActiveRecord::Migration
  def initialize(table_name)
    @table_name = table_name
  end
  def add_string_column(column_name)
    add_column @table_name, column_name, :string
  end
end

然后做类似的事情

service = DbService.new("customer")
attrs.each do |column_name|
  service.add_string_column(column_name)
end

【讨论】:

  • 我不敢相信我错过了。我使用 rails helper 用下划线替换空格,这显然有问题。解决。非常感谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 1970-01-01
  • 2016-05-03
  • 2018-04-14
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
相关资源
最近更新 更多