PerlでSQLiteを使う

2019/03/08更新

目次

基本事項

PerlでSQLiteを使う方法を簡単にまとめておく。

まず、必要となるのは、DBIモジュールと、対象のデータベースへの接続である。

# DBIモジュールを使う。
use DBI;

# connectでSQLiteのデータベースファイルに接続する。
my $dbname = 'data.db';
my $db = DBI->connect("DBI:SQLite:dbname=$dbname", '', '', { AutoCommit => 0 });

  :

# 全ての操作が終わったらdisconnectで接続を終了する。
$db->disconnect;

以降、サンプルとして、「data.db」にはdataという名前の以下のようなテーブルが記録されているものとする。

id

name

value1

value2

1

hoge

111

333

2

fuga

111

444

3

piyo

222

555

4

paco

222

666

SELECT文の実行

SQL文を実行するには、prepare()で文を用意し、execute()で値の挿入と実行を行なう形が基本となる。prepare()では、値を挿入する位置をプレースホルダ?としておき、execute()?の位置に対応する値を引数に渡す。

実行結果を取得する方法はいくつかあるが、fetchrow_hashref()が使い勝手が良い。これは、呼び出すごとに結果を1行ずつ取得し、列名をキーにしたハッシュリファレンスを返す。

# SQL文を用意
my $s1 = $db->prepare('SELECT * FROM data WHERE value1 = ? AND value2 = ?;');

# 値を渡して実行
$s1->execute(111, 333);

# 結果を1行ずつ取得
while (my $row = $s1->fetchrow_hashref()) {
    my $id     = $row->{id}; # 列名がキーになっている。
    my $name   = $row->{name};
    my $value1 = $row->{value1};
    my $value2 = $row->{value2};
    print "$id: $name, $value1, $value2\n";
}

# 取得し終えたらfinishを呼ぶ
$s1->finish;

SQLで合計などを取得した場合は、列名が無いため、fetchrow_hashref()の代わりにfetchrow_arrayref()を使うとよい。こちらは、1行ずつを配列リファレンスにして返す。

# 列名の無いSELECT文を実行
my $s2 = $db->prepare('SELECT COUNT(*), SUM(value2) FROM data WHERE value1 = ?;');
$s2->execute(111);

# 結果を取得
my $row = $s2->fetchrow_arrayref();
my $count = $row->[0];  # COUNT(*)の値
my $sum   = $row->[1];  # SUM(value2)の値
print "count=$count, sum=$sum\n";  # count=2, sum=777

$s2->finish;

INSERT、UPDATE、DELETE文の実行

INSERT文やUPDATE文の場合もSQL文の実行方法は同じであるが、これらのSQL文の場合はexecute()が影響を受けたレコード数(失敗時はundef)を返す。ただし、影響を受けたのが0行の場合は、0E0という文字列が返る。この値はそのまま評価すると真となり、数値評価すると0となるため、以下のように「成功して1行以上」「成功したが0行」「失敗」の3つの場合を区別することができる。

なお、SELECT文の場合もexecute()が値を返す環境もあるらしいが、そちらは確実ではないので頼らない方がよいとのことである。

データベース接続時にAutoCommit => 0を指定していた場合は、以下のように1つ以上のSQL文を実行した後で、自分でトランザクションをcommitする必要がある。逆に途中で問題が生じた場合は、一連のトランザクションをrollbackすることもできる。

# UPDATE文を実行
my $s3 = $db->prepare('UPDATE data SET value2 = ? WHERE value1 = ?;');
my $result = $s3->execute(777, 111);

# 成功した場合
if ($result) {
    # 実行を確定する
    $db->commit;
    
    # 成功かつ1行以上が影響を受けた場合
    if ($result > 0) {
        print "$result records were updated.\n";
    # 成功したが影響を受けた行が無い場合
    } else {
        print "No records were updated.\n";
    }

# 失敗した場合
} else {
    # 実行を無かったことにする
    $db->rollback;
    
    print "Update statement failed.\n";
}

$s3->finish;