我尝试使用带有DBI和DBD::CSV的德语CSV文件。反过来,这使用Text::CSV来解析文件。我想使用SQL查询该文件中的数据。
让我们先看一下这个文件。它以分号(;
)分隔,其中的数字如下所示:5,23
,相当于英文5.23
。
这是我到目前为止所得到的:
use strict; use warnings;
use DBI;
# create the database handle
my $dbh = DBI->connect(
'dbi:CSV:',
undef, undef,
{
f_dir => '.',
f_schema => undef,
f_ext => '.csv',
f_encoding => 'latin-1',
csv_eol => "\n",
csv_sep_char => ';',
csv_tables => {
foo => {
file => 'foo.csv',
#skip_first_row => 0,
col_names => [ map { "col$_" } (1..3) ], # see annotation below
},
},
},
) or croak $DBI::errstr;
my $sth = $dbh->prepare(
'SELECT col3 FROM foo WHERE col3 > 80.50 ORDER BY col3 ASC'
);
$sth->execute;
while (my $res = $sth->fetchrow_hashref) {
say $res->{col3};
}
现在,这看起来很不错。问题是SQL(意思是SQL :: Statement,它位于DBI和DBD :: CSV的某个地方)并不考虑col3
中的数据,这是一个带有逗号的浮点值中间,作为一个浮动。相反,它将列视为整数,因为它不理解逗号。
以下是一些示例数据:
foo;foo;81,90
bar;bar;80,50
baz;baz;80,70
所以带有这些数据的上述代码将产生一行输出:81,90
。当然,这是错误的。它使用int()
col3
部分进行比较,这是正确的,但不是我想要的。
问题:如何告诉它用逗号处理数字为浮动?
我曾经想过的事情:
将源CSV文件更改为点而不是逗号是不一个选项。
我愿意接受各种建议。通过SQL的其他方法也很受欢迎。非常感谢。
答案 0 :(得分:13)
您需要使用SQL::Statement::Functions
编写用户定义的函数(已作为DBD::CSV
的一部分加载)。
这个程序可以满足您的需求。将0.0
添加到已转换的字符串是完全没必要的,但它说明了子例程的用途。 (另请注意f_encoding
调用的connect
参数中的拼写错误。)
use strict;
use warnings;
use DBI;
my $dbh = DBI->connect(
'dbi:CSV:',
undef, undef,
{
f_dir => '.',
f_schema => undef,
f_ext => '.csv',
f_encoding => 'latin-1',
csv_eol => "\n",
csv_sep_char => ';',
csv_tables => {
foo => {
file => 'test.csv',
#skip_first_row => 0,
col_names => [ map { "col$_" } (1..3) ], # see annotation below
},
},
},
) or croak $DBI::errstr;
$dbh->do('CREATE FUNCTION comma_float EXTERNAL');
sub comma_float {
my ($self, $sth, $n) = @_;
$n =~ tr/,/./;
return $n + 0.0;
}
my $sth = $dbh->prepare(
'SELECT col3 FROM foo WHERE comma_float(col3) > 80.50 ORDER BY col3 ASC'
);
$sth->execute;
while (my $res = $sth->fetchrow_hashref) {
say $res->{col3};
}
<强>输出强>
80,70
81,90