我正在尝试使用带有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的其他方法也很受欢迎.非常感谢.
Bor*_*din 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