end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

mysql + perl でプレースホルダを利用したバルクインサート

プレースホルダを利用したバルクインサートは、sqlでは次のように記載します。

insert into tbl_meisai
 (mitsumori_id, hinmei, hinban, quantity, tanka,price)
values
 (?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?),(?,?,?,?,?)...

これをperl(DBI)で書くなら、次のようになるかと思います。

#無制限に大量レコードをinsertすると、sql文長の制限を超える気がする為
my $BULK_INSERT_LIMIT = 40;

#明細行に登録されるカラム名
my @FORM_KEYS_MEISAI =
    qw/maker maker_id
       shouhin_code hinmei_code hinmei hinban color size
       juchuu_quantity unit juchuu_tanka juchuu_price
       note/;


sub add_hachuu_meisai {
    my ($self,$meisais) = @_;

    return $self if(scalar(@$meisais)==0);

    my @meisais_grp;
    my $row_id = 1;
    my $pre_page_id = 1;
    for my $meisai (@$meisais){
	#row_idはpage毎にcountします
	$row_id = 1 if $meisai->{page_id} != $pre_page_id;
	$pre_page_id = $meisai->{page_id};
	push(@meisais_grp,$meisai);

	if($meisai->{page_id} != $pre_page_id or
	   scalar(@meisais_grp)>$BULK_INSERT_LIMIT ){
	    #この単位(かたまり)でbulk inset
	    $row_id = $self->_add_meisai_page_each($meisai->{page_id},
						   $row_id,
						   \@meisais_grp);
	    return undef unless($row_id);
	    @meisais_grp = ();
	}
    }
    if( scalar(@meisais_grp)>0 ){
	my $page_id = $meisais_grp[0]->{page_id};
	#この単位(かたまり)でbulk inset
	$row_id = $self->_add_meisai_page_each($page_id,
					       $row_id,
					       \@meisais_grp);
	return undef unless($row_id);
    }
    return $self;
}

sub _add_meisai_page_each {
    my ($self,$pno,$row_id,$meisais) = @_;

    return $self if(scalar(@$meisais)==0);

    my $keys_str = join(',',@FORM_KEYS_MEISAI);
    my $vals_str = '(?,?,?'. ',?'x scalar(@FORM_KEYS_MEISAI) .')';
    my @meisais_val;
    for my $meisai (@$meisais){
	push(@meisais_val,$vals_str);
    }
    my $meisais_val_str = join(',',@meisais_val);

    my $sql =<<EOF;
insert into h_meisai (hachuu_id,page_id,row_id,$keys_str)
values $meisais_val_str
EOF
    my $sth = $self->{dbh}->prepare($sql);

    my @vals_all;
    for my $meisai (@$meisais){
	my @vals_row = ($self->{id},$pno,$row_id++);

	for my $meisai_key ( @FORM_KEYS_MEISAI ){
	    push(@vals_row,$meisai->{$meisai_key});
	}
	push(@vals_all,@vals_row);
    }

    unless ( $sth->execute(@vals_all) ){
	$self->error( $sth->errstr );
	$self->set_err_msg( $sth->errstr );
	return undef;
    }
    return $row_id;
}