【问题标题】:Rails 4, single mass insert导轨 4,单质量插入
【发布时间】:2016-07-05 09:21:48
【问题描述】:

我正在尝试通过使用单个批量插入而不是多次调用 ActiveRecord 的 create 方法来导入数据来优化我的 rake 任务的性能。

这是我写的代码:

inserts = []
orders.each do |ord|
  inserts.push "('#{ord.company}', '#{ord.number}', '#{ord.line}', '#{Time.now.to_s(:db)}', '#{ord.comment}')"
end
sql = "INSERT INTO orders (company, number, line, created_at, comment) VALUES #{inserts.join(", ")}"
ActiveRecord::Base.connection.execute(sql)

问题是comment字符串可以包含'字符,所以生成的sql查询字符串如下:

INSERT INTO 订单(公司、编号、行、created_at、评论)值 ('100', '023074', '001', '2016-07-05 11:17:38', '转换 K7'), ('100', '023943', '001', '2016-07-05 11:17:38', 'BANDE PE D'AMARRAGE')

这将生成一个

PG::SyntaxError: ERROR: "AMARRAGE" 或附近的语法错误

我该如何处理?

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-4


    【解决方案1】:

    问题是您的字符串引号正在关闭 SQL 查询中的字符串值。试试escaping them

    '#{ord.comment.gsub("'"){ "\\'" }'
    

    这样,SQL 查询将包含有效的字符串。

    另外,你不应该做你想做的事。如果comment 属性包含sql 代码,可能会被注入,并对您的数据库做一些讨厌的事情。请阅读this。注意安全!

    【讨论】:

      【解决方案2】:

      请尝试以下方法。

      Order.sanitize(ord.comment)
      

      【讨论】:

        【解决方案3】:

        Postgresql 中,转义字符是 single quote。所以如果你想使用connection.execute方法批量插入数据库,那么将single quote替换为two single quotes

        这是代码示例。

        inserts = []
        orders.each do |ord|
          inserts.push "('#{ord.company}', '#{ord.number}', '#{ord.line}', '#{Time.now.to_s(:db)}', '" + ord.comment.gsub("'","''")   + "')"
        end
        sql = "INSERT INTO orders (company, number, line, created_at, comment) VALUES #{inserts.join(", ")}"
        ActiveRecord::Base.connection.execute(sql)
        

        【讨论】:

          【解决方案4】:

          我最终使用了ActiveRecord::Base.connection.quote 方法:

          inserts = []
          orders.each do |ord|
            company = ActiveRecord::Base.connection.quote(ord.company)
            number = ActiveRecord::Base.connection.quote(ord.number)
            line = ActiveRecord::Base.connection.quote(ord.line)
            comment = ActiveRecord::Base.connection.quote(ord.comment)
            inserts.push "(#{company}, #{number}, #{line}, '#{Time.now.to_s(:db)}', #{comment})"
          end
          sql = "INSERT INTO orders (company, number, line, created_at, comment) VALUES #{inserts.join(", ")}"
          ActiveRecord::Base.connection.execute(sql)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-07-03
            • 1970-01-01
            • 1970-01-01
            • 2016-03-04
            • 2018-11-17
            • 2014-04-29
            • 1970-01-01
            相关资源
            最近更新 更多