Perl DBI:使用 OR 语句的绑定变量数量不均匀(需要 y 时使用 x 绑定变量调用)

Perl DBI: uneven-number of bind variables with OR Statement (called with x bind variables when y are needed)

任务定义: 使用 OR.

从两个不同的列中获取数据

问题: 在使用普通 (MySQL) 查询时,Perl DBI 会抛出异常,因为 bind variables 的数量不均匀。

让我们假设以下数据库架构:

customer    vpn_primary_ip   vpn_secondary_ip
1000        1.1.1.1          2.2.2.2
1001        3.3.3.3          NULL
1002        4.4.4.4          5.5.5.5
1003        NULL             6.6.6.6

旁注: 由于存储 ip 地址的列是不可预测的,我将搜索列 vpn_primary_ip AND vpn_secondary_ip 使用 OR 运算符。 plainSQL查询如下:

SELECT
     customer,
     vpn_primary_ip,
     vpn_secondary_ip,
 FROM
     table
 WHERE
     vpn_primary_ip IN ( '1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6' )
 OR  
     vpn_secondary_ip IN ( '1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6' );

上面的查询给出了以下(适当的)结果:

+----------+-----------------+------------------+
| customer | vpn_primary_ip  | vpn_secondary_ip |
+----------+-----------------+------------------+
|   1000   | 1.1.1.1         | 2.2.2.2          |
|   1002   | 4.4.4.4         | 5.5.5.5          |
|   1003   | NULL            | 6.6.6.6          |
+----------+-----------------+------------------+

与 Perl DBI 相同的 SQL 查询:

 my @ip_addresses = ('1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6');

 my $sth = $dbh->prepare (
     "SELECT
       customer,
       vpn_primary_ip,
       vpn_secondary_ip,
     FROM
       table
     WHERE
       vpn_primary_ip IN ( @{[join',', ('?') x @ip_addresses]} )
     OR  
       vpn_secondary_ip IN ( @{[join',', ('?') x @ip_addresses]} )"
    );

 $sth->execute(@ip_addresses);

引发以下异常:

DBD::mysql::st execute failed: called with 4 bind variables when 8 are needed at get_vpn_customers line 211, <DATA> line 1.
DBD::mysql::st execute failed: called with 4 bind variables when 8 are needed at get_vpn_customers line 211, <DATA> line 1.

让它工作的唯一想法是将@ip_addresses传递给execute方法twice:

$sth->execute(@ip_addresses, @ip_addresses);

问题: 这是正确的方法还是有另一种方法,比方说,最佳更好的做法

$sth->execute(@ip_addresses, @ip_addresses);

这是正确的做法。 DBI 只知道您向它传递了一个包含八个绑定点的 SQL 查询。因此,它需要传递给 execute() 方法的八个匹配值。

Perl、DBI 或 MySQL 无法知道绑定值是否重复。

其他可能的解决方案是 massage SQL 在 $sth->execute()

之前查询到可用状态
use strict;
use warnings;
use feature 'say';

my @ip_addresses = ('1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6');

 my $query = "
    SELECT
       customer,
       vpn_primary_ip,
       vpn_secondary_ip,
     FROM
       table
     WHERE
       vpn_primary_ip IN ( @{[join',', ('?') x @ip_addresses]} )
     OR  
       vpn_secondary_ip IN ( @{[join',', ('?') x @ip_addresses]} )
    ";

say $query;

my $ip_addresses;
my $flag = 0;

for (@ip_addresses) {
    $ip_addresses .= ', ' if $flag;
    $ip_addresses .= "'$_'";
    $flag = 1;
}

$query = "
    SELECT
       customer,
       vpn_primary_ip,
       vpn_secondary_ip,
     FROM
       table
     WHERE
       vpn_primary_ip IN ( $ip_addresses )
     OR  
       vpn_secondary_ip IN ( $ip_addresses )
    ";

say $query;

输出

SELECT
   customer,
   vpn_primary_ip,
   vpn_secondary_ip,
 FROM
   table
 WHERE
   vpn_primary_ip IN ( ?,?,?,? )
 OR
   vpn_secondary_ip IN ( ?,?,?,? )


SELECT
   customer,
   vpn_primary_ip,
   vpn_secondary_ip,
 FROM
   table
 WHERE
   vpn_primary_ip IN ( '1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6' )
 OR
   vpn_secondary_ip IN ( '1.1.1.1', '4.4.4.4', '5.5.5.5', '6.6.6.6' )