2017-04-07 4 views
6

eventから単一のteamを取得するための、最も簡単で効率的なSQLクエリを作成します。しかしeventteamとは直接関係していない可能性があり、テーブル関係階層のどのレベルでも関連している可能性があります。SQLで任意の子関係の "親"を照会する方法は?

enter image description here

注意するカップルの事を:


セットアップ

は、ここに私のスキーマがどのように見えるかの単純化した表現だ

  • teamsは多くのcollectionsを持つことができ、 appswebhooks
  • collectionsもまた、多くのwebhooksを持つことができます。
  • webhooksは、teamまたはcollectionのいずれかに属することができますが、1つのみです。
  • eventsは、任意のオブジェクトに属することができますが、1つだけです。

これは、ほとんどのSaaS型企業(例えば、スラックまたはストライプ)が持つようなかなり基本的な設定のようです。すべてが「チーム」の下にグループ化され、ユーザーはメンバーとしてメンバーと交流することができます。


問題セットアップ、私は解決SQLクエリを作成したいことを考えると...

idによってイベントのチームを検索します。

親チームを直接または特定の方法で間接的に検索するクエリを簡単に作成できます。たとえば...

は直接「チームイベント」に関連のチームを検索します。

SELECT teams.* 
FROM teams 
JOIN events ON events.team_id = teams.id 
WHERE events.id = ${id} 

それとも...

間接的関連の "コレクションイベント" のチームを検索します。

SELECT teams.* 
FROM teams 
JOIN collections ON collections.team_id = teams.id 
JOIN events ON events.collection_id = collections.id 
WHERE events.id = ${id} 

彼らは2つの異なる方法で関連することができますので、ウェブフックは、より複雑な取得...

は、「ウェブフックイベント」関連間接的のチームを検索します。

SELECT teams.* 
FROM teams 
JOIN collections ON collections.team_id = teams.id 
JOIN webhooks AS team_webhooks ON team_webhooks.team_id = teams.id 
JOIN webhooks AS collection_webhooks ON collection_webhooks.collection_id = collections.id 
JOIN events AS team_webhook_events ON team_webhook_events.webhook_id = team_webhooks.id 
JOIN events AS collection_webhook_events ON collection_webhook_events.webhook_id = collection_webhooks.id 
WHERE team_webhook_events.id = ${id} 
OR collection_webhook_events.id = ${id} 

私は、パフォーマンスのために優れているか不明私はそのように書くべきであるかどうかわからないんだけど、またはその代わりにUNIONを使用して...

SELECT teams.* 
FROM teams 
JOIN webhooks ON webhooks.team_id = teams.id 
JOIN events ON events.webhook_id = webhooks.id 
WHERE events.id = ${id} 

UNION 

SELECT teams.* 
FROM teams 
JOIN collections ON collections.team_id = teams.id 
JOIN webhooks ON webhooks.collection_id = collections.id 
JOIN events ON events.webhook_id = webhooks.id 
WHERE events.id = ${id} 

...。


ご覧のとおり、特定のチームに1つのイベントを関連付けるには、これらのすべてのパスを使用する方法がたくさんあります。私は「すべての包括的な」クエリを記述しようとするので、それはそれをUNION道をやってスーパー複雑な...

潜在的な解決策#1

なってしまう、私はちょうどクエリの束を作ることができると思います、そしてそれを一緒に組み合わせると、これは無駄かもしれないようですが?

SELECT teams.* 
FROM teams 
JOIN events ON events.team_id = teams.id 
WHERE events.id = ${id} 

UNION 

SELECT teams.* 
FROM teams 
JOIN apps ON apps.team_id = teams.id 
JOIN events ON events.app_id = apps.id 
WHERE events.id = ${id} 

UNION 

SELECT teams.* 
FROM teams 
JOIN collections ON collections.team_id = teams.id 
JOIN events ON events.collection_id = collections.id 
WHERE events.id = ${id} 

UNION 

SELECT teams.* 
FROM teams 
JOIN webhooks ON webhooks.team_id = teams.id 
JOIN events ON events.webhook_id = webhooks.id 
WHERE events.id = ${id} 

UNION 

SELECT teams.* 
FROM teams 
JOIN collections ON collections.team_id = teams.id 
JOIN webhooks ON webhooks.collection_id = collections.id 
JOIN events ON events.webhook_id = webhooks.id 
WHERE events.id = ${id} 

潜在的な解決策#2

使用して、複数のJOIN sが私がteamsとの関係で、一緒にイベントの所有者の異なる組み合わせの全てに参加することができるかもしれないと思いますか?これはまた、JOINの多くのように思えるが...

SELECT teams.* 
FROM teams 

JOIN apps ON apps.team_id = teams.id 
JOIN collections ON collections.team_id = teams.id 
JOIN webhooks AS team_webhooks ON team_webhooks.team_id = teams.id 
JOIN webhooks AS collection_webhooks ON collection_webhooks.collection_id = collections.id 

