假设我正在使用以下内容查询表:
$dbh->selectrow_hashref('SELECT id, name FROM foos WHERE name = "bar"');
当然,id
将是一个整数,但生成的hashref将在内部存储一个值作为Perl PV而不是IV。反过来,当将数据序列化为例如JSON时,这将产生不希望的结果。
当然,可以手动调用值0+
,但有没有办法让DBI
自动将其存储为实际整数,而不仅仅是一个看起来像数字的字符串?同样,DBIx::Class
和朋友可以解决这个问题,但DBI
寂寞呢?
答案 0 :(得分:7)
根据您的数据库驱动程序, * 可以使用bind_col
中的类型提示:
use DBI qw(:sql_types);
...
my $sth = $dbh->prepare('SELECT id, name FROM foos WHERE name = "bar"');
$sth->execute;
$sth->bind_col(1, undef, {
TYPE => SQL_INTEGER,
StrictlyTyped => 1,
DiscardString => 1
});
while (my $hr = $sth->fetchrow_hashref) {
say to_json $hr;
}
这会尝试将第一列(从一个索引)绑定到SQL_INTEGER
类型,如果转换为任何值失败,则会抛出错误。作为bohica notes,DiscardString
属性是必需的,因为它会丢弃数据的字符串部分(pv)。"
*根据DBI文档:
很少有驱动程序支持通过
bind_col
调用指定数据类型(大多数会忽略数据类型)。
DBD::Oracle
和DBD::ODBC
支持它,而DBD::Pg
可能支持它,根据this thread(虽然我无法验证)它),而DBD::mysql
没有。我不确定其他司机。
答案 1 :(得分:6)
虽然ThisSuitlsBlack几乎不正确,但他的回答有一些重要的遗漏。作为大多数StrictlyTyped和DiscardString属性的作者,我可以告诉你,事实上,DiscardString属性在这种情况下更为重要。
DBI将尝试将您的数据转换为指定的TYPE,如果失败,您的数据将保持不变,不会产生错误。如果强制转换失败并且指定了StrictlyTyped,则会生成错误。
DiscardString属性抛弃数据的字符串部分(pv)被丢弃。当使用JSON :: XS和其他JSON模块时,这一点尤为重要,因为JSON :: XS特别关注pv。
所以你至少应该这样做:
$sth->bind_col(1, undef, {TYPE => SQL_INTEGER, DiscardString => 1});
注意,很少有DBD实际关注bind_col中的绑定类型。 DBD :: ODBC是因为我维护它。 DBD :: Oracle通常不会注意TYPE,除非与StrictlyTyped和/或DiscardString一起使用(因为我为你提供了完全相同的问题而添加了该功能)。
驱动程序是否支持这些属性只能通过搜索代码使用sql_type_cast及其xs等价物sql_type_cast_svpv等来确定(除非文档说明),我不相信DBD: :Pg支持StrictlyTyped或DiscardString;事实上我相信在这个时候只有DBD :: ODBC和DBD :: Oracle做(因为我添加了它们)。
您可能还会发现this有趣。