如何根据第二张表的状态执行条件SQL左联接?

时间:2018-06-28 04:36:22

标签: mysql sql join jdbc left-join

例如,我有两个表

Person Table
ID : Name
1 : Bob
2 : Jane
3 : Mike
4 : John
5: Mary

然后我也有(当前实际上是一个整数,但我使用文本使其更具可读性):

Job Table
ID : Name : PersonID : JobStatus
1 : Plumber : 1 : current
2 : Doctor : 2 : past
3 : Driver : 2 : current
4 : Cook : 3 : current
5: Programmer : 5 : past

我想联接两个表,以便获得每个人的列表,但是我只想在左侧联接中包括当前作业。换句话说,我希望结果是:

Bob : Plumber : current
Jane : Driver : current
Mike : Cook : current
John : :  
Mary : : 

如何通过联接执行此操作。我尝试这样做:

SELECT 
  person.name, job.name, job.status 
FROM 
  person
LEFT JOIN 
  job ON person.id=job.person.id

但是问题是,在这种情况下,我将看到Jane的两个条目,一个是她过去的Doctor职位以及她的Driver的新职位。如果我添加了where子句,例如:

WHERE job.status='current' 

然后将其删除,从列表中删除John和Mary。

如何编写一个可以显示所有人员但只包括当前职位的联接?

4 个答案:

答案 0 :(得分:2)

至少在Oracle中,您应该能够做到这一点:

SELECT 
  person.name, job.name, job.status 
FROM 
  person
LEFT JOIN 
   job ON person.id=job.personId AND job.status = 'current';

因此,在进行person.id=job.person.id AND job.status = 'current'联接时,并且当该条件为false时,您仅会获得person数据。

我不知道MySQL是否在ON子句中支持复合条件,但我想是这样,这并不是开创性的技术。

更新:

似乎受支持,请阅读https://dev.mysql.com/doc/refman/8.0/en/join.html

答案 1 :(得分:0)

有几种方法可以做到这一点;最佳选择取决于您的数据库以及不同方法的执行方式。

方法1:使用OR左联接

SELECT p.name, j.name, j.status
FROM person AS p
LEFT JOIN job AS j ON j.personId = p.id AND j.status = 'current';
-- Returns all persons, and only jobs w/ value 'current'
-- If the filter on j.status were in the WHERE clause, it would remove non-matching

方法2:使用UNION ALL执行两个查询(这将删除没有当前值或空值的行)

SELECT p.name, j.name, j.status
FROM person AS p
INNER JOIN job AS j ON j.personId = p.id
WHERE j.status = 'current'
OR j.status IS NULL

UNION ALL

SELECT p.name, j.name, j.status
FROM person AS p
LEFT JOIN job AS j ON j.personId = p.id
WHERE j.status IS NULL;

方法2b:两个带有UNION ALL的查询(这将保留没有当前值或空值的行)

SELECT p.name, j.name, j.status
FROM person AS p
INNER JOIN job AS j ON j.personId = p.id
WHERE j.status = 'current'
OR j.status IS NULL

UNION ALL

SELECT p.name, j.name, j.status
FROM person AS p
LEFT JOIN job AS j ON j.personId = p.id
WHERE NOT EXISTS 
  (SELECT 1 FROM jobs AS t WHERE t.personId=p.Id AND t.status='current')
GROUP BY p.Id; 
-- GROUP BY ensures we only get one row back per person, but will be random if there are multiples

方法3:子选择

SELECT p.name, j.name, j.status
FROM person AS p
LEFT JOIN (
  SELECT x.name
  FROM job AS x
  WHERE x.status = 'current'
) AS j;

答案 2 :(得分:0)

   Select p.name, j.name,j.status 
     From person p 
Left Join
         (Select name,status,personId 
            From job 
            Where status ='current'
         ) j On p.id = j.personId;

您可以尝试查询吗?

答案 3 :(得分:0)

尝试一下

SELECT 
  person.name, job.name, job.status 
FROM 
  person
LEFT JOIN 
  job ON person.id=job.person.id
WHERE CASE WHEN job.status IS NULL THEN '@' WHEN job.status ='current' THEN '@' else job.status END = '@'