m6u's blog

便利な製品・サービス・アプリを見つけては、その評価を書き続けるブログ

Perlでcsvデータからsqlのupdate文を生成してみた

    • csvの1行目にフィールド名があること。
    • 「-k」オプションで主キーを指定すること。
    • 「-t」オプションでupdate先のテーブル名を指定すること。
    • 読み込むcsvファイル名へのフルパスを与えること。エンコードはShiftJISが前提。
    • Windows上のActivePerlで動作確認。
    • 標準出力に返すので、リダイレクトしてファイルに書き出すべし。(perl csv2sql.pl -t table_name -k id,no csv_file_name > update.sql
    • ツッコミどころが多々あるんだろうけど、自分としてはこれで事足りたから公開してみるテスト。
use strict;
use warnings;
use Encode;
use IO::File;
use IO::Handle;
use Text::CSV_XS;
use Time::HiRes;
use POSIX 'strftime';

my $start_time = Time::HiRes::time;

STDOUT->autoflush(1);
STDERR->autoflush(1);
binmode(STDOUT,":encoding(shift_jis)");
binmode(STDERR,":encoding(shift_jis)");

my @pkey = ();
my $fname = '';
my $tname = '';
for (my $i = 0; $i <= $#ARGV; $i++) {
    if (($ARGV[$i] eq '-k') || ($ARGV[$i] eq '-K')) {
        if (defined($ARGV[$i+1])) {
            if ($ARGV[$i+1] =~ /,/) {
                push @pkey, split(/,/, $ARGV[$i+1]);
            }
            else {
                push @pkey, $ARGV[$i+1];
            }
        }
    }
    elsif (($ARGV[$i] eq '-t') || ($ARGV[$i] eq '-T')) {
        if (defined($ARGV[$i+1])) {
            $tname = $ARGV[$i+1];
        }
    }
    elsif (-f $ARGV[$i]) {
        $fname = $ARGV[$i];
    }
}

if ($fname eq '') {
    die "csvファイルを指定してください。";
}
if ($#pkey < 0) {
    die "insert文は未実装です。";
}

my $csv = Text::CSV_XS->new({binary => 1, always_quote => 1, eol => $/});
my $fc = IO::File->new("$fname", '<:encoding(shiftjis)') || die "can't open $fname: $!";
my $lcount = 0;
my @cols = ();
until ($fc->eof) {
    my $dat = $csv->getline($fc);
    if ($lcount++ == 0) {
        @cols = @$dat;
    }
    else {
        my @vals = @$dat;
        my $set_phrase = '';
        my $where_phrase = '';
        
        for (my $i = 0; $i <= $#cols; $i++) {
            if (grep {$_ eq $cols[$i]} @pkey) {
                if ($where_phrase ne '') { $where_phrase .= ' AND '; }
                if ($vals[$i] eq '\N') {
                    $where_phrase .= $cols[$i] . ' = NULL';
                }
                elsif ($vals[$i] =~ /^-?[0-9]+[0-9\.]*$/) {
                    $where_phrase .= $cols[$i] . ' = ' . $vals[$i];
                }
                else {
                    $where_phrase .= $cols[$i] . " = '" . $vals[$i] . "'";
                }
            }
            else {
                if ($set_phrase ne '') { $set_phrase .= ', '; }
                if ($vals[$i] eq '\N') {
                    $set_phrase .= $cols[$i] . ' = NULL';
                }
                elsif ($vals[$i] =~ /^-?[0-9]+[0-9\.]*$/) {
                    $set_phrase .= $cols[$i] . ' = ' . $vals[$i];
                }
                else {
                    $set_phrase .= $cols[$i] . " = '" . $vals[$i] . "'";
                }
            }
        }
        print 'UPDATE ', $tname, ' SET ', $set_phrase, ' WHERE ', $where_phrase, ";\n";
    }
}
close $fc;

printf(STDERR "実行時間 %0.3f\n", Time::HiRes::time - $start_time);