左连接与复合连接子句

时间:2009-09-02 14:41:48

标签: sql mysql

我有两张桌子,想要加入他们。 我想要帐户表中的所有条目,但只需要与右表中的条件匹配的行。如果没有匹配的条件,我只想要该帐户。

以下内容无效:

SELECT * FROM Account a
LEFT JOIN 
 Entries ef ON ef.account_id = a.account_id AND
(ef.entry_period_end_date BETWEEN $periodStartDate_escaped AND LAST_DAY(date_add( $periodStartDate_escaped, INTERVAL $periodLengthInMonths_escaped MONTH)) 
OR
ef.forecast_period_end BETWEEN $periodStartDate_escaped AND LAST_DAY(date_add( $periodStartDate_escaped, INTERVAL $periodLengthInMonths_escaped MONTH))
OR
ef.entry_period_end_date IS NULL 
OR 
ef.forecast_period_end IS NULL
)

因为它还为我提供了条目表中的行,这些行超出了请求的时间段。

示例数据:

Account Table
AccountID | AccountName
1           Test
2           Foobar
3           Test1
4           Foobar2


Entries Table
id | AccountID | entry_period_end_date | forecast_period_end | amount
1    1           12/31/2009              12/31/2009            100
2    1           NULL                    10/31/2009            150
3    2           NULL                    NULL                  200
4    3           10/31/2009              NULL                  250
5    4           10/31/2009              10/31/2009            300

所以查询应该返回(当我设置startDate = 12/01/2009,endDate 12/31/2009)

AccountID | id
1           1
2           NULL
3           NULL
4           NULL

THX, 马丁

2 个答案:

答案 0 :(得分:1)

如果entry_period_end_dateforecast_period_endNULL,则系统会返回该行,即使您的其他非NULL列不在此期间内。

可能你的意思是:

SELECT  *
FROM    Account a
LEFT JOIN 
        Entries ef
ON     ef.account_id = a.account_id
       AND
       (
       entry_period_end_date BETWEEN …
       OR forecast_period_end BETWEEN …
       )

,它将在给定时间段内返回包含entry_period_endforecast_period_end的所有行。

<强>更新

测试脚本:

CREATE TABLE account (AccountID INT NOT NULL, AccountName VARCHAR(100) NOT NULL);

INSERT
INTO     account
VALUES
(1, 'Test'),
(2, 'Foobar'),
(3, 'Test1'),
(4, 'Foobar1');

CREATE TABLE Entries (id INT NOT NULL, AccountID INT NOT NULL, entry_period_end_date DATETIME, forecast_period_end DATETIME, amount FLOAT NOT NULL);

INSERT
INTO    Entries
VALUES
(1, 1, '2009-12-31', '2009-12-31', 100),
(2, 1, NULL, '2009-10-31', 100),
(3, 2, NULL, NULL, 100),
(4, 3, '2009-10-31', NULL, 100),
(5, 4, '2009-10-31', '2009-10-31', 100);

SELECT  a.*, ef.id
FROM    Account a
LEFT JOIN
        Entries ef
ON      ef.accountID = a.accountID
        AND
        (
        entry_period_end_date BETWEEN '2009-12-01' AND '2009-12-31'
        OR forecast_period_end BETWEEN '2009-12-01' AND '2009-12-31'
        );

返回以下内容:

1, 'Test',    1
2, 'Foobar',  NULL
3, 'Test1',   NULL
4, 'Foobar1'  NULL

答案 1 :(得分:1)

修改逻辑以便将结束日期逻辑组合在一起,然后预测期间逻辑......

现在它应该检查“好”结束日期(空或在范围内),然后检查“好”预测日期(空或在范围内)

由于所有逻辑都在条目表上,因此先将其缩小,然后加入

    SELECT a.*,temp.id FROM Account a
LEFT JOIN 
 (
    SELECT id, account_id
    FROM Entries ef
    WHERE
    ((ef.entry_period_end_date BETWEEN $periodStartDate_escaped AND LAST_DAY(date_add( $periodStartDate_escaped, INTERVAL $periodLengthInMonths_escaped MONTH)) 
    OR
    ef.entry_period_end_date IS NULL
    )
AND
    (ef.forecast_period_end BETWEEN $periodStartDate_escaped AND LAST_DAY(date_add( $periodStartDate_escaped, INTERVAL $periodLengthInMonths_escaped MONTH))

    OR 
    ef.forecast_period_end IS NULL
)
 ) temp
ON a.account_id = temp.account_id