結合の SQL コンセプト

SQL と同様に、LookML の結合は、2 つ以上のテーブルの関連する列に基づいて、それらのテーブルの行を結合するために使用されます。

LookML では、explore LookML パラメータで定義されている Explore を使用して、ユーザーがデータをクエリする方法が定義されます。Explore は、1 つ以上のビューまたは結合されたビューのセットで構成されます。Explore のメインビューは常にクエリに含まれます。通常、結合ビューは、クエリを満たすために必要な場合にのみ含まれます。

LookML ビューは、データベース内の SQL テーブル(またはテーブルの構造を持つ他の要素)または派生テーブルに対応します。ビューでは、データベースで使用できるフィールドまたは列と、それらへのアクセス方法を定義します。

次の例は、orders Explore の定義です。

explore: orders {
  join: users {
    type: left_outer
    sql_on: ${orders.user_id} = ${users.id} ;;
    relationship: many_to_one
  }
}

Explore のメインビューである orders ビューは、type: left_outer LookML パラメータで示されているように、SQL LEFT OUTER JOIN を使用して users ビューに結合されています。sql_on LookML パラメータで定義される SQL ON 句は、table_alias.column ではなく to ${view_name.field_name} を参照します。これは、データベース内のテーブル名または列名が変更された場合に、その変更を 1 か所でのみ行うことができるようにするためです。

relationship パラメータは重要です。結合により、行が重複するファンアウトの問題が発生する可能性があります。多くの注文が 1 人のユーザーにのみ結合されることを指定すると、Looker はこの結合からファンアウトが発生しないことを認識するため、特別な処理は必要ありません。ただし、one_to_many 関係はファンアウトをトリガーする可能性があります。

ビューとデータ探索の自動生成は、デフォルトで左外部結合になります。ただし、前の例では、すべての注文に 1 人のユーザーが関連付けられている可能性が高いため、この例の結合は内部結合にできます。

Explore の生成された SQL を表示するには、UI で Explore を実行し、[データ] パネルで [SQL] タブを選択します。

たとえば、前述の Orders Explore を開いて、[User ID] フィールドと [Count] フィールドを選択すると、生成される SQL は次のようになります。

SELECT
    `user_id` AS `orders.user_id`,
    COUNT(*) AS `orders.count`
FROM
    `thelook`.`orders` AS `orders`
GROUP BY
    1
ORDER BY
    2 DESC
LIMIT 500

この例では、users テーブルはまったく参照されていません。必要な場合にのみ持ち込まれます。

[ユーザー ID] ディメンションを削除し、[ユーザー] ビューから [ID] ディメンションを追加すると、SQL は次のようになります。

SELECT
    `users`.`id` AS `users.id`,
    COUNT(*) AS `orders.count`
FROM
    `thelook`.`orders` AS `orders`
    INNER JOIN `thelook`.`users` AS `users` ON `orders`.`user_id` = `users`.`id`
GROUP BY
    1
ORDER BY
    2 DESC
LIMIT 500

この場合、[ユーザー] ビューから選択されているため、結合が含まれます。

次の例は、前に定義した orders Explore ファイルの LookML を示しています。order_items ビューに結合を追加しています。

explore: orders {
  join: users {
    type: inner
    sql_on: ${orders.user_id} = ${users.id} ;;
    relationship: many_to_one
  }
  join: order_items {
    type: inner
    sql_on: ${orders.id} = ${order_items.order_id} ;;
    relationship: one_to_many
  }
}

UI で [Orders] Explore を開くと、[Order Items] ビューが表示されます。[Order Items] ビューの [Total Sale Price] メジャーと、[Orders] の [Count] と [Users] の [ID] を選択すると、Looker は次の SQL を生成します。

SELECT
    `users`.`id` AS `users.id`,
    COUNT(DISTINCT orders.id ) AS `orders.count`,
    COALESCE(SUM(`order_items`.`sale_price`), 0) AS `order_items.total_sale_price`
FROM
    `thelook`.`orders` AS `orders`
    INNER JOIN `thelook`.`users` AS `users` ON `orders`.`user_id` = `users`.`id`
    INNER JOIN `thelook`.`order_items` AS `order_items` ON `orders`.`id` = `order_items`.`order_id`
GROUP BY
    1
ORDER BY
    2 DESC
LIMIT 500

この例では、COUNT(*) AS orders.countCOUNT(DISTINCT orders.id ) AS orders.count になりました。Looker は、ファンアウトが発生する可能性があることを検出し、SQL DISTINCT キーワードを SQL COUNT 関数に自動的に追加しました。