2011-03-04 203 views
0

我在MySQL(5.1)中有3個表: account,bank_account_data和investment_account_data。MySQL左連接問題

表是定義如下: (注:這是一個簡化版本的實際表具有更多的列,銀行和投資數據有不是需要這種特殊情況下,但在其他地方需要不同的信息)

CREATE TABLE account 
(
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 
    type ENUM ('INVESTMENT', 'BANK') NOT NULL, 
    PRIMARY KEY (id) 
) ENGINE=InnoDB; 

CREATE TABLE investment_account_data 
(
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 
    account_id BIGINT UNSIGNED NOT NULL, 
    as_of_date TIMESTAMP NULL DEFAULT NULL, 
    total_balance NUMERIC(12, 4) NOT NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY (account_id) REFERENCES account (id), 
    CONSTRAINT unique_per_account_and_date UNIQUE (account_id, as_of_date) 
) ENGINE=InnoDB; 

CREATE TABLE bank_account_data 
(
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, 
    account_id BIGINT UNSIGNED NOT NULL, 
    as_of_date TIMESTAMP NULL DEFAULT NULL, 
    current_balance NUMERIC(12, 4) NOT NULL, 
    PRIMARY KEY (id), 
    FOREIGN KEY (account_id) REFERENCES account (id), 
    CONSTRAINT unique_per_account_and_date UNIQUE (account_id, as_of_date) 
) ENGINE=InnoDB; 

目前我在帳戶表中只有一個帳戶,id = 1,type ='INVESTMENT' ,我在investment_account_data表中有一條記錄(id = 1,account_id = 1,total_balace = 15000,as_of_data ='2011 -03-02 00:00:00')

the bank_account_data沒有行。

運行下面的查詢(奇怪)不返回行:

SELECT A.id as account_id, 
     COALESCE(BD.as_of_date, ID.as_of_date) as as_of_date, 
     COALESCE(BD.current_balance, ID.total_balance) as balance 
    FROM account A 
     LEFT JOIN bank_account_data BD ON (BD.account_id = A.id and A.type='BANK') 
     LEFT JOIN investment_account_data ID ON (ID.account_id = A.id and A.type='INVESTMENT') 
WHERE A.id=1 

但是這一次返回一行(預期):

SELECT A.id as account_id, 
     COALESCE(BD.as_of_date, ID.as_of_date) as as_of_date, 
     COALESCE(BD.current_balance, ID.total_balance) as balance 
FROM account A 
     LEFT JOIN investment_account_data ID ON (ID.account_id = A.id and A.type='INVESTMENT') 
     LEFT JOIN bank_account_data BD ON (BD.account_id = A.id and A.type='BANK') 
WHERE A.id=1 

任何想法,爲什麼我看到這些結果?

此外,如果我從連接中刪除A.type條件它也將返回一行。

+0

我會通過將測試行的類型字段更改爲BANK來測試這些查詢。假定第一個查詢會返回一行,第二個查詢將不返回任何行。 – 2011-03-04 01:36:40

+0

更改爲鍵入'BANK'確實會在第一個查詢中返回一行,而在第二個查詢中不會返回任何行。 – talg 2011-03-04 01:39:58

回答

1

我敢肯定,看到的行爲的原因是,你在第一個連接子句上的類型字段上創建了一個篩選器,該篩選器屏蔽了第二個連接子句中的所有帳戶。

  1. 選擇所有帳戶匹配型「銀行」
  2. 與相應的銀行賬戶信息
  3. 加入他們選擇所有帳戶匹配型「投資」的,即所有帳戶匹配型「銀行」設置最後的結果離開
  4. 加入具有相應投資賬戶信息的空集。

的修復

髒和壞的方式做到這一點是創建一套不同的連接條件

SELECT A.id as account_id, 
     COALESCE(BD.as_of_date, ID.as_of_date) as as_of_date, 
     COALESCE(BD.current_balance, ID.total_balance) as balance 
FROM account A 
     LEFT JOIN investment_account_data ID ON (ID.account_id = A.id) 
     LEFT JOIN bank_account_data BD ON (BD.account_id = A.id) 
WHERE 
     A.id=1 
     AND ((ID.account_id is not null and A.TYPE='INVESTMENT') 
      OR 
      (BD.account_id is not null and A.TYPE = 'BANK')) 

不必使用或類似的讓我覺得有什麼東西臭約數據庫模式。你可以用一個更適合這裏的UNION來做同樣的事情。

在我看來,你的意圖是該賬戶可以是銀行賬戶或投資賬戶。數據庫模式不會強制執行,因此導致需要在此問題中詳細討論這樣的查詢。帳戶表的目的似乎是爲所有帳戶ID提供一個空間。它可以用一個序列來代替。根據目前的定義,我也不確定你需要有不同的銀行賬戶和投資賬戶表。你可以對兩個表格做同樣的處理,一個包含賬戶信息,另一個包含每個日期的賬戶餘額。

+0

您能否顯示查詢不確定我在追蹤點3和4 – talg 2011-03-04 01:47:54

+0

這個查詢是可行的,但您爲什麼認爲架構 – talg 2011-03-04 01:50:24

+0

Aleksi存在問題,這是我們當前數據庫的簡化版本,賬號表包含還有更多的列,投資賬戶數據和bank_account_data也如此 – talg 2011-03-04 02:02:39

1

這正是您在發佈查詢和數據時應該期待的輸出。

在您的第一個查詢中,第一個連接條件指定A.type = 'BANK'。因此,在第一個LEFT JOIN之後,您有一個零行結果集,然後您再次登錄LEFT JOIN。如果您的「左側」爲零行,則LEFT JOIN(或INNER JOIN)將始終返回零行。

對於第二個查詢,順序顛倒。所以,在第一次連接之後,你有一個單行結果集。您現在在第二次加入時在「左側」有1行。

+0

我認爲條件是在聯接(因爲它全部在ON子句中),所以在第一次左連接後,我仍然有單行結果集 – talg 2011-03-04 02:06:59

0

問題在於處理左連接的方式和A.type條件。 UNION將是您正在嘗試做的更合適的操作員。

SELECT account_id, as_of_date, current_balance as balance 
     FROM bank_account_data 
UNION 
SELECT account_id, as_of_date, total_balance as balanceas 
     FROM investment_account_data 

(插入加入櫃面你需要從帳戶表附加信息)

你也可能要重新考慮你的數據庫佈局一般和合並三者合而爲一,如果他們真的具有相同的屬性只有類型不同。