JOIN events AS app_events ON app_events.app_id = apps.id 
JOIN events AS collection_events ON collection_events.collection_id = collections.id 
JOIN events AS team_events ON team_events.team_id = teams.id 
JOIN events AS collection_webhook_events ON collection_webhook_events.webhook_id = collection_webhooks.id 
JOIN events AS team_webhook_events ON team_webhook_events.webhook_id = team_webhooks.id 

WHERE app_events.id = ${id} 
OR collection_events.id = ${id} 
OR team_events.id = ${id} 
OR collection_webhook_events.id = ${id} 
OR team_webhook_events.id = ${id} 

質問

  • は、これらの潜在的な解決策のいずれかは、それを行うための最善の方法はありますか?
  • もっと効率的な書き方がありますか?
  • 後で読むのが簡単で、読みやすい方法がありますか?

編集:私はこの質問が重複しているとは思いません!

昨日、私は"How to query for nested relationships in SQL?"に似たデータ構造(同じものなので)を尋ねました。同様の方法で書かれました。しかし、私が知る限り、その質問は実際にはです。最初に

、私はどのように求めていた...

はIDによって指定されたユーザーに(直接または間接的に)関連するイベントのすべてを検索します。あるいは、より親しんだIDがあれば、木のようなデータモデルで可能なすべての子孫を見つけます。

しかし、このいずれかで、私は...

は、IDによって、任意のイベントのチームを検索する方法を求めている

より一般的に言えば、階層の任意のレベルで木のようなデータモデルに接続できる任意の "子" IDがあれば、その一致する親を見つけることができます。 (それは本質的に最初の質問の逆です。)

そして私が知る限り、それらはさまざまな解決策を含んでいます。最初は、ツリーをたどってすべてのイベントを収集する際に、一連のクエリを実行する必要があります。 2番目の方法は、私はあまり確かではありませんが、結合されたモデルをすべて構築し、そのうちのどれが特定のイベントに一致するかを確認する必要があるようです。

私はそれを重複ではないとマークするのを手伝ってください!

ダブル編集:いいえ、重複してマークされていません!ありがとう:D

+2

この質問はhttp://stackoverflow.com/questions/43267473/how-to-simply-and-efficiently-query-for-nested-relationships-in-からそれほど異なっていないようですSQL。 –

+1

ここにはUNIONがあります。 –

+0

あるいは、テーブルに常に 'team_id'値を含めるようにスキーマを設計し直すことができます(そして、' MATCH SIMPLE'でマルチカラムの外部キーを使うことができます。この方法では、特定のチームに関連しているオブジェクトを見つけるために高度なクエリを書く必要はありません。 – pozs

答えて

3

IDすることにより、任意のイベントのチームを探す:

は左を取るには、イベント表から参加し、TEAM_IDはそれを使用して返すオブジェクト参照してください。一緒に

select t.* from teams t 
join 
(select coalesce(e.team_id,a.team_id,c.team_id,w.team_id) eteam_id 
from events e left join apps a on e.app_id=a.id 
left join collections c on c.id=e.collection_id 
left join webhooks w on w.id=e.webhook_id 
left join teams t on t.id=e.team_id 
where e.id=1) t1 
on t.id=eteam_id; 
+0

'select coalesce(e.team_id、a.team_id、c.team_id、w.team_id)を使用すると、ヌルの束の中に一つのフィールドが返されます。 –

+0

@ Stefano Zanini正しい答えを編集しました。 – bazinga012

2

だけOR条件:

select coalesce(e.team_id,a.team_id,c.team_id,w.team_id) eteam_id 
from events e 
    left join apps a on e.app_id=a.id 
    left join collections c on c.id=e.collection_id 
    left join webhooks w on w.id=e.webhook_id 
    left join teams t on t.id=e.team_id 
where e.id=${id}; 

ちょうど完全を期すために、あなたは、得られたチームのすべてのデータが必要な場合は。

あなたはteamsにのみ関心があるので、あなたがに必要いけないは、唯一の他のテーブル内の特定(マッチング)値を持つレコードの存在のために(重複を生成することができること)他のテーブルを結合します。


SELECT * 
FROM teams t 
WHERE EXISTS (
     SELECT 1 
     FROM events e 
     WHERE e.SOME_FIELD = SOME_EVENT 
     AND 
      ( team_id = t.id -- direct reference 
     OR EXISTS (   -- reference via webhooks 
       SELECT 1 FROM webhooks w 
       WHERE w.id = e.webhook_id 
       AND w.team_id = t.id 
       ) 
     OR EXISTS (   -- reference via apps 
       SELECT 1 FROM apps a 
       WHERE a.id = e.app_id 
       AND a.team_id = t.id 
       ) 
     OR EXISTS (   -- reference via collections 
       SELECT 1 FROM collections c 
       WHERE c.id = e.collection_id 
       AND c.team_id = t.id 
       ) 
     OR EXISTS (   -- reference via webhooks*collections 
       SELECT 1 FROM webhooks w 
       JOIN collections c ON w.collection_id = c.id 
       WHERE w.id = e.webhook_id 
       AND c.team_id = t.id 
       WHERE c.team_id = t.id 
       ) 
     ) 
     ) ; 
関連する問題