0

我正在寻找一种特定于 ruby​​ 的解决方案来使用INSERT..VALUES 语法插入多行

目前我正在生成单独的插入语句,但从数据库的角度来看,这是非常低效的。我发现了一些相关的问题,但不完全是我想要的。

示例 INSERT 语句(当前):

INSERT INTO qux SELECT 1,3,'foo';
INSERT INTO qux SELECT 4,11,'bar';
INSERT INTO qux SELECT 12,19,'baz';

使用 ruby​​ on rails 活动记录插入多条记录

上面的问题使用 ActiveRecord 来实现我想要做的事情,但我正在寻找一种纯 ruby​​ 方法。

如何使用 ruby​​ mysql2 执行事务

上述问题使用事务来实现与我的需求相似的结果。然而,这仍然不如使用一个 INSERT VALUES 语句那么有效。

示例数据:

start,end,name
1,3,foo
4,11,bar
12,19,baz

INSERT VALUES 语句(需要):

INSERT INTO qux VALUES (1,3,'foo'),(4,11,'bar'),(12,19,'baz');

任何已经存在的具有此功能的 gem/代码库?

更新:我不使用也不打算在这个特定项目中使用 ActiveRecord。我直接与 MySQL 数据库进行交互,并且很想知道我的问题的任何解决方案。一种选择可能是自己构建功能;但是我不想在这里重新发明轮子。

4

2 回答 2

0
INSERT INTO SomeTable ( Col1, Col2, Col3 )
SELECT Val1, Val2, Val3 FROM SomeOtherTable
UNION
SELECT 'MyProvidedVal1', 'MyProvidedVal2', 'MyProvidedVal3'
UNION
SELECT 'MyProvidedVal4', 'MyProvidedVal5', 'MyProvidedVal6'

来源:使用选择插入多行

于 2013-01-24T00:50:47.897 回答
0

好的,我想出了一个有点笨拙的解决方案,但它确实有效!

在 MySQL 中,制作一个简单的测试表:

CREATE TABLE `aa_test` (
  `a` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `b` varchar(256) DEFAULT NULL,
  `c` varchar(256) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=48 DEFAULT CHARSET=utf8;

在您的 ruby​​ 代码中,将您的行组合成一个大的 honkin' 数组:

values = [1, 'hi', 'there', 2, 'ho', 'there', 47, 'yo', 'buddy']

动态构建查询,具体取决于您拥有的行数:

query = "INSERT INTO aa_test (`a`, `b`, `c`) VALUES "
(values.size / 3).times {|ignore|
    query << '(?,?,?),'
}
query.chop! # remove final comma
client.prepare(query).execute(*values)

有用!至少,在irb。:-)

# mysql -h*** -u*** -p*** YourDatabaseHere -e'SELECT * FROM aa_test'
+----+------+-------+
| a  | b    | c     |
+----+------+-------+
|  1 | hi   | there |
|  2 | ho   | there |
| 47 | yo   | buddy |
+----+------+-------+

当然,您必须跟踪 values[] 中有多少字段和行。您可以将列名保存在一个数组中,并将它们插入到查询中并为循环提供除数。

这是我的应用程序中动态行数的示例。您只需要一个列名数组:

col_names = ['Date', 'Receipt_type', 'Type', 'Name', 'Item', 'Num', 'Amount', 'Source', 'Destination', 'Statement_s']
query = 'INSERT INTO sa_general_journal ('
col_names.each do |col_name|
    query << '`' << col_name << '`,'
end
query.chop!
query << ') VALUES '
(values.size / col_names.size).times {|ignore|
    query << '('
    (col_names.size).times {|ignore|
        query << '?,'
    }
    query.chop!
    query << '),'
}
query.chop!
client.prepare(query).execute(*values)

请记住,准备好的语句存在服务器端限制。max_prepared_stmt_count限制可以排队的准备好的语句的数量,以减少拒绝服务攻击。如果设置为零,则不能执行任何准备好的语句。此外,如果您正在加载 BLOBS,请记住准备好的语句数据必须在max_allowed_packet(我的服务器上为 16MB)范围内。我正在使用准备好的语句将 PDF 文件加载到 BLOB 中,这让我吃了好几次。

我来这里是为了寻找答案,但不得不自己想出一个。我知道这是一个老问题。(人们因为回答老问题而跳槽我!)但我希望这对像我一样通过搜索到达这里的人有用!

于 2020-12-14T08:11:48.913 回答