Mysql

如何編寫正確的查詢來加入所有這些表而不會重複?

  • April 23, 2018

假設我有四個表:

TABLE:    players
COLUMNS:  id, first_name, last_name

TABLE:    passing_stats
COLUMNS:  id, year, passing_yards (several other passing columns)

TABLE:    rushing_stats
COLUMNS:  id, year, rushing_yards (several other rushing columns)

TABLE:    receiving_stats
COLUMNS:  id, year, receiving_yards (several other receiving columns)

假設 Michael Vick 的 id 為 100。我想得到他的全名和他每年的所有統計數據(傳球、衝球和接球)。

我不想要任何重複數據,這意味著 2011 年的快速統計數據應該與 2011 年的通過統計數據出現在同一行中。

編寫此查詢的最優雅的方式是什麼?謝謝。

以下將在 Postgres 中工作。在這裡測試:SQL-Fiddle,postgres-test。SQL-Server 沒有NATURAL JOIN,MySQL 有NATURAL但沒有FULL連接:

SELECT
   id,
   first_name,
   last_name,
   year,
   passing_yards,
   rushing_yards,
   receiving_yards
 FROM 
     players p 
   NATURAL LEFT JOIN 
     ( passing_stats pas
     NATURAL FULL JOIN 
       rushing_stats rus
     NATURAL FULL JOIN 
       receiving_stats rec 
     )
SELECT p.first_name
    , p.last_name
    , year
    , pas.passing_yards
    , rus.rushing_yards
    , rec.receiving_yards
FROM   players p 
LEFT   JOIN (
           (SELECT * FROM passing_stats   WHERE id = 100) pas
FULL   JOIN (SELECT * FROM rushing_stats   WHERE id = 100) rus USING (id, year)
FULL   JOIN (SELECT * FROM receiving_stats WHERE id = 100) rec USING (id, year)
  ) USING (id)
WHERE  p.id = 100
ORDER  BY year;

子查詢是核心功能 - 儘早減少到相關行,這應該會產生最佳性能

@ypercube 的想法NATURAL JOIN甚至更短一些,但在查詢或基礎表發生更改時更容易中斷。USING出於類似的原因,有些人甚至在較小程度上對該條款皺眉。但在這種情況下,它使查詢簡短易讀。

LEFT JOIN返回根本沒有統計數據的球員。

備用查詢

我的第一個想法基本上是@kgrittn’s query的變體。我的修復有點侵入性,所以我發布了另一個答案。需要 PostgreSQL 8.4 或更高版本。

WITH x AS (SELECT 100 AS id)
  , y AS (
 SELECT year FROM x JOIN passing_stats USING (id)
 UNION
 SELECT year FROM x JOIN rushing_stats USING (id)
 UNION
 SELECT year FROM x JOIN receiving_stats USING (id)
 )
SELECT p.first_name
    , p.last_name
    , y.year
    , s.passing_yards
    , r.rushing_yards
    , c.receiving_yards
FROM  (x CROSS JOIN y)
JOIN   players p USING (id)
LEFT   JOIN passing_stats s USING (id, year)
LEFT   JOIN rushing_stats r USING (id, year)
LEFT   JOIN receiving_stats c USING (id, year)
ORDER  BY y.year;

db<>在這裡擺弄

引用自:https://dba.stackexchange.com/questions/16383