如何告诉DBD :: CSV使用逗号作为小数分隔符?

时间:2012-12-06 12:13:15

标签: perl csv dbi

我尝试使用带有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部分进行比较,这是正确的,但不是我想要的。

问题:如何告诉它用逗号处理数字为浮动?

我曾经想过的事情:

  • 我没有在Text :: CSV中找到任何内置方式来执行此操作。我不确定在Text :: CSV中我可以将其挂钩,或者如果Text :: CSV中有一个机制可以将这些内容放入其中。
  • 我不知道是否存在DBD :: CSV想要使用Text :: CSV_XS的问题。
  • 也许我可以在以后读取数据后将其存储在某处,但我还不确定正确的接入点在哪里。
  • 我知道这些东西存储在SQL :: Statement中。我还不知道在哪里。这可能会有点方便。

将源CSV文件更改为点而不是逗号是一个选项。

我愿意接受各种建议。通过SQL的其他方法也很受欢迎。非常感谢。

1 个答案:

答案 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