SQLSRV 使用数组作为 UPDATE 语句中的 IN 子句
Posted
技术标签:
【中文标题】SQLSRV 使用数组作为 UPDATE 语句中的 IN 子句【英文标题】:SQLSRV using an array for the IN clause in the UPDATE statement 【发布时间】:2021-02-14 23:06:23 【问题描述】:我想更新一个表,其中列 user_id
具有值,存储在一个数组中,但我收到此错误:
数组([0] => 数组([0] => 42S22 [SQLSTATE] => 42S22 [1] => 207 [代码] => 207 [2] => [Microsoft][ODBC Driver 17 for SQL Server][SQL 服务器]列名“数组”无效。 [消息] => [微软][ODBC 用于 SQL Server 的驱动程序 17][SQL Server]列名“数组”无效。 ))
这是我的代码:
$sql = "
SELECT usuario_id
FROM control_asistencias
WHERE
ano=".$ano." and
mes=".$mes." and
dia".$dia."='T' and
comida_habitual ='T'
";
$stmt = sqlsrv_query( $conn, $sql);
if( $stmt === false )
die( print_r( sqlsrv_errors(), true) );
$usuarios_comida_habitual = array();
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
array_push($usuarios_comida_habitual,$row['usuario_id']);
// Una vez que tenemos los usuarios Que han fichado para ese dia hacemos un Update
$sql_update = "
UPDATE VLD_PRESENCIA
SET VLD_PRESENCIA_DIA".$dia." = 'T'
WHERE
VLD_PRESENCIA_CODUSUARIO IN (".$usuarios_comida_habitual.") AND
VLD_PRESENCIA_COMIDA_HABITUAL = 'T'
";
$stmt2 = sqlsrv_query( $conn2, $sql_update);
if( $stmt2 === false )
die( print_r( sqlsrv_errors(), true) );
else
echo 'eureka';
有没有可能是数组的传递方式不对?或者是否可以设置我想要实现 userid
应该在该数组中的条件?
我找到了这个
array_walk($usuarios_comida_habitual , 'intval');
$ids = implode(',', $usuarios_comida_habitual);
我在生成 $sql_update 之前执行此操作
【问题讨论】:
如果您认为这个或任何其他答案是您问题的最佳解决方案,您可以accept它。只能接受一个答案。 【参考方案1】:虽然IN
子句使用数组已经有类似answer,你可以尝试使用sqlsrv_prepare()\sqlsrv_execute()
组合来准备一个语句并多次执行。但在这两种情况下,您都需要考虑以下几点:
sys.columns
系统目录视图检查生成的名称,以防止可能的SQL注入问题。
请注意,您的错误原因是您正在尝试构建一个连接字符串文字和 php 数组的 SQL 语句。
以下示例基于您的代码并使用参数化查询,是您问题的可能解决方案:
<?php
// SELECT statement
$sql = "
SELECT usuario_id
FROM control_asistencias
WHERE ano = ? AND mes = ? AND dia".$dia." = 'T' AND comida_habitual = 'T'
";
$params = array($ano, $mes);
$stmt = sqlsrv_query($conn, $sql, $params);
if ( $stmt === false )
die( print_r( sqlsrv_errors(), true) );
$usuarios_comida_habitual = array();
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
$usuarios_comida_habitual[] = $row['usuario_id'];
// Multiple UPDATE statements
$sql = "
UPDATE VLD_PRESENCIA
SET VLD_PRESENCIA_DIA".$dia." = 'T'
WHERE
VLD_PRESENCIA_CODUSUARIO = ? AND
VLD_PRESENCIA_COMIDA_HABITUAL = 'T'
";
$usuario = 0;
$params2 = array(&$usuario);
$stmt2 = sqlsrv_prepare($conn2, $sql, $params2);
if ( $stmt2 === false )
die( print_r( sqlsrv_errors(), true) );
foreach ($usuarios_comida_habitual as $usuario)
if (sqlsrv_execute($stmt2) === false )
die( print_r( sqlsrv_errors(), true) );
else
echo 'eureka';
?>
如果要执行单个UPDATE
语句,可以选择以下方法,但同样使用参数化语句:
<?php
// SELECT statement
$sql = "
SELECT usuario_id
FROM control_asistencias
WHERE ano = ? AND mes = ? AND dia".$dia." = 'T' AND comida_habitual = 'T'
";
$params = array($ano, $mes);
$stmt = sqlsrv_query($conn, $sql, $params);
if ( $stmt === false )
die( print_r( sqlsrv_errors(), true) );
$usuarios_comida_habitual = array();
while ( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) )
$usuarios_comida_habitual[] = $row['usuario_id'];
// Single UPDATE statement
$usuarios_placeholders = substr(str_repeat(',?', count($usuarios_comida_habitual)), 1);
$sql = "
UPDATE VLD_PRESENCIA
SET VLD_PRESENCIA_DIA".$dia." = 'T'
WHERE
VLD_PRESENCIA_CODUSUARIO IN (".$usuarios_placeholders.") AND
VLD_PRESENCIA_COMIDA_HABITUAL = 'T'
";
$stmt2 = sqlsrv_query($conn2, $sql, $usuarios_comida_habitual);
if ( $stmt2 === false )
die( print_r( sqlsrv_errors(), true) );
else
echo 'eureka';
?>
【讨论】:
【参考方案2】:考虑一个没有任何循环的 SQL 查询,因为 IN
支持子查询。由于连接跨不同的服务器运行,请考虑将OPENROWSET
替换为ad hoc queries。相应地调整 ODBC 连接字符串参数和 [database].[schema]
标识符。 (注意:默认架构是dbo
)。
$sql = "UPDATE VLD_PRESENCIA
SET VLD_PRESENCIA_DIA".$dia." = 'T'
WHERE VLD_PRESENCIA_CODUSUARIO
IN (SELECT sub.usuario_id
FROM OPENROWSET('SQLNCLI',
'DRIVER=SQL Server;SERVER=ServerName;UID=userID;PWD=password',
'SELECT * FROM [database].[schema].control_asistencias') sub
WHERE sub.ano = ?
AND sub.mes = ?
AND sub.dia".$dia." = 'T'
AND sub.comida_habitual = 'T')
AND VLD_PRESENCIA_COMIDA_HABITUAL = 'T'";
$prms = array($ano, $mes);
$stmt = sqlsrv_query($conn, $sql, $prms);
if( $stmt === false )
die( print_r( sqlsrv_errors(), true));
【讨论】:
看起来很合理,如果$conn
和$conn2
保持到同一个服务器和数据库的连接。
@Zhorov,好收获!我调整了 SQL,假设两个连接都指向同一个服务器,不一定是同一个数据库。
这是一个测试,但是连接在不同的服务器上
然后,考虑ad hoc queries从不同的后端查询。编辑节目OPENROWSET
。以上是关于SQLSRV 使用数组作为 UPDATE 语句中的 IN 子句的主要内容,如果未能解决你的问题,请参考以下文章
在 PHP 中使用带有 sqlsrv_query 函数的临时表不会产生任何结果
SQL Server Driver for PHP之sqlsrv相关函数
我应该在 Oracle Update 语句中使用 Too Many Rows Error 作为例外子句吗?