mysql - 速度 - sql in句 パフォーマンス




リソース、トピック、および章について正規化されたDBでGROUP BYを使用してJOINする (2)

私はDBを正規化しましたが、私が探しているデータを正しい方法で返すようには見えません。

私は5つのテーブルを持っている:

  1. リソース(5リソース)
  2. トピック(10トピック)
  3. 章(10章)
  4. トピックスからリソースへ(トピックからリソースへの18のリンク)
  5. トピック - 章(トピック - 章間のリンク18件)

このSQL Fiddleをチェックしてください...

私は、Resourcesテーブルのすべてのレコードを収集し、それぞれを対応するトピックと章(Topics-to-ResourcesとTopics-to-Chaptersの表から)でグループ化する必要があります。

5つのリソースレコードを出席するトピックと章を返すための正しいSQLクエリを誰でも提案できますか?

私はGROUP BYでJOINSを試しましたが、これはレコードセットを5つのリソースに集約しますが、私が必要とする他の情報(トピックと章)はすべて集約しません。

SELECT * FROM TOPICS, CHAPTERS, RESOURCES AS RES
INNER JOIN TOPICS_to_RESOURCE AS TR ON RES.RES_ID = TR.TR_RESID
INNER JOIN TOPICS_to_CHAPTER AS TCH ON TR.TR_TID = TCH.TCH_TID
GROUP BY RES.RES_ID

これは標準ではない構文です:

SELECT *
...
GROUP BY RES.RES_ID

ここでは、すべての列(select *)を要求しましたが、group byの下に指定された1つの列のみが要求されています。 ONLY MySQLは、サーバー設定によって制御されるこの非標準のGROUP BY構文を許可します。 これらのデフォルト設定は最近変更されており、今後非標準のGROUP BYを使用した多くのクエリが失敗する可能性があります。

標準準拠のGROUP BY句は、すべての「非集約」列を指定します。 つまり、SUM / COUNT / AVG / MIN / MAXなどを使用しないすべての列を指定する必要があります。

SELECT * FROM TOPICS, CHAPTERS, RESOURCES AS RES
INNER JOIN TOPICS_to_RESOURCE AS TR ON RES.RES_ID = TR.TR_RESID
INNER JOIN TOPICS_to_CHAPTER AS TCH ON TR.TR_TID = TCH.TCH_TID
GROUP BY RES.RES_ID

このクエリには、2つの形式の結合構文があります。 ** FR1 t1、t2、t3 **は古くて賢明ではありません。 また、 この古い構文形式を、クエリエラーにつながる可能性のある単一のクエリのより新しい結合構文と「結合する」ことは決してありません。

from節の表の間にカンマを使用しないでください。この単純な手順は、すべての時間のより良い構文を使用するようにします。

ちなみに、 TOPICS、CHAPTERS、RES RESURURCES RESでwhere節でこれらを制限するものはありません:

TOPICSのすべての行にCHAPTERSのすべての行をRESOURCESのすべての行で掛けます。 言い換えれば、 "デカルト製品"である。 より最近の構文では、クエリは次のように変換されます。

SELECT * FROM TOPICS
CROSS JOIN CHAPTERS
CROSS JOIN RESOURCES AS RES
INNER JOIN TOPICS_to_RESOURCE AS TR ON RES.RES_ID = TR.TR_RESID
INNER JOIN TOPICS_to_CHAPTER AS TCH ON TR.TR_TID = TCH.TCH_TID
GROUP BY RES.RES_ID

私はあなたが達成しようとしているものを本当に区別することはできませんが、話題とリソースを持つすべての章を表示する表を探しているように思えます。

その場合は、次のSQLを実行します。

select * from resources r
JOIN topics_to_resource ttr ON ttr.tr_resid = r.res_id
JOIN topics t on t.t_id = ttr.tr_tid
JOIN topics_to_chapter ttc on ttc.tch_tid = t.t_id
JOIN chapters ch ON ch.ch_id = tch_chid
ORDER BY r.res_id;

http://sqlfiddle.com/#!9/ddf252/12のとおり 、それだけを返します。

または、selectで結合IDを無視する:

select r.res_id, r.res_name, t.t_id, t.t_name, ch.ch_id, ch.ch_name from resources r
JOIN topics_to_resource ttr ON ttr.tr_resid = r.res_id
JOIN topics t on t.t_id = ttr.tr_tid
JOIN topics_to_chapter ttc on ttc.tch_tid = t.t_id
JOIN chapters ch ON ch.ch_id = tch_chid
ORDER BY r.res_id, t.t_id, ch.ch_id

http://sqlfiddle.com/#!9/ddf252/14に従って

それがあなたが探しているものではないなら、あなたが見たいと思っている結果についてちょっと説明できますか?

編集 :すべての関連レコードを含むより簡潔なリストを返す

select 
CONCAT(r.res_id,': ',r.res_name) 'Resources', 
GROUP_CONCAT(CONCAT(' (',t.t_id,': ',t.t_name,')')) 'Topics', 
GROUP_CONCAT(CONCAT(' (',ch.ch_id,': ',ch.ch_name,')')) 'Chapters'
from resources r
JOIN topics_to_resource ttr ON ttr.tr_resid = r.res_id
JOIN topics t on t.t_id = ttr.tr_tid
JOIN topics_to_chapter ttc on ttc.tch_tid = t.t_id
JOIN chapters ch ON ch.ch_id = tch_chid
GROUP BY r.res_id
ORDER BY r.res_id, t.t_id, ch.ch_id

http://sqlfiddle.com/#!9/ddf252/30に従って

最後に 、これらを章とトピックでグループ化する:

select 
CONCAT(res_id,': ',res_name) 'Resources', 
GROUP_CONCAT(`chapters` order by chapters separator '\n') as 'Content'
FROM
  (SELECT r.res_id 'res_id',
          r.res_name 'res_name', 
          t.t_id 't_id',
          t.t_name 't_name',
          CONCAT(t.t_name,': (',GROUP_CONCAT(ch.ch_name ORDER BY t.t_name separator ','),')') 'Chapters'
    FROM resources r
      JOIN topics_to_resource ttr ON ttr.tr_resid = r.res_id
      JOIN topics t on t.t_id = ttr.tr_tid
      JOIN topics_to_chapter ttc on ttc.tch_tid = t.t_id
      JOIN chapters ch ON ch.ch_id = tch_chid
    GROUP BY res_id, t_id
    ORDER BY r.res_id, t.t_id, ch.ch_id) as t
GROUP BY res_id

ここに見られるように: http : //sqlfiddle.com/# !9/ ddf252 / 85

私は結果をチェックしたが、彼らはうまく見える - しかし、ダブルチェック、それは私の頭の中にMySQLの開始のように少し行った(それはここで1am過去)

さらに追加:リソースごとに異なる値

    select CONCAT(r.res_id,': ',r.res_name) 'Resources', GROUP_CONCAT(distinct t_name separator ',') 'Topics', 
GROUP_CONCAT(distinct ch.ch_name separator ',') 'Chapters'
from resources r
JOIN topics_to_resource ttr ON ttr.tr_resid = r.res_id
JOIN topics t on t.t_id = ttr.tr_tid
JOIN topics_to_chapter ttc on ttc.tch_tid = t.t_id
JOIN chapters ch ON ch.ch_id = tch_chid
GROUP BY r.res_id
ORDER BY r.res_id, t.t_id, ch.ch_id

http://sqlfiddle.com/#!9/ddf252/88を参照してください。





normalization