左外连接不起作用?

时间:2012-09-17 22:04:22

标签: sql join reporting-services

我有一个查询从三个表中使用LEFT OUTER JOIN为两个连接提取数据。我需要查询返回最左边的(Salesrep表)信息,即使两个右表中没有相应的数据(分别是开处方者和处方药)。当我在WHERE子句中没有日期参数的情况下运行此查询时,我得到了预期的返回值,但是一旦我包含日期参数,我就不会返回任何没有salesrep匹配数据的地方。我至少需要查看查询中请求的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

4 个答案:

答案 0 :(得分:64)

您应该将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中没有null的{​​{1}}结尾的条目和prescriptions.filldate条款会将它们抛弃。

答案 1 :(得分:14)

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

  1. 首次制作CARTESIAN JOIN,
  2. 而不是对生成行子集的结果集执行ON条件
  3. 之后,外部行在内部表的连接列上附加了NULL,
  4. 在该结果上应用WHERE子句执行过滤。
  5. 当您将条件放在接触外表行的WHERE子句中时,它们都被丢弃。您应该简单地将该条件放在ON子句中,因为在附加外部行之前对其进行评估。

    那么,那些条件:

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

    应该移入ON子句。

答案 2 :(得分:0)

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

因此,如果存在空值(没有来自右表的匹配数据),则整个行(包括salesrep数据)将被日期过滤器过滤掉 - 因为null不会介于两者之间日期。

答案 3 :(得分:0)

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