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' )
任务定义: 使用 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' )