色々な検索方法1B!

こんにちわ! data-model トラックを達成するとかんかんが焼き肉をおごってくれるんじゃないかと期待している yappo です!

四日目は Data::Model での DB 検索の細かい使い方についてです。

search

Data::Model には DBIC にあるような search method として使える get method が用意されています。

通常は下記のように primary key や index を指定してレコードを絞り込みます。

    my $itr = $bookmark->get(
        user => 1
    );
    warn $itr->next->nickname;

一つ目に検索対象とするtable名を指定します

二つ目には primary key を指定します。複合 index の時は ARRAY リファレンスにします。

特定の index/unique 定義を使うときは次のようになります。

    my $itr = $bookmark->get(
        user => {
            index => {
                nickname => 'Yappo'
            }
        }
    );
    warn $itr->next->nickname;

が、一応 index が張られていないカラムに対しても絞り込みを行えます。

下記の例は、 nickname に既に unique index が張られていますが、これを別の index 設定が無いカラムに指定しても絞り込めます。

    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => 'Yappo'
            ]
        }
    );
    warn $itr->next->nickname;

一つ目に検索対象とする table name を指定します

二つ目の hashref に検索条件を指定します

get メソッドはメソッドの返り値をスカラーコンテキストで受けるかリストコンテキストでうけるかで返り値の情報が変わります。

スカラーコンテキストで受けた場合は Data::Model::Iterator が取得でき、

リストコンテキストで受けた場合は結果 Row の配列を取得することができます。

色々な検索条件

get メソッドで色々複雑な検索条件を指定したい場合があると思いますので

色々な例をあげましょう。

IN で複数の値をつかって検索したい場合:

# SELECT id, nickname FROM user WHERE (nickname IN (?,?,?))
    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => [qw/ nekokak Yappo kan /]
            ]
        }
    );

# もしくは
    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => { 'IN' => [qw/ nekokak Yappo kan /]}
            ]
        }
    );

NOT IN で検索したい場合:

# SELECT id, nickname FROM user WHERE (nickname NOT IN (?,?,?))
    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => { 'NOT IN' => [qw/ nekokak kan /]}
            ]
        }
    );

範囲指定で検索したい場合:

# SELECT id, nickname FROM user WHERE (id < ?)
    my $itr = $bookmark->get(
        user => {
            where => [
                id => { '<' => 10 }
            ]
        }
    );

# SELECT id, nickname FROM user WHERE (id > ?)
    my $itr = $bookmark->get(
        user => {
            where => [
                id => { '>' => 10 }
            ]
        }
    );

IS NOT NULLで検索したい場合:

# SELECT id, nickname FROM user WHERE (nickname IS NOT NULL)
    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => \'IS NOT NULL',
            ]
        }
    );

AND 検索したい場合:

# SELECT id, nickname FROM user WHERE (id < ?) AND (nickname = ?)
    my $itr = $bookmark->get(
        user => {
            where => [
                id => { '<' => 10 },
                nickname => 'Yappo',
            ]
        }
    );
);

同じカラムを AND 検索したい場合

# SELECT id, nickname FROM user WHERE ((id <= ?) AND (id >= ?))
    my $itr = $bookmark->get(
        user => {
            where => [
                id => [ -and => { '<=' => 11 }, { '>=' => 1 } ]
            ]
        }
    );

# SELECT id, nickname FROM user WHERE ((id = ?) AND (id = ?) AND (id = ?))
    my $itr = $bookmark->get(
        user => {
            where => [
                id => [ -and => 1, 2, 3 ]
            ]
        }
    );

同じカラムを OR 検索したい場合:

# SELECT id, nickname FROM user WHERE ((nickname = ?) OR (nickname = ?))
    my $itr = $bookmark->get(
        user => {
            where => [
                nickname => [ { '=' => 'Yappo' }, { '=' => 'nekokak' } ]
            ]
        }
    );

LIMIT/OFFSET をかけたい場合:

# ELECT id, nickname FROM user LIMIT 1 OFFSET 1
    my $itr = $bookmark->get(
        user => {
            limit  => 1,
            offset => 1,
        }
    );

order byをかけたい場合:

# SELECT id, nickname FROM user ORDER BY id DESC
    my $itr = $bookmark->get(
        user => {
            order => [ { id => 'DESC' } ]
        }
    );

# SELECT id, nickname FROM user ORDER BY id DESC, nickname ASC
    my $itr = $bookmark->get(
        user => {
            order => [ { id => 'DESC' }, { nickname => 'ASC' } ]
        }
    );

このように色々な検索条件を指定できます。

DBIC とは少しインタフェースが異なるので注意してください。

single

Data::Model では DBIx::Skinny とは違って find 相当の lookup メソッドが存在しています。

ただし primary key でしか検索出来ないので、他の条件で取得したい場合は limit/offset を設定したりする必要があります。

count

Data::Model では、今のところ count メソッドが用意されていないので、 count を取りたい場合は DBI ハンドルを直接取り出して SQL 文を直接組み立てる必要があります。

    my $dbh = $bookmark->get_driver('user')->r_handle;
    my $sth = $dbh->prepare_cached('SELECT COUNT(*) AS count FROM user');
    $sth->execute;
    my $count;
    $sth->bind_columns(undef, \$count);
    $count = 0 unless $sth->fetch;
    $sth->finish;
    warn "COUNT: $count";

この辺は、だいぶメンドくさいので Data::Model の機能を使ってうまくラッピングをしたいと思いますが、この解説は今度にしましょう。

have a nice Data::Model days!:)