Предложение WHERE, приводящее к тому, что таблица пропускает правило LEFT JOIN - PullRequest
2 голосов
/ 02 февраля 2010

Я пытаюсь изменить эту хранимую процедуру.

Модифицированная хранимая процедура:

CREATE PROCEDURE sp1(d1 date, d2 date, client INT(10))
    declare d datetime;

    create TEMPORARY TABLE foo (d date NOT NULL, Amount INT(10) DEFAULT 0);

    set d = d1;

    while d <= d2 do 
        insert into foo (d) values (d);
        set d = date_add(d, interval 1 day);
    end while;

    SELECT SUM(p.Amount), foo.d
    FROM foo LEFT JOIN ItemTracker_dbo.Payment ON foo.d = p.Datetime
    WHERE p.ClientId = ClientId
    GROUP BY
        foo.d;

    DROP TEMPORARY TABLE foo;
end PROCEDURE

ПРИМЕЧАНИЕ: предложение WHERE ... p.ClientId = client

Я ломал свой мозг, пытаясь понять, почему он пропускает нули.

после удаления WHERE p.ClientId = client процедура начала возвращать NULL ...

Почему в предложении WHERE пропущены пустые строки? Я, вероятно, неправильно понимаю, что такое точно a LEFT JOIN.

Как мне отфильтровать результаты SUM(p.Amount), чтобы получить только сумму WHERE clientId = client?

Ответы [ 4 ]

4 голосов
/ 02 февраля 2010

Прежде всего, не ваш пример кода

SELECT SUM(p.Amount), foo.d 
    FROM foo LEFT JOIN ItemTracker_dbo.Payment ON foo.d = p.Datetime 
    WHERE p.ClientId = ClientId 
    GROUP BY 
        foo.d; 

отсутствует p для псевдонима для таблицы ItemTracker_dbo.Payment ?? то есть не следует читать:

SELECT SUM(p.Amount), foo.d 
    FROM foo 
       LEFT JOIN ItemTracker_dbo.Payment p
            ON foo.d = p.Datetime 
WHERE p.ClientId = ClientId 
GROUP BY foo.d; 

В любом случае, причина возникновения этой проблемы заключается в том, что условия условия не применяются до тех пор, пока не будет обработано внешнее объединение (где строки с внешней стороны добавлены обратно). Поэтому необходимо переместить условие where в условие присоединения:

SELECT SUM(p.Amount), foo.d 
    FROM foo 
       LEFT JOIN ItemTracker_dbo.Payment p
            ON foo.d = p.Datetime 
                And p.ClientId = ClientId 
GROUP BY foo.d; 
3 голосов
/ 02 февраля 2010

Должно работать, если вы поставите все условия в условие LEFT JOIN:

SELECT SUM(p.Amount), foo.d
FROM foo
LEFT JOIN ItemTracker_dbo.Payment p ON foo.d = p.Datetime AND p.ClientId = ClientId
GROUP BY
    foo.d;
2 голосов
/ 02 февраля 2010

Переместите предложение WHERE в предложение ON следующим образом:

SELECT SUM(p.Amount), foo.d
FROM foo LEFT JOIN ItemTracker_dbo.Payment ON foo.d = p.Datetime 
    and p.ClientId = ClientId
GROUP BY
    foo.d;

Поместив сравнение ClientId в предложение WHERE, вы фактически превратили LEFT JOIN в INNER JOIN при ClientId.

0 голосов
/ 02 февраля 2010

Проблема в том, что оператор = не является NULL-безопасным в SQL. NULL = NULL ложно. Вы должны использовать NULL-безопасный эквивалент, который, если я правильно помню, равен <=> в MySQL. Вы также можете использовать функцию COALESCE или написать a=b как (a=b OR a IS NULL or b IS NULL).

...