Как вы выполняете условие SQL левого соединения на основе состояния второй таблицы? - PullRequest
0 голосов
/ 28 июня 2018

Так, например, у меня есть две таблицы

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

У меня также есть (current на самом деле является целым числом, но я использовал текст, чтобы сделать его более читабельным):

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

Но проблема в том, что в этом случае я увижу две записи для Джейн, одну для ее прошлой работы Доктора, а также ее новую работу Водителя. И если я добавлю предложение where, например:

WHERE job.status='current' 

Затем он удаляет удаляет Джона и Мэри из списка.

Как я могу написать объединение, которое покажет всем людям, включая только текущие вакансии?

Ответы [ 4 ]

0 голосов
/ 28 июня 2018

По крайней мере, в 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' соединение выполнено, и когда это условие ложно, вы получаете только person данные.

Я не знаю, поддерживает ли MySQL составные условия в предложениях ON, но, думаю, это не совсем новаторская технология.

UPDATE:

Похоже, что поддерживается, читать https://dev.mysql.com/doc/refman/8.0/en/join.html

0 голосов
/ 28 июня 2018
   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;

Можете ли вы попробовать этот запрос?

0 голосов
/ 28 июня 2018

Попробуйте это

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 = '@'
0 голосов
/ 28 июня 2018

Есть несколько способов сделать это; лучший вариант зависит от вашей базы данных и от того, как работают разные методы.

Метод 1: Соединение влево с помощью ИЛИ

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;
...