LEFT OUTER JOIN PostgreSQL是INNER JOIN吗?

时间:2018-10-30 12:34:59

标签: sql postgresql left-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 行,并且仅存在作业表中的记录

4 个答案:

答案 0 :(得分:1)

是因为这种咬伤:

Student oldest = studentList.pollLast();

您需要像这样将其移至LEFT JOIN:

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

答案 1 :(得分:1)

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

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'

答案 2 :(得分:1)

您需要将 last 表上的条件移至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;

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

答案 3 :(得分:1)

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

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

之后,它将应用您的WHERE子句。在这种情况下,您的WHERE子句包含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上的条件会更好,因为首先要将较少的记录拉入内存。