hiveで複数カラムのOUTER JOINを楽に行うには文字列連結を使えばよい

複数カラムのOUTER JOINを楽に行う方法メモ。



ONの条件に使うカラムを文字列で連結してからOUTER JOINする


ONの条件に複数カラムを使うと挙動がややこしくなる。そういうときは、一旦文字列にして連結することで、ONの条件をシンプルにすれば色々と簡単になる。


ONの条件が複雑で分かりづらい例。


use abc_db;

SELECT
  ...
FROM
(
  SELECT
    a.device a_device,
    b.device b_device,
    c.device c_device,
    ...
  FROM
    (...) -- a, b, c テーブルをJOINするクエリ
  WHERE
    ...
  GROUP BY
    ...

) hey FULL OUTER JOIN (

  SELECT
    a.device a_device,
    b.device b_device,
    c.device c_device,
    ...
  FROM
    (...) -- a, b, c テーブルをJOINするクエリ
  WHERE
    ...
  GROUP BY
    ...

) heyhey ON (hey.a_device = heyhey.b_device
             AND hey.b_device = heyhey.b_device
             AND hey.c_device = heyhey.c_device)

上記のクエリでは、FULL OUTER JOINのONに複数条件が使われており、どういう挙動をするのかパッと分からない。


文字列連結を使うことで上記の分かりづらさを解消した例。


use abc_db;

SELECT
  ...
FROM
(
  SELECT
    a.device a_device,
    b.device b_device,
    c.device c_device,
    concat(if(a.device IS NULL, 'NULL', a.device),
           if(b.device IS NULL, 'NULL', b.device),
           if(c.device IS NULL, 'NULL', c.device)) devices,
    ...
  FROM
    (...) -- a, b, c テーブルをJOINするクエリ
  WHERE
    ...
  GROUP BY
    ...

) hey FULL OUTER JOIN (

  SELECT
    a.device a_device,
    b.device b_device,
    c.device c_device,
    concat(if(a.device IS NULL, 'NULL', a.device),
           if(b.device IS NULL, 'NULL', b.device),
           if(c.device IS NULL, 'NULL', c.device)) devices,
    ...
  FROM
    (...) -- a, b, c テーブルをJOINするクエリ
  WHERE
    ...
  GROUP BY
    ...

) heyhey ON (hey.devices = heyhey.devices)

上記のクエリのように文字列連結した結果をONに使うことで、ONの中身がすっきりするし、挙動も明確になる。たぶんバッドノウハウ的なものなんでしょうけども。


そもそもJOINし過ぎでは?みたいな指摘がMySQLの人からきそうですが、JOINが最も少なくなるようにしてもこんな感じです。


あと、このクエリはそもそも数十分かかることが全体のHiveクエリなので、これはこれでOKなんです。バッチみたいなものだと思ってください。


著者プロフィール
Webサイトをいくつか作っています。
著者プロフィール