【问题标题】:Rails and Postgres - COPY from .cvs to table while skipping created_at columnRails 和 Postgres - 在跳过 created_at 列时从 .cvs 复制到表
【发布时间】:2012-10-12 20:04:07
【问题描述】:

我的客户给了我一个项目的车辆清单。我需要将它们放入我可以使用的表中,但它们当前位于 .cvs 文件中。我有 read aroundfound 一些信息,但没有什么能解决我的特殊问题。

我已经生成了一个与 .cvs 文件中的信息匹配的模型(id、year、make、model、trim),运行迁移,现在有了我需要的表。当我尝试使用 psql COPY 时出现问题。这是我读过的内容:

copy list_vehicles from '/path/to/list.csv' DELIMITERS ',' CSV;

但它给了我

ERROR:  missing data for column "created_at"

很好,所以我试试这个:

copy list_vehicles (id, year, make, model, trim)  from '/path/to/list.csv' DELIMITERS ',' CSV;

我回来了

ERROR:  null value in column "created_at" violates not-null constraint

好的,那么这应该可以工作:

copy list_vehicles (id, year, make, model, trim)  from '/path/to/list.csv' DELIMITERS ',' WITH NULL AS ' ' CSV FORCE NOT NULL created_at;

不,

ERROR:  FORCE NOT NULL column "created_at" not referenced by COPY

我不知道从这里去哪里。我正在考虑暂时取消 created_at 列,然后将其添加到另一个迁移中?任何指导将不胜感激。

谢谢

【问题讨论】:

    标签: ruby-on-rails-3 csv postgresql-9.1


    【解决方案1】:

    created_at 列在大多数情况下由 Rails 自动生成,当您运行迁移以为新模型创建表时。当您在应用程序中创建新模型对象时,它通常由 Rails 默认代码填充。

    不过,您将数据直接加载到数据库中,绕过了所有 Rails 代码。这很好,但您还需要做 Rails 所做的事情。

    我认为最简单的方法是直接从数据库中删除 created_at 和其他列,加载您的 CSV 文件,然后重新添加这些列。

    【讨论】:

    • 谢谢,我有点倾向于这种方式。我知道 rails 会这样做,我可以手动删除该列。我认为我不需要删除 updated_at 因为它可以是空白的,对吧?删除列的最佳方法是什么?有迁移吗?不确定这里的最佳做法...
    • 如果此数据加载是一次性的,您可能希望全部在 SQL 中完成。删除列,加载数据,再次添加列。如果您认为您需要偶尔执行此操作,请考虑在 Rails 应用程序中添加一些代码来为您执行此操作。
    • 截至目前,它看起来像是一个季度更新。我想我们以后会有更好的解决方案,但就目前而言,我不介意每次都重建表。现在,如果我知道这样做的最佳方式就好了……
    • 可能直接在命令行中使用 SQL 命令。见postgresql.org/docs/9.1/interactive/ddl-alter.html
    【解决方案2】:

    您还可以让 Postgres 从 STDIN 读取数据,允许您在加载数据之前对其进行修改。

    我使用类似的东西,它未经测试,但应该给你一个大纲。

    connection = ActiveRecord::Base.connection.raw_connection
    
    connection.exec("COPY #{tablename} (#{fields},created_at,updated_at) FROM STDIN")
    
    data = File.open(datafile)
    data::gets # abandon the header line (if needed)
    data.each_with_index do |line, index|
      connection.put_copy_data(line + ",,")
    end
    
    connection.put_copy_end
    
    res = connection.get_result
    if res.result_error_message
      puts "Result of COPY is: %s" % [ res.result_error_message ]
    end
    

    【讨论】:

      猜你喜欢
      • 2016-12-24
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多