我insert
在PHPfor
循环中生成一条SQL语句。
生成的SQL字符串是大量的单个SQL语句,如下所示:
INSERT INTO tbl VALUES(1,2,3);
INSERT INTO tbl VALUES(4,5,6);
INSERT INTO tbl VALUES(7,8,9);
等等…
然后我执行:
$InsertResult = sqlsrv_query($conn, $InsertSQL);
问题在于仅执行前312条语句,而不执行完整的2082行(表中仅插入312行)。
当我将$InsertSQL
变量输出到JavaScript控制台,然后在SSMS中手动执行它时,它可以完美工作并插入所有2082行。只有当我运行$InsertSQL
变量时sqlsrv_query
,它才能完成。
我也没有收到任何错误,查询结果返回真,如以下代码所示:
if(!$InsertResult) die('Problem with Insert query: ' . $InsertSQL);
当我搜索该问题的解决方案时,我发现(尽管PHP手册站点中未提及)sqlsrv_query
该$SQL
变量显然有一个字符串限制(大约65k个字符)。
请参阅此处的其他StackOverflow文章:
sqlsrv_query上sql变量的长度限制?
我发现这就是问题所在,因此创建了一个较短版本的字符串(通过仅添加我实际想要导入的列值)。但是,这个短得多的版本仍然只插入前312行!所以现在看来这与最大字符串长度无关。实际上,如果是这样,我应该只能得到大约250行(在执行250条语句后,我大约需要65k个字符)。
我也可以insert
单独执行每个语句,但是当然这要花费更长的时间。在我的测试中,以这种方式执行此操作大约需要90
s,而在SMSS中手动运行组合语句仅需40 s。
请注意,我也研究了SQL Server的批量插入,但是无法将文件发送到安装SQL Server的计算机上(SQL
Server和Web服务器位于单独的计算机上)。据我了解,这消除了这种可能性。
非常感谢任何帮助,因为我什至无法弄清楚是什么限制了我,没关系解决它,我讨厌一次只能执行一行。
说明:
发布在GitHub上的该驱动程序存在一个有关执行大型SQL语句的已知问题。提供的解决方案的一部分是以下说明:
似乎在执行大批SQL语句时,Microsoft SQL Server可能会在执行该批处理中的所有语句之前停止处理该批处理。 处理批处理的结果时,SQL
Server用该批处理创建的结果集填充连接的输出缓冲区。这些结果集必须由客户端应用程序处理。如果您正在执行具有多个结果集的大批处理,则SQL
Server会填充该输出缓冲区,直到达到内部限制并且无法继续处理更多结果集。此时,控制权返回给客户端。此行为是设计使然。客户端应用应刷新所有待处理的结果集。客户端使用完所有待处理的结果集后,SQL
Server将立即执行批处理。客户端应用程序可以调用sqlsrv_next_result(),直到返回NULL。
因此,我认为SQL语句的长度没有限制,只有PHP字符串变量的大小($InsertSQL
在您的情况下)被限制为允许的最大PHP内存限制。发生这种意外行为的实际原因是这样的事实,即SQL
Server使用SET NOCOUNT OFF
(默认情况下)和大量单个INSERT
语句,将受影响的行的计数作为结果集返回(例如(1 row affected)
)。
解决方案:
我能够重现此问题(使用SQL Server 2012,PHP 7.1.12和SQL Server 4.3.0 +
9904的PHP驱动程序),并且您可以使用以下选项来解决此问题:
sqlsrv_next_result()
。SET NOCOUNT ON
在复杂的T-SQL语句中作为第一行执行,以停止SQL Server将受影响的行的计数作为结果集返回。sqlsrv_prepare()\sqlsrv_execute()
桌子:
CREATE TABLE MyTable (
Column1 int,
Column2 int,
Column3 int
)
一个复杂的语句(使用sqlsrv_query()
和sqlsrv_next_result()
):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Statement with sqlsrv_query
$sql = "";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// Clean the buffer
while (sqlsrv_next_result($stmt) != null){};
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
一个复杂的语句(使用sqlsrv_query()
和SET NOCOUNT ON
):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
// Statement with sqlsrv_query
$sql = "SET NOCOUNT ON;";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
参数化的语句(使用sqlsrv_prepare()
和sqlsrv_execute()
):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
$sql = "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (?, ?, ?);";
$value1 = 0;
$value2 = 0;
$value3 = 0;
$params = array(&$value1, &$value2, &$value3);
$stmt = sqlsrv_prepare($con, $sql, $params);
if ($stmt === false ) {
echo "Error (sqlsrv_prepare): ".print_r(sqlsrv_errors(), true);
exit;
}
for ($i = 1; $i <= 1000; $i++) {
$value1 = $i;
$value2 = 0;
$value3 = 0;
$result = sqlsrv_execute($stmt);
if ($result === false) {
echo "Error (sqlsrv_execute): ".print_r(sqlsrv_errors(), true);
exit;
}
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
我正在将select查询传递给准备好的语句以获取记录列表。问题是,如果我将查询追加到insert或truncate table中,那么准备好的语句将执行所有查询。示例 如何限制sql查询只执行select查询,或者在Java中一次至少只执行一个查询。
问题内容: 我想知道是否可以使用JDBC执行类似的操作,因为即使在MySQL查询浏览器中,它当前也提供了异常。 虽然我确实意识到可以拆分SQL查询字符串并执行两次语句,但是我想知道是否有一次性的方法。 问题答案: 我想知道是否可以使用JDBC执行类似的操作。 对的,这是可能的。据我所知,有两种方法。他们是 通过设置数据库连接属性以允许多个查询,默认情况下用分号分隔。 通过调用返回隐式游标的存储过程
我想知道是否可以在一个准备好的语句中执行多个SQL查询。这是我要执行的第一个查询:
问题内容: 我想在hibernateHql的同一查询中执行多个更新语句。如下所示: 在同一调用中,我想更新表1中的记录并从表2中删除记录。 那可能吗? 问题答案: 简而言之,您所看到的就像是JDBC中的批处理。Hichnate没有为批量更新查询提供Thich,并且我怀疑是否会为Hibernate考虑它。 根据我过去的经验,HQL的批处理功能在现实生活中很少有用。在SQL + JDBC中有用但在HQ
问题内容: 如何将这些多个查询合并为一个(可以吗?) 顺便问一下,如果在完成所有查询后再执行mysql_close($ db),那会更好吗? 问题答案: 传递到作为第五个参数。 例: 当您使用mysql_fetch_ *或mysql_num_rows或mysql_affected_rows时,仅第一条语句有效。 例如,以下代码,第一个语句为INSERT,则无法执行mysql_num_rows和my