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

Why do Perl's DBI placeholders break for negative number MySQL queries?

我有两个 MySQL 数据库,numbers1 和 numbers2,它们都是这样的:

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

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

此代码成功地为 numbers2 打印“number is: -5”,但为 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";

该代码对 numbers1 和 numbers2 都适用。

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

请注意,这与目前遇到的问题相同unsolved 2007 PerlMonks thread

因为MySQL在做字符串比较,虽然数字-5小于数字-3,但字符串“-5”大于字符串“-3”。您遇到的行为是预料之中的,它不是您声称的 "broken"。

使用占位符时,绑定值被类型转换为字符串,因为列类型是 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)";