2012-07-17 51 views
0

我有5個表中的結構相同。只有PAGEVISITS字段是唯一的MySQL LEFT加入顯示不正確的數據

即。表1:

ITEM | PAGEVISITS | Commodity 
1813  50   Griddle 
1851  10   Griddle 
11875  100   Refrigerator 
2255  25   Refrigerator 

即,表2:

ITEM | PAGEVISITS | Commodity 
1813  0    Griddle 
1851  10   Griddle 
11875  25   Refrigerator 
2255  10   Refrigerator 

我希望它加起來Commodity吐出:

table1 | table2 | Commodity 
60   10   Griddle 
125   35   Refrigerator 

一些數據實際上是正確的,但有些遙遠給出以下查詢:

SELECT 
SUM(MT.PAGEVISITS) as table1, 
SUM(CT1.PAGEVISITS) as table2, 
SUM(CT2.PAGEVISITS) as table3, 
SUM(CT3.PAGEVISITS) as table4, 
SUM(CT4.PAGEVISITS) as table5, 
(COUNT(DISTINCT MT.ITEM)) + (COUNT(DISTINCT CT1.ITEM)) + (COUNT(DISTINCT CT2.ITEM)) + (COUNT(DISTINCT CT3.ITEM)) + (COUNT(DISTINCT CT4.ITEM)) as Total, 
MT.Commodity 
    FROM table1 as MT 
     LEFT JOIN table2 CT1 
     on MT.ITEM = CT1.ITEM 
     LEFT JOIN table3 CT2 
     on MT.ITEM = CT2.ITEM 
     LEFT JOIN table4 CT3 
     on MT.ITEM = CT3.ITEM 
     LEFT JOIN table5 CT4 
     on MT.ITEM = CT4.ITEM 
GROUP BY Commodity 

我相信這可能是由於錯誤地使用了LEFT JOIN導致的。我也嘗試了INNER JOIN,結果相同。

+1

您應該使用'完全外部連接',這在MySQL中不可用。嘗試使用'left outer join'和'right outer join'並將其與'union'結合使用。 – 2012-07-17 15:39:34

+0

你目前獲得什麼結果? – Jocelyn 2012-07-17 15:45:11

回答

2

我會做所有五個這些表,讓他們作爲一個行集(內嵌視圖)的UNION,然後運行上一查詢,像這樣的東西開始...

SELECT SUM(IF(t.source='MT',t.pagevisits,0)) AS table1 
    , SUM(IF(t.source='CT1',t.pagevisits,0)) AS table2 
    , t.commodity 
    FROM (SELECT 'MT' as source, table1.* FROM table1 
      UNION ALL 
     SELECT 'CT1', table2.* FROM table2 
      UNION ALL 
     SELECT 'CT2', table3.* FROM table3 
      UNION ALL 
     SELECT 'CT3', table4.* FROM table4 
      UNION ALL 
     SELECT 'CT4', table5.* FROM table5 
    ) t 
GROUP BY t.commodity 

(但我會爲每個表指定列列表,而不是使用'。*',並讓我的查詢依賴於任何表中沒有人添加/刪除/重命名/重新排列列。)

I include一個「額外」字面值(別名爲「源」)來標識該行來自哪個表。我可以在SELECT列表中的表達式中使用條件測試來確定行是否來自特定的表。

該方法特別靈活,可用於獲取更復雜的結果集。例如,如果我也希望將表3,表4和表5中的總訪問量與個人計數一起加起來。

SUM(IF(t.source IN ('CT2','CT3','CT4'),t.pagevisits,0) AS total_345 

爲了讓您的COUNT(DISTINCT item) + COUNT(DISTINCT item) + ...表達相當於...

我會使用,使得無論從「源」和「項目」列單值的表達式,小心有某種保證,任何特定的「來源」+「項目」不會創建一些其他「來源」+「項目」的副本。 (例如,如果我們只是連接字符串,例如我們沒有辦法區分'A'+'11'和'A1'+'1')。我在這裏看到的最常用的方法是仔細選擇分隔符保證不會出現在任何一個值中。我們之間的「A :: 11」和「A1 :: 1」區分開來,所以像這樣將工作:

COUNT(DISINCT CONCAT(t.source,'::',t.item)) 

在你當前的查詢,如果item爲NULL,則該行不會被列入在COUNT中。完全複製這種行爲,你需要這樣的事:

COUNT(DISINCT IF(t.item IS NOT NULL,CONCAT(t.source,'::',t.item),NULL)) AS Total 

或課程,讓不同的項目值的數量在整個組五個表簡單得多(但後來,它返回不同的結果)

COUNT(DISINCT t.item) 

但是,爲了回答你關於使用LEFT JOIN的問題,左邊的表是「司機」,所以匹配的行必須是該表中的相應行從檢索一張桌子在右邊。也就是說,右側表格中不匹配的行將不會被返回。

如果你有什麼基本上是5個「分區」,並且你想要處理所有的行,無論匹配的行是否出現在任何其他的「分區」中,我會採用UNION ALL的方法來簡單地連接將所有這些表中的所有行組合在一起,並像處理單個表一樣處理這些行。

注意:對於非常大的表,這可能不是一種可行的方法,因爲MySQL將不得不實現該內聯視圖。還有其他方法不需要將所有行連接在一起。

如果這些表中的列不需要在查詢中引用,那麼在每個表的SELECT中指定僅需要的列的列表可能有助於提高性能。