FC2ブログ
2011
01.11

DBIxのwhere句にEXISTSを使いたい

Category: perl
version: 0.08124

例が適当なんでわかりにくかったらすみませぬ。

やりたいのは、EXISTS 使いたいってコトなのだが、
$cond->{-and} = \"EXISTS select * from hogehoge where name like '%ねこ%'";

ってしたら、

DBIx::Class::ResultSet::search(): [SQL::Abstract::__ANON__] Fatal: -and => \$scalar not supported, use -nest


とか言われたので、

$cond->{-nest} = \"EXISTS select * from hogehoge where name like '%ねこ%'";

みたいな感じで、単体なら問題ない。

でも、これ
$cond->{-nest} = \"EXISTS select * from hogehoge where name like '%ねこ%'";
$cond->{-nest} = \"EXISTS select * from mogemoge where name like '%くま%'";

ってすると、片方しか適用されん・・・当たり前ですねすみません。

もしかして、
$cond->{-nest} = \[
\"EXISTS select * from hogehoge where name like '%ねこ%'",
\"EXISTS select * from mogemoge where name like '%くま%'"
];

ってしたら、EXISTS ~ OR EXISTS ~ って感じになってしまった・・・。

最悪
$cond->{"(select count(*) from hogehoge where name like '%ねこ%'"} = {'>' , 0 };

とかして逃げるからいいんだけd(いやいや・・・)

対応してるソースを探す。grep したら説明っぽいのが出てきた。
SQL/Abstract.pm
There is also a special -nest
operator which adds an additional set of parens, to create a subquery.
For example, to get something like this:

$stmt = "WHERE user = ? AND ( workhrs > ? OR geo = ? )";
@bind = ('nwiger', '20', 'ASIA');

You would do:

my %where = (
user => 'nwiger',
-nest => [ workhrs => {'>', 20}, geo => 'ASIA' ],
);


Finally, clauses in hashrefs or arrayrefs can be
prefixed with an C<-and> or C<-or> to change the logic
inside :

my @where = (
-and => [
user => 'nwiger',
-nest => [
-and => [workhrs => {'>', 20}, geo => 'ASIA' ],
-and => [workhrs => {'<', 50}, geo => 'EURO' ]
],
],
);

That would yield:

WHERE ( user = ? AND
( ( workhrs > ? AND geo = ? )
OR ( workhrs < ? AND geo = ? ) ) )

ふむふむ。
...
In the examples above, the subquery was used as an operator on a column;
but the same principle also applies for a clause within the main C<%where>
hash, like an EXISTS subquery :

my ($sub_stmt, @sub_bind)
= $sql->select("t1", "*", {c1 => 1, c2 => \"> t0.c0"});
my %where = (
foo => 1234,
-nest => \["EXISTS ($sub_stmt)" => @sub_bind],
);

which yields

$stmt = "WHERE (foo = ? AND EXISTS (SELECT * FROM t1
WHERE c1 = ? AND c2 > t0.c0))";
@bind = (1234, 1);

つーことは、
$cond->{-and} = \[
{'-nest' => \"EXISTS select * from hogehoge where name like '%ねこ%'"},
{'-nest' => \"EXISTS select * from mogemoge where name like '%くま%'"}
];

お、AND でつながった!

まとめ
1. EXISTS を使うときは、 -nest を使う。
2. $cond->{'-nest'} = \[\"EXISTS ~",\"EXISTS ~"] な感じで連結させるとデフォルトで OR になるので、
  AND にしたい場合は $cond->{-and} = \[{'-nest' => \"EXISTS ~"},{'-nest' => \"EXISTS ~"}]
  を使う。

まぁよく考えると、うーん、そーですよねーって感じではあるんですg

精進しましょう!



スポンサーサイト




トラックバックURL
http://noriko3.blog42.fc2.com/tb.php/529-a7c88367
トラックバック
コメント
管理者にだけ表示を許可する
 
back-to-top