2011-03-04 201 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 

(插入加入柜面你需要从帐户表附加信息)

你也可能要重新考虑你的数据库布局一般和合并三者合而为一,如果他们真的具有相同的属性只有类型不同。