【问题标题】:How to insert multiple rows based on a query?如何根据查询插入多行?
【发布时间】:2010-11-23 14:21:41
【问题描述】:

我正在开发一个具有文件夹、组和权限的系统。权限决定了不同组可以在每个文件夹中执行的操作。因此,每当我创建一个新组时,我都想在每个文件夹的权限表中添加一条记录,描述新组在该文件夹中可以做什么。

目前我只是循环遍历系统中的所有文件夹并为每个文件夹添加权限记录:

group = Group.create(params)

Folder.all.each do |folder|
  Permission.create! do |permission|
    permission.folder = folder
    permission.group = group
    permission.can_create = true
    permission.can_read = true
    permission.can_update = true
    permission.can_delete = true
  end
end

我不喜欢每次创建新组时都必须遍历所有记录的事实。所以基本上我正在寻找一种优雅的方式来使用 ActiveRecord 执行以下 SQL。

INSERT INTO permissions (folder_id, group_id, can_creat, can_read, can_update, can_delete)
SELECT id, #{group.id}, true, true, true, true
FROM folders

我想我可以使用find_by_sql 运行上述查询,但感觉不对,因为我是INSERTing,而不是SELECTing

或者我应该忘记这一点并像上面的示例一样继续循环浏览我的文件夹记录吗?

提前致谢。

【问题讨论】:

    标签: mysql ruby-on-rails activerecord ruby-on-rails-3


    【解决方案1】:

    你要找的是ar-extensions


    使用安装gem

    sudo gem install ar-extensions
    

    在你的 environment.rb 中包含 gem(或者直接在你想要插入的模型中)

    require 'ar-extensions'
    

    并在一个INSERT查询中插入多条记录

    fields = [:first_name, :last_name, :email]
    data = [["glenn", "gillen", "foo@bar.com"],
           ["john", "jones", "jim@bar.com"],
           ["steve", "smith", "bar@foo.com"]]
    
    User.import fields, data
    

    您也可以使用 ActiveRecord 对象来做到这一点。

    data = [ 
             User.new(:first_name => 'glenn', :last_name => 'gillen', :email => 'foo@bar.com'),
             User.new(:first_name => 'john', :last_name => 'jones', :email => 'jim@bar.com'),
             User.new(:first_name => 'steve', :last_name => 'smith', :email => 'bar@foo.com')
           ]
    
    User.import fields, data
    

    已将 3 个新行插入到 users 表中,只需 单个查询!

    更多关于它的信息hereherehere

    【讨论】:

    • 谢谢,听起来像我要找的东西!明天我会看看它,如果它完成了我需要它做的事情,就给你赏金。
    • 这对于从 ruby​​/rails 进行大规模插入非常有用。但是,您基本上希望从另一个表中批量插入。
    • johno 似乎是对的。这似乎无法满足我上面的描述。抱歉,但看来我必须接受 johno 的回答。
    【解决方案2】:

    这就是我在 rails/activerecord 中处理自定义 sql 的方式(包括 after_create 技巧!)

    class Group < ActiveRecord::Base
      after_create :create_default_folder_permissions
    
      def create_default_folder_permissions
        sql = <<-SQL
         INSERT INTO permissions (folder_id, group_id, can_creat, can_read, can_update, can_delete)
            SELECT id, #{id}, true, true, true, true FROM folders
        SQL
        connection.execute(sql)
      end
    end
    

    但是,为每个组和每个文件夹添加权限很快就会成为瓶颈,因为您在权限表中获得了number_of_groups * number_of_folders 行。但是,如果您的查询很简单并且索引正确,则可以轻松扩展到数百万行。

    【讨论】:

    • 谢谢。我查看了 ar-extensions,你是对的:它不允许我根据查询导入记录。我会接受你的回答并给你赏金,但我还有一个问题。我希望这个应用程序可以使用不同类型的数据库,Rails 的布尔数据类型在 MySQL 中变成 tinyint(1)。所以SELECT id, #{id}, 'true', 'true', 'true', 'true' FROM folders 会失败,因为 MySQL 需要01,而不是truefalse。有什么建议吗?
    【解决方案3】:

    您是在寻找最“优雅”的做事方式,还是最快的方式?为什么不直接从activerecord 调用你的SQL 查询呢?另一种解决方案是将您的查询放入数据库函数中,并从您的网络应用程序中调用该函数。维护起来可能有点困难,但性能提升令人难以置信,尤其是当您的网络应用程序中开始有大量文件夹时。

    【讨论】:

    • 感谢您的回答。我想最简单的方法是从 ActiveRecord 调用 SQL。我之前用过find_by_sql,但是好像不太合适,因为我不是SELECTING,而是INSERTING。如果您有任何代码示例,我将不胜感激。同时我会开始一个小赏金,看看我是否能得到更多的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    • 1970-01-01
    相关资源
    最近更新 更多