4

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(DBIおよびDBD::CSVのどこかにあるSQL::Statementを意味します)が、のデータを考慮しないことcol3です。これは、中央にコンマが含まれる浮動小数点値です。浮く。代わりに、コンマを理解しないため、列を整数として扱います。

データの例を次に示します。

foo;foo;81,90
bar;bar;80,50
baz;baz;80,70

したがって、このデータを含む上記のコードは、1行の出力になります81,90。もちろん、それは間違っています。比較のint()一部を使用しましたが、これは正しいですが、私が望むものではありません。col3

質問:コンマを含む数値をfloatとして扱うように指示するにはどうすればよいですか?

私が考えたこと:

  • Text::CSVにこれを行うための組み込みの方法は見つかりませんでした。Text :: CSVのどこにこれをフックできるか、またはText::CSVにそのようなものを入れるメカニズムがあるかどうかはわかりません。
  • DBD::CSVが可能であればText::CSV_XSを使用したいという問題が発生するかどうかはわかりません。
  • データが読み取られ、すでにどこかに保存された後で、後でそれを実行できるかもしれませんが、適切なアクセスポイントがどこにあるかはまだわかりません。
  • SQL::Statementに保存されていることを理解しています。まだどこかわかりません。これはどういうわけか便利かもしれません。

ソースCSVファイルをコンマではなくドットに変更することはできません。

私はあらゆる種類の提案を受け入れています。SQLを介したCSV全体への他のアプローチも歓迎します。どうもありがとう。

4

1 に答える 1

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
于 2012-12-06T12:38:57.023 に答える