繁体   English   中英

LEFT OUTER JOIN PostgreSQL是INNER JOIN吗?

[英]LEFT OUTER JOIN PostgreSQL works as INNER JOIN?

以下查询正常工作

SELECT "employee"."id",
       "employee"."created",
       (SELECT SUM(minutes) FROM jobs_job AS job WHERE job.employee_id = employee.id AND job.job_date BETWEEN '2018-10-21' AND '2018-10-30')
FROM users_employee AS employee
    INNER JOIN users_user AS users ON (employee.user_id = users.id)
WHERE NOT ("users"."status" = 'F')
GROUP BY
    employee.id

而且我得到正确的数据(对于在JOB表中没有记录的人为NULL

但是,如果我将相同的查询重构为LEFT OUTER JOIN

SELECT "employee"."id",
       "employee"."created",
       SUM(job.minutes) AS job_minutes
FROM users_employee AS employee
    INNER JOIN users_user AS users ON (employee.user_id = users.id)
    LEFT OUTER JOIN jobs_job AS job on employee.id = job.employee_id
WHERE NOT ("users"."status" = 'F') AND job.job_date BETWEEN '2018-10-21' AND '2018-10-30'
GROUP BY
    employee.id

我在原始查询中得到112行而不是142行,并且仅存在Job表中的记录

这是因为这种咬伤:

AND job.job_date BETWEEN '2018-10-21' AND '2018-10-30'    

您需要将其移动到LEFT JOIN,例如:

LEFT OUTER JOIN jobs_job AS job on employee.id = job.employee_id
AND job.job_date BETWEEN '2018-10-21' AND '2018-10-30'

您需要在ON规则中使用其他条件,而不是where子句

SELECT "employee"."id",
       "employee"."created",
       SUM(job.minutes) AS job_minutes
FROM users_employee AS employee
    INNER JOIN users_user AS users ON (employee.user_id = users.id)
    LEFT OUTER JOIN jobs_job AS job on employee.id = job.employee_id
and "users"."status" <> 'F' AND job.job_date BETWEEN '2018-10-21' AND '2018-10-30'
GROUP BY
    employee.id

您需要将最后一张表上的条件移到on子句。 第二个表上的过滤保留在where

SELECT "employee"."id",
       "employee"."created",
       SUM(job.minutes) AS job_minutes
FROM users_employee employee INNER JOIN
     users_user users
     ON employee.user_id = users.id LEFT OUTER JOIN
     jobs_job job 
     ON employee.id = job.employee_id AND
        job.job_date BETWEEN '2018-10-21' AND '2018-10-30'
WHERE "users"."status" <> 'F' 
GROUP BY employee.id;

该逻辑以这种方式工作,因为左外部联接从JOIN的第二个表产生的结果为NULL值。 这些NULL值可以在WHERE子句中过滤掉。

提供的所有答案将帮助您修复代码。 我只想扩展一下为什么它们会起作用。

SQL引擎首先评估您的FROMJOIN ,然后将您的初始数据集提取到内存中。 到那时,因为您已经使用了LEFT OUTER JOIN ,所以您期望的所有行都仍然存在。

之后,它将应用您的WHERE子句。 在这种情况下,您的WHERE子句在job.job_date BETWEEN '2018-10-21' AND '2018-10-30'包含job.job_date BETWEEN '2018-10-21' AND '2018-10-30' ,因此此时引擎会过滤掉所有不符合该条件的行。 这样可以有效地使您从LEFT JOIN获得的结果与使用INNER JOIN获得的结果完全相同。

多次建议的最佳答案是将过滤条件移至ON子句。 一种可行的替代方法是,将IS NULL可能性添加到您现有的WHERE子句中,并且可以证明结果实际上是从头开始的:

...
WHERE 
  NOT ("users"."status" = 'F') 
  AND
  (
    (job.job_date BETWEEN '2018-10-21' AND '2018-10-30')
    OR
    job.job_date IS NULL
  )

但是,使用JOIN上的条件会更好,因为首先将较少的记录拉入内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM