37

我有一个使用 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
4

4 回答 4

77

您应该将约束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'

否则,不存在的条目以s inprescriptions结尾,并且该子句将它们丢弃。nullprescriptions.filldateWHERE

于 2012-09-17T22:07:23.790 回答
17

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

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

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

所以,这些条件:

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

应移至 ON 子句。

于 2012-09-17T22:17:20.810 回答
3

这个小提琴可用于说明:

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

请注意,内连接无关紧要,但外连接很重要。文档中的更多详细信息


表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   |

在 DB Fiddle 上查看

于 2019-12-04T08:31:39.500 回答
0

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

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

于 2012-09-17T22:11:32.930 回答