【问题标题】:Left joined 2 tables, result looks like inner join左连接 2 个表,结果看起来像内连接
【发布时间】:2018-07-03 08:24:21
【问题描述】:

问题可能很简单,但我对 SQL 还很陌生,所以就这样吧。

我想要完成的事情:

我有TableATableBTableA 包含我的大部分数据,但是如果 ID 和日期范围匹配,它应该使用来自 TableB 的数据修改其中一列(修改后的结果)。

这是我的查询:

SELECT 
    t1.ID, t1.a, t1.b, t1.c, t1.d, t1.e, t1.f, t1.g, t1.h, t1.i, 
    (t1.totalcost  - (ISNULL(t2.cost, 0) * ISNULL(t2.qty,0))) AS modified_result, 
    t1.j, t1.k, t1.createdate
FROM 
    TableA as t1
LEFT JOIN 
    TableB AS t2 ON t1.ID = t2.ID
WHERE 
    t1.createdate BETWEEN '2018-06-19' AND '2018-06-23' 
    AND t2.createdate BETWEEN '2018-06-19' AND '2018-06-23' 
    AND t2.trans_type = 'H'
ORDER BY
    t1.createdate

TableA 中大约有 2000 多条记录满足 TableA 的这些条件,而 TableB 中只有少数匹配记录。运行此查询会产生与 TableB 结果相同的行号,这对我来说看起来像是一个内部联接。

我的WHERE 部分可能有误,但我看不到。

【问题讨论】:

  • 永远不要在 where 子句中使用左连接表,否则会变成内连接
  • 所有应用于 T2 的限制都必须在外连接的 ON 子句中。
  • @JaydipJadhav 不知道,谢谢!

标签: sql sql-server-2008 tsql


【解决方案1】:

我不确定技术,但我根据我的工作经验回答你

当您在WHERE 子句中过滤 t2 时。 DBMS 在JOIN 之后过滤整个结果

如果您想使用 subQuery 而不是 t2 保留 t1 的所有行或移动过滤器 t2 以加入条件示例

使用子查询代替 T2

SELECT t1.ID, t1.a, t1.b, t1.c, t1.d, t1.e, t1.f, t1.g, t1.h, t1.i, 
(t1.totalcost  - (ISNULL(t2.cost, 0) * ISNULL(t2.qty,0))) as modified_result, 
t1.j, t1.k, t1.createdate
FROM TableA as t1
LEFT JOIN (
    SELECT *
    FROM TableB t2 
    WHERE t2.createdate between '2018-06-19' and '2018-06-23' and t2.trans_type = 'H'
) AS t2 ON t1.ID = t2.ID
WHERE t1.createdate between '2018-06-19' and '2018-06-23' 
ORDER BY t1.createdate

将过滤器 t2 移动到加入条件

SELECT t1.ID, t1.a, t1.b, t1.c, t1.d, t1.e, t1.f, t1.g, t1.h, t1.i, 
(t1.totalcost  - (ISNULL(t2.cost, 0) * ISNULL(t2.qty,0))) as modified_result, 
t1.j, t1.k, t1.createdate
FROM TableA as t1
LEFT JOIN TableB AS t2 ON t1.ID = t2.ID and t2.createdate between '2018-06-19' and '2018-06-23' and t2.trans_type = 'H'
WHERE t1.createdate between '2018-06-19' and '2018-06-23' 
ORDER BY t1.createdate

上面的代码我没有测试

希望对你有所帮助。

【讨论】:

    【解决方案2】:
    SELECT 
        t1.ID, t1.a, t1.b, t1.c, t1.d, t1.e, t1.f, t1.g, t1.h, t1.i, 
        (t1.totalcost  - (ISNULL(t2.cost, 0) * ISNULL(t2.qty,0))) AS modified_result, 
        t1.j, t1.k, t1.createdate
    FROM 
        TableA as t1
    LEFT JOIN 
        TableB AS t2 ON t1.ID = t2.ID AND t2.createdate BETWEEN '2018-06-19' AND '2018-06-23' 
        AND t2.trans_type = 'H'
    WHERE 
        t1.createdate BETWEEN '2018-06-19' AND '2018-06-23' 
    
    ORDER BY
        t1.createdate
    

    【讨论】:

      【解决方案3】:

      这是你的 where 条件

          WHERE t1.createdate between '2018-06-19' and '2018-06-23' and t2.createdate 
          between '2018-06-19' and '2018-06-23' ***and t2.trans_type = 'H'***
      

      在这里,您的行将根据 trans 类型进行过滤...基本上它是在限制行

      【讨论】:

        【解决方案4】:

        WHERE 子句中包含来自LEFT OUTER JOIN 表的条件不会神奇地将其转换为INNER JOIN;没有“特殊规则”要求您必须在 ON 子句中包含所有条件。

        这里发生的情况是,没有WHERE 子句的查询将返回来自t2 的一些NULL 值,然后您通过包含不包括NULL 值的此别名的条件来排除这些值。

        如果您要像这样重写查询,那么它将按您的意愿工作:

        SELECT t1.ID, t1.a, t1.b, t1.c, t1.d, t1.e, t1.f, t1.g, t1.h, t1.i, 
        (t1.totalcost  - (ISNULL(t2.cost, 0) * ISNULL(t2.qty,0))) as modified_result, 
        t1.j, t1.k, t1.createdate
        FROM TableA as t1
        LEFT JOIN TableB AS t2 ON t1.ID = t2.ID
        WHERE t1.createdate between '2018-06-19' and '2018-06-23' and (t2.createdate IS NULL OR t2.createdate 
        between '2018-06-19' and '2018-06-23') and (t2.trans_type IS NULL OR t2.trans_type = 'H')
        ORDER BY t1.createdate
        

        【讨论】:

        • 嘿,随便投反对票,这并不能改变我所说的一切都是正确的事实;P
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-12
        • 2012-03-13
        • 1970-01-01
        • 2011-06-30
        • 2013-01-30
        • 2017-12-08
        相关资源
        最近更新 更多