読者です 読者をやめる 読者になる 読者になる

元フリーエンジニアライフ

Ruby on Rails とか MovableType とかAWSやってるフリーランスウェブエンジニアの記録でした。現在は法人成りしてIT社長。

MT::Object で外部結合(OUTER JOIN)

  • MT6.03で確認

例えば、

まだ1件もアイテムを関連付けていない記事を取り出す

ようなケースでは外部結合を使います。

外部結合は、複数のテーブルから一致する要素の有無にかかわらず結合して表示します

参考 第6回 SQL基礎II|OSS-DB入門|OSS-DB道場|受験対策|DBスペシャリストを認定する資格 OSS-DB技術者認定試験

なので、アイテムの関連付けの有無に係らず結合しておき、そこから関連付けのないものだけ抽出すればよいわけですね。

SQLにするとこんな感じでしょうか。

SELECT e.entry_id, e.entry_title
FROM mt_entry e LEFT OUTER JOIN mt_objectasset oa ON
    oa.objectasset_object_ds = 'entry' AND e.entry_id = oa.objectasset_object_id
WHERE e.entry_class = 'entry' AND oa.objectasset_object_id IS NULL;

これは、アイテムの関連付けのほかにも、コメント、ロール割り当てなどいろいろ使えます。

で、これを MT::ObjectSQLを無理やりexecuteする以外で行う方法がわかりませんでした。

調べてみると

lib/MT/ObjectDrivcer/Driver/DBI.pm の、prepare_statement のあたりに書いてあるので、詳しくはそちらを読めばよいです。

https://github.com/movabletype/movabletype/blob/mt6.0.3/lib/MT/ObjectDriver/Driver/DBI.pm

サンプルコード

my @entries = MT->model( 'entry' )->load(
    undef,
    {
        'join' => MT->model( 'objectasset' )->join_on(
            undef,
            {
                object_id => \' IS NULL',
            },
            {
                type => 'LEFT OUTER',
                condition => {
                    object_ds => 'entry',
                    object_id => \' = entry_id',
                },
            },
        ),
    } );

join_on\' IS NULL'のあたりについては、@okayamaさんのちょっとイレギュラーな join 指定でオブジェクトを load するという記事に詳しく説明があるので、そちらをお読み頂くとして、外部結合を行うためには、以下を指定します。

  • join_onの第三引数で
    • typeで結合の種類(ここではLEFT OUTER)を指定
    • conditionでON句(結合の条件)

このことは、こちらの657行目あたりから書いてありますので確認してみてください。

要はtypeを渡したときは、conditionの内容とあわせて、JOIN句を組み立ててくれるという感じです。

あとはWHERE句のobjectasset_object_id IS NULLが組み立てられるように第二引数で指定すればOKです。