日向夏特殊応援部隊

俺様向けメモ

SQL::Abstract::Plugin::InsertMulti

作ってみました。元ネタは MySQLにおけるbulk insert と bulk update - 金利0無利息キャッシング – キャッシングできます - subtech です。bulk insert, bulk update *1 が出来ます。

使い方は非常に簡単で、t/01_basic.t とか見て頂けるとすぐ分かるかと思いますがこんな感じです。

use strict;
use warnings;

use Data::Dump qw(dump);
use Perl6::Say;

use SQL::Abstract;
use SQL::Abstract::Plugin::InsertMulti;

my $sql = SQL::Abstract->new;

my ($stmt, @bind) = $sql->insert_multi(
  'app_data',
  [qw/app_id guid name value created_on updated_on/],
  [
    [1, 1, 'score', 100, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
    [1, 1, 'ranking', 3, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
    [1, 2, 'score', 200, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
    [1, 2, 'ranking', 2, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
    [1, 3, 'score', 300, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
    [1, 3, 'ranking', 1, \'UNIX_TIMESTAMP()', \'UNIX_TIMESTAMP()'],
  ],
);

say dump($stmt, \@bind);

とか実行すると、

(
  "INSERT INTO app_data ( app_id, guid, name, value, created_on, updated_on ) VALUES ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() ), ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() ), ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() ), ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() ), ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() ), ( ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() )",
  [
    1,
    1,
    "score",
    100,
    1,
    1,
    "ranking",
    3,
    1,
    2,
    "score",
    200,
    1,
    2,
    "ranking",
    2,
    1,
    3,
    "score",
    300,
    1,
    3,
    "ranking",
    1,
  ],
)

って感じになります。その後すぐに DBI の do に渡せる感じですな。

元の id:mala さんの奴のコードを丸っとパクる事から始めたんですが、結局全部書き直してしまいました。

  • SQL::Abstract の値の変換 (ScalarRef ならリテラルとして扱うとかそういうの) が適用されるように直した
  • ON DUPLICATE KEY UPDATE 以下のパラメータも update() の時のパラメータのように設定出来るようにした
  • update_multi() の時に、元のデータのフィールドが全部適用されちゃうのがちょっと嫌だったので、除外指定出来るようにした
  • SQL::Abstract::LimitOffset 使ってて、これが継承してる奴だから横槍入れて適用出来るようにした

とかですかね。

とりあえずテーブル名が app_data ってのに特に意味はありません。悪しからず。

*1: ON DUPLICATE KEY UPDATE を利用した INSERT