タケユー・ウェブ日報

Ruby on Rails や Flutter といったWeb・モバイルアプリ技術を武器にお客様のビジネス立ち上げを支援する、タケユー・ウェブ株式会社の技術ブログです。

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です。