DBIx::Simple と SQL::Abstract::Limit
なんちゃってマッパ DBIx::Simple
DBIC などの O/R マッパを使うほどじゃないけど DB 操作で楽したい,という場合には tomi さんも御推薦の DBIx::Simple があります。tomi さんもお書きのように結構致命的なバグ(その1,その2)が放置されているのが悲しいところですが。
DBIx::Simple を生の状態で使ってもそれほど有難味がないですが,周辺モジュールがインストールされていると透過的に使ってくれるので格段に便利になります。たとえば SQL::Abstract でクエリを簡単に書くことができますし,クエリ結果をテーブルにしたい場合 DBIx::XHTML_Table を使うと楽です。
さらに,DBIx::Simple::OO という拡張モジュールを別途インストールするとクエリ結果を Object::Accessor ベースなオブジェクトにしてくれます。
use DBIx::Simple; use DBIx::Simple::OO; my $db = DBIx::Simple->connect('dbi:SQLite:sample.db') or die; my $result = $db->select( 't_bookmark', # table name '*', # columns { # WHERE clause available => 1, }, [ # ORDER BY clause 'ctime', ] ); # Using DBIS::OO foreach my $record ($result->objects) { print "URL: ", $record->URL, " ", "Comment: ", $record->comment, "\n"; } # Using DBIx::XHTML_Table print $result->html;
リレーションを使わなくてよくって SELECT, DELETE が使えればいいやって場合であれば*1これで充分なのがおわかりいただけるかと。
ページングがしたい→ SQL::Abstract::Limit
上記のように DBIx::Simple + SQL::Abstract で直感的に操作ができるのですが,検索結果をページングしたい時に LIMIT 句を指定する方法がありません。
SQL::Abstract はあくまで SQL 文とプレースホルダを構築するだけなので,別々に使えば無理矢理指定することが可能です。
my ($stmt, @bind) = SQL::Abstract->new->select( ... ); $stmt .= ' LIMIT ? OFFSET ?'; push(@bind, 30, 0); my $result = $db->query($stmt, @bind);
ですがまどろっこしいですし,何を隠そう LIMIT 句は標準 SQL の範疇に入らないので*2データベースによって書き方が異なります。
個人用にラッパでも書くかなぁと思っていましたが,さすが CPAN,とっくにそのようなものがありました。それが SQL::Abstract::Limit です*3。これは先ほど書いた方言を吸収してくれますし SQL::Abstract の上位互換として働きます。
use SQL::Abstract::Limit; # DBIx::Simple->abstract は lvalue になれる $db->abstract = SQL::Abstract::Limit->new( limit_dialect => $db->dbh ); my $result = $db->select( 't_bookmark', '*', { # WHERE clause available => 1, }, [ # ORDER BY clause 'id', ], 30, # LIMIT 0 # OFFSET );
limit_dialect で LIMIT まわりの方言を指定します。dbh を与えると JDBC 等特殊な物でなければ自動判別してくれます。