【问题标题】:Left Outer Join Not Working?左外连接不起作用?
【发布时间】:2012-09-10 04:05:02
【问题描述】:

我有一个使用 LEFT OUTER JOIN 从三个表中提取数据的查询,用于两个连接。我需要查询返回最左边的(Salesrep 表)信息,即使两个右表(分别为处方者和处方)中没有相应的数据。当我在 WHERE 子句中不带日期参数运行此查询时,我得到了预期的回报,但是一旦我包含日期参数,我就没有返回任何内容,因为销售代表没有匹配的数据。我至少需要查看查询中请求的 salesrep 表列。

这是查询...非常感谢任何帮助。

SELECT  salesrep.salesrepid as SalesRepID,
        salesrep.fname as SalesrepFName,
        salesrep.lname as SalesRepLName,
        salesrep.fname+' '+salesrep.lname as SalesRepFullName,
        prescriber.dea_no as PDeaNo,
        prescriber.lname+', '+prescriber.fname as DocName,
        CONVERT(VARCHAR(8), prescriptions.filldate, 1) as FillDate,
        prescriptions.drugname as DrugName,
        prescriptions.daysupply as Supply,
        prescriptions.qtydisp as QtyDisp,
        prescriptions.rx_no as Refill,
        prescriptions.copay as Sample,
        ROUND(prescriptions.AgreedToPay-(prescriptions.AgreedToPay*.07),2) as AgreedToPay,
        prescriptions.carrierid as CarrierID
FROM    salesrep
  LEFT OUTER JOIN prescriber on salesrep.salesrepid = prescriber.salesrepid
  LEFT OUTER JOIN prescriptions on prescriber.dea_no = prescriptions.dea_no
  WHERE salesrep.salesrepid = 143 AND
        prescriptions.filldate >= '09-01-12' AND
        prescriptions.filldate <= '09-17-12'
ORDER BY prescriptions.filldate

【问题讨论】:

  • 什么 DBMS? (题外话,但我讨厌药品代表和药品行业)
  • @njk(题外话)考虑到媒体对该行业的强烈偏见,这一点也不奇怪 :)

标签: sql join reporting-services


【解决方案1】:

您应该将prescriptions.filldate 上的约束移动到连接的ON 条件中,并将其从where 子句中删除:

LEFT OUTER JOIN prescriptions ON prescriber.dea_no = prescriptions.dea_no
                             AND prescriptions.filldate >= '09-01-12'
                             AND prescriptions.filldate <= '09-17-12'

否则,没有prescriptions 的条目在prescriptions.filldate 中以nulls 结尾,WHERE 子句将它们丢弃。

【讨论】:

  • 我犯了完全一样的错误,把where误用为on似乎是一个常见的问题
  • 过去两天我一直在寻找这个。非常感谢
【解决方案2】:

Here 您可以找到关于查询处理阶段的简要说明(这对于大多数 DBMS 来说很常见)。你会在那里发现,对于 OUTER JOIN:

  1. 产生第一个笛卡尔连接,
  2. 比对生成行子集的结果集执行 ON 条件,
  3. 在外部行之后,在内表的连接列上附加 NULL,
  4. 在该结果上应用 WHERE 子句执行过滤。

当您将条件放在触及外部表行的 WHERE 子句中时,它们都会被丢弃。您应该简单地将该条件放在 ON 子句中,因为该条件是在附加外部行之前评估的。

那么,这些条件:

prescriptions.filldate >= '09-01-12' AND
prescriptions.filldate <= '09-17-12'

应该移到ON子句中。

【讨论】:

    【解决方案3】:

    这个fiddle 可以用来说明:

    放在 ON 子句中的限制在连接之前处理,而放在 WHERE 子句中的限制在连接之后处理。

    请注意,内连接无关紧要,但外连接很重要。更多详情docs


    表 t1

    | num | name |
    | --- | ---- |
    | 1   | a    |
    | 2   | b    |
    | 3   | c    |
    

    表 t2

    | num | value |
    | --- | ----- |
    | 1   | xxx   |
    | 3   | yyy   |
    | 5   | zzz   |
    

    ON子句中的连接条件

    SELECT * FROM t1 
    LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';
    
    | num | name | num | value |
    | --- | ---- | --- | ----- |
    | 1   | a    | 1   | xxx   |
    | 2   | b    |     |       |
    | 3   | c    |     |       |
    

    WHERE 子句中的连接条件

    SELECT * FROM t1 
    LEFT JOIN t2 ON t1.num = t2.num 
    WHERE t2.value = 'xxx';
    
    | num | name | num | value |
    | --- | ---- | --- | ----- |
    | 1   | a    | 1   | xxx   |
    

    View on DB Fiddle

    【讨论】:

      【解决方案4】:

      这是因为您的 prescriptions.filldate 不等式正在过滤掉您的 salesrep 行,这些行在 prescriptions.filldate 列中没有值。

      因此,如果有空值(右表中没有匹配的数据),那么包括 salesrep 数据在内的整行都会被日期过滤器过滤掉 - 因为null 不在两个日期之间。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-15
        • 1970-01-01
        • 2015-12-02
        • 2019-02-02
        相关资源
        最近更新 更多