2014-09-26 83 views
0

我在mysql中有一個查詢有問題。 我有2個表:表A和B表查詢Mysql - 爲兩個表中不存在的值返回0

表A:

名稱 - 總

法國| 20
西班牙| 10
英國| 5
意大利| 10
法國| 5

表B

名稱

法國
西班牙
意大利
法國
希臘

我的目標是獲得總變量的總和爲每表B中的值,即:

法國| 25
西班牙| 10
意大利| 10
法國| 5
希臘| 0

我的問題是,當表B中值表A

不存在在這個時刻,我不能把它返回0,我有這個疑問:

select B.name, SUM(A.total) 
from table A , table B 
where A.name = B.name 
group by B.name 
having count(B.name)>1 

任何人都可以幫助我? 謝謝!

回答

1

從表B有表A沒有匹配行返回行,你可以使用一個「外」連接操作。

首先,拋棄連接操作的舊式逗號語法,並使用JOIN關鍵字代替。要指定一個「外」的「JOIN」關鍵字之前加入使用關鍵字「LEFT」,把驅動表(表B,你想從返回行的所有表上的左側JOIN。並移動執行從WHERE子句兩個表之間的「匹配」的ON子句比較謂詞。

在該例子中的數據,我注意到被「複製」,在表nameB(例如'France'),並告訴你結果集包含了這兩行:

France | 25 
France | 5 

我們可以看到,第一行是如何產生,從表A 2個'France'行中的值的總和,但第二排,這是一個難以解決的問題。 (也許這就是你的查詢中的HAVING子句是試圖處理什麼?)

因此,爲了簡化事情,我將繼續假設示例輸出中的第二個France行不是實際的在結果

基於示例數據,以及指定的結果(除第二France 5行)需要,我們可以做這樣的事情,使用內嵌視圖從B得到name明顯的列表。

SELECT d.name 
    , IFNULL(SUM(a.total),0) AS total 
    FROM (SELECT b.name 
      FROM B b 
      GROUP BY b.name 
     ) d 
    LEFT 
    JOIN A a 
    ON a.name = d.name 
GROUP BY d.name 

如果表B實際上並沒有重複值name,而是具有'England'的地方,第二'France'排的,結果應該包括England | 5,而不是France | 5 ...

如果我們有一個保證name列在表B UNIQUE,我們可以消除內嵌視圖,只是這樣做:

SELECT b.name 
    , IFNULL(SUM(a.total),0) AS total 
    FROM B b 
    LEFT 
    JOIN A a 
    ON a.name = b.name 
GROUP BY b.name 

上面的查詢是返回結果像你描述的一個規範的模式,但它並不是唯一的模式。還有其他幾種形式也會返回相同的結果。

作爲一種不同的方法的演示,其中一個不使用連接操作:

SELECT b.name 
    , IFNULL(SELECT SUM(a.total) FROM A a WHERE a.name = b.name) AS total 
    FROM B b 

這種方法通常不執行,以及在加入了大量的行從B返回。 (使用小套件時,我們沒有注意到有什麼區別,但是大套件的性能差異會變得明顯。)

1

我從您的問題中看不到您爲什麼需要COUNT(b.name) > 1。但這兩方面的信息,可以這樣回收:

-- Test data 
CREATE TABLE a (name varchar(20), total integer); 
CREATE TABLE b (name varchar(20)); 

INSERT INTO a VALUES ('France', 20), ('Spain', 10), 
('England', 5), ('Italy', 10), ('France', 5); 

INSERT INTO b VALUES ('France'), ('Spain'), ('Italy'), ('France'), ('Greece'); 


    SELECT c.name, 
    COALESCE(d.number, 0) AS rows, 
    COALESCE(e.total, 0) AS total 
FROM 
    (SELECT DISTINCT name FROM a 
    UNION 
    SELECT DISTINCT name FROM b 
    ) AS c 
LEFT JOIN 
    ( SELECT name, COUNT(1) AS number FROM b GROUP BY name) AS d 
    ON (c.name = d.name) 
LEFT JOIN 
    ( SELECT name, SUM(total) AS total FROM a GROUP BY name) AS e 
    ON (c.name = e.name); 

這是效率非常低,但它的工作。如果不需要實際上需要諸如b行數等信息,那麼查詢可能會大大簡化。

以上是結果,

name rows total 
France 2  25 
Spain 1  10 
England 0  5 
Italy 1  10 
Greece 1  0 

注意,「行」是指將b表中的行。所以你可以有0行,就像英格蘭一樣。如果條件是一個或多個(在您指定的問題中您指定> 1,那麼兩個或多個),將會更容易JOIN表。

要簡單

我的目標是獲得總變量的總和每個值表B中

你可以首先從B選擇獨特的國名,然後LEFT JOIN反對錶A的總計。要解決您使用COALESCE的缺失國家/地區的NULL值的問題。

SELECT c.name, COALESCE(d.total, 0) AS total 
FROM 
    (SELECT DISTINCT name FROM b) AS c 
LEFT JOIN 
    (SELECT name, SUM(total) AS total FROM a GROUP BY name) AS d 
ON (c.name = d.name) 

France 25 
Spain 10 
Italy 10 
Greece 0 

或者:

SELECT c.name, SUM(COALESCE(a.total, 0)) AS total 
FROM 
    (SELECT DISTINCT name FROM b) AS c 
LEFT JOIN 
    a 
ON (c.name = a.name) 
GROUP BY c.name 

如果你能有B中唯一的國家名稱,你可以在查詢與b取代(SELECT DISTINCT name FROM b) AS c(當然那麼c小號也成爲b)。

+0

+1。有幾點需要注意:第一條語句中的內聯視圖中的「DISTINCT」並不是絕對必要的,因爲'UNION'操作將消除重複。此外,內聯視圖對錶A進行查詢以獲得COUNT()和SUM()可以合併爲一個內聯視圖;但內聯視圖查詢不是絕對必要的。 – spencer7593 2014-09-26 23:58:19