为什么Perl的DBI占位符会因负数MySQL查询而中断?

时间:2015-05-26 22:50:05

标签: mysql perl placeholder dbi

我有两个MySQL数据库,number1和numbers2,两者都是这样的:

+--------+
| number |
+--------+
|     -5 |
+--------+

但是,numbers1有一个VARCHAR列,而numbers2有一个INT列。

此代码成功打印"数字为:-5"对于numbers2,但对于numbers1:

失败
my $high_number = -2;
my $sql = "select * from numbers1 where number < ?";
my $sth = $dbh->prepare($sql);
$sth->execute($high_number);
while (my @row = $sth->fetchrow_array){
        print "number is: $row[0]\n";
}

但是,如果我删除占位符并直接替换:

my $sql = "select * from numbers1 where number < $high_number";

代码对number1和number2都很好。

因此,罪魁祸首必须是DBI的占位符,它以某种方式打破了负数的mysql查询(奇怪的正数工作得很好!)为什么DBI占位符在这里打破负数?

请注意,这与今天unsolved 2007 PerlMonks thread中遇到的问题相同。

1 个答案:

答案 0 :(得分:6)

这是因为MySQL正在进行字符串比较,字符串“-5”大于字符串“-3”,即使数字-5小于数字-3。您正在经历的行为是预期的,并不像您声称的那样“破坏”。

使用占位符时,绑定值是字符串的字符串,因为列类型是varchar。没有占位符的查询在右侧有一个整数。换句话说,下面的两个查询可以理解地产生不同的结果:

select * from numbers1 where number < '$high_number';
select * from numbers1 where number < $high_number;

如果你真的想这样做,并且想要使用占位符,你可以使用显式类型转换:

my $sql = "SELECT * FROM numbers1 WHERE 
           CAST(number AS SIGNED INTEGER) < CAST(? AS SIGNED INTEGER)";