Class::DBI で疑似的カラムを扱う - にぽたん研究所

November 16, 2005

このエントリーをはてなブックマークに追加
最近、SQL で WHERE 句に入らず、ORDER BY やら GROUP BY もされず、かつ MAX() だとか MIN() だとかを求められる必要もない、言うなれば「取るに足らない値」とかを、個別のカラムに持たず、そういうのを一気にまとめて text 型のカラムに入れたりすることがあったりする。
例えば、住所録を作ろうなんつって、テーブルを組みたいわけだが、そもそも WHERE 句に入る要素なんて名前ぐらいしかないなぁ…という場合は
CREATE table address (
  id int unsigned NOT NULL auto_increment,
  name varchar(255) NOT NULL default '',
  props text,
  PRIMARY KEY (id),
  KEY (name)
);
こんなようなテーブルを一個作っておいたりして。
要するに、name 以外の値は「取るに足らない値」で、props というカラムが一個あるだけ。
んで、この propsに郵便番号だ、住所だ、電話番号をつっこむわけです。
mysql> INSERT INTO address (name)
VALUES ('YAMADA'), ('SUZUKI'), ('TANAKA');
こんなんだったとすると、Class::DBI で扱う場合、いつものようにこのテーブルのクラスを作るわけですが、props のカラムを扱うのが難しい。
よく Data::Dumper とかで、文字列化した値を入れておいて、それを eval() して取り出したりするんですが、その手続きが意外に面倒臭かったり。
なんとか楽に出来んかなーっていっつも思ってたりしたんですが、今日いつものように CPAN あたりを徘徊していたら、Class::DBI::Plugin::PseudoColumns とかいう、何やらそれにうってつけなモジュールがあった。
package MyData::Address;

use strict;
use base qw(MyData::Base);
use Class::DBI::Plugin::PseudoColumns;
__PACKAGE__->table('address');
__PACKAGE__->columns(Primary => qw(id));
__PACKAGE__->columns(All => qw(id name props));
__PACKAGE__->pseudo_columns(props => qw(zipcode address sex phone cellphone));

1;
とりあえず、今んとこ
mysql> SELECT * FROM address;
+----+--------+-------+
| id | name   | props |
+----+--------+-------+
|  1 | YAMADA | NULL  |
|  2 | SUZUKI | NULL  |
|  3 | TANAKA | NULL  |
+----+--------+-------+
3 rows in set (0.00 sec)
こんなんなってますが「そういや、YAMADA も SUZUKI も TANAKA も男だったなー」とかいう時
use strict;
use MyData::Address;

my $iter = MyData::Address->retrieve_all;
while (my $row = $iter->next) {
    $row->sex('M');
    $row->update;
}
こんなカンジで、いつものように、普通のカラムを扱うようにいじってみると、
mysql> SELECT * FROM address;
+----+--------+----------------+
| id | name   | props          |
+----+--------+----------------+
|  1 | YAMADA | {'sex' => 'M'} |
|  2 | SUZUKI | {'sex' => 'M'} |
|  3 | TANAKA | {'sex' => 'M'} |
+----+--------+----------------+
3 rows in set (0.00 sec)
こんな風になります。
取り出す時もいつも通り、
use strict;
use MyData::Address;

my $yamada = MyData::Address->retrieve(1);
print $yamada->sex, "\n";
お手軽に利用出来たりします。
携帯番号でも登録しようかなーって時に「あー、そういや TANAKA は携帯電話を 2 個持ってたなー」とか思い出す。でもそんな取るに足らないデータなのに「一対多だから」という理由で正規化するのもアホくさい。
use strict;
use MyData::Address;

my $tanaka = MyData::Address->retrieve(3);
$tanaka->cellphone([qw(090-1234-56xx 090-2345-67xx)]);
$tanaka->update;
こうしておけば、
use strict;
use Data::Dumper;
use MyData::Address;

my $tanaka = MyData::Address->retrieve(3);
my $cellphones = $tanaka->cellphone;
print Dumper $cellphones;
こうした時に
$VAR1 = [
          '090-1234-56xx',
          '090-2345-67xx'
        ];
こう取り出せたりする。
いやー、なかなか素敵。

てことで、お手軽に擬似的カラムを扱える、Class::DBI::Plugin::PseudoColumns は、軽くオススメです。

nipotan at 14:55 | Comments(3) | TrackBack(4) | 技術 
このエントリーをはてなブックマークに追加

Trackback URL for this entry

Trackbacks

1. [Perl][PHP] Class::DBI::Plugin::PseudoColumnsって便利じゃん、と思ったけれど、  [ 浅倉卓司@blog風味? ]   November 17, 2005 11:00
 「Class::DBI で疑似的カラムを扱う」を読んで「こりゃ便利」と思ったけど、でも、最近はPerlとPHPの混用が多いので使えないのですよね……。  というわけで、シリアライザを指定できるとうれしいかも。  PHP::Serializationを使ってPHP側に合わせてあげるのがPerlクオリ...
nipotanさんの「Class::DBI で疑似的カラムを扱う」で自演紹介され...
3. Class::DBI で疑似的カラムを扱う  [ $ kill -ALRM pid ... ]   December 02, 2005 21:44
にぽたん研究所 Class::DBI で疑似的カラムを扱うより 取るに足らないデータなのに「一対多だから」という理由で 正規化するのもアホくさい。 今作っている業務システムまさにこの状態。 この問題を取り急ぎ解決するのにちょうど良い。 $ dh-make-perl --cp...
4. Class::DBI でもっと透過的に擬似的カラムを扱う  [ にぽたん研究所 ]   January 10, 2006 20:47
以前 Class::DBI で疑似的カラムを扱うというタイトルで、Class::DBI::Plugin::PseudoColumns という CPAN モジュールを紹介したことがありました。 で、そのエントリを見てみるとこんなトラックバックをいただきました。 浅倉卓司@blog風味? - Class::DBI::Plugin::Ps...

Comments

1. Posted by 840   November 18, 2005 04:49
Perl初心者で、あまり、考えてないで発言しちゃいますが。。。

正規化を勝手にやってくれるPseudoTableみたいなのはないんですかね?
シリアライズした物をDBにつっこむ系は後ではまるパターンが多いので
やりたくないんですが、
勝手に生成されたテーブルであればメンテも拡張もDBの機能が利用できて
楽なんじゃないかな?と思った次第です。
2. Posted by hase   November 19, 2005 14:13
ベンリ〜
3. Posted by BlogPetのにぽたん   November 20, 2005 10:09
きょうは、ここで正規みたいな登録しなかった?
いやにぽたんの、電話された。

Post a comment

Name:
URL:
  Remember info?: Rate: Face    Star