代码之家  ›  专栏  ›  技术社区  ›  Derek Adair

WHERE子句导致表省略左联接规则

  •  2
  • Derek Adair  · 技术社区  · 15 年前

    我基本上是想修改 this 存储过程。

    已修改的存储过程:

    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=客户

    我绞尽脑汁想弄明白为什么它忽略了零。

    拆除时 WHERE p.ClientId = client 过程开始返回空值…

    为什么WHERE子句将空行省略?我可能误解了什么 确切地 LEFT JOIN 是。

    我该怎么过滤 SUM(p.Amount) 只返回和的结果 WHERE clientId = client ?

    4 回复  |  直到 15 年前
        1
  •  3
  •   Peter Lang    15 年前

    如果你把所有的条件都放到 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
  •  4
  •   Charles Bretana    15 年前

    首先,您的示例代码不是

    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子句条件,因此需要将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
  •  2
  •   D'Arcy Rittich    15 年前

    移动 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 .

        4
  •  0
  •   Romain    15 年前

    问题是=运算符在SQL中不安全为空。 NULL = NULL 是假的。你必须使用空安全等价物,如果我正确地记得是 <=> 关于MySQL。您也可以使用 COALESCE 函数或写入 a=b 作为 (a=b OR a IS NULL or b IS NULL) .