使用MySQL INSERT VALUES语法插入多行

时间:2013-01-22 21:26:27

标签: mysql ruby mysql2

我正在寻找一种特定于ruby的解决方案,使用INSERT..VALUES syntax

插入多行

目前我正在生成单独的insert语句,但从数据库的角度来看这是非常低效的。我找到了一些相关的问题,但不完全是我正在寻找的。

示例INSERT语句(当前):

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

INSERT multiple records using ruby on rails active record

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

how do I perform transactions with 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 / codebase?

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

2 个答案:

答案 0 :(得分:0)

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

来源:Insert multiple rows using select

答案 1 :(得分: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 |
+----+------+-------+

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

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

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中,这让我感到有些困惑。

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