MySQL запрос с несколькими полными объединениями - PullRequest
1 голос
/ 21 января 2020

У меня есть запрос, который получает все задания из базы данных, некоторые задания не имеют языковой пары , и мне нужно получить их тоже, пока я получаю информацию о языковой паре для заданий, которые имеют языковая пара , я понимаю, что это делается с помощью полного объединения , но полных объединений в mySQL не существует, я читал об этом и мне нужно сделать что-то вроде UNION.

Если я получу NULLS в качестве источника и цели для заданий, у которых нет языковой пары, это хорошо.

Это запрос, который у меня есть в данный момент:

SELECT jobName, source.name AS source, target.name AS target FROM (
        (SELECT jobs.name AS jobName, lp.sourceId, lp.targetId FROM jobs **JOIN languagePairs** lp
            ON lp.id = jobs.languagePairId)
            UNION  
        (SELECT jobs.name AS jobName, lp.sourceId, lp.targetId FROM collectiveJobs JOIN jobs ON jobs.id = collectiveJobs.jobId
            **JOIN languagePairs lp** on jobs.languagePairId = lp.id
            WHERE collectiveJobs.freelancerId = 1)
        ) AS jobs **JOIN languages** source ON source.id = sourceId **JOIN languages** target ON target.id = targetId;

Я думаю, но я не уверен, что полные объединения должны произойти при жирных соединениях . Также должна быть какая-то проверка на ноль (я думаю) в запросе.

Конечно, я мог бы сделать это программно, но было бы неплохо иметь 1 запрос

Схема БД:

create table languages
(
    id    int auto_increment primary key,
    name  varchar(255) not null
)

create table languagePairs
(
    id                  int auto_increment
        primary key,
    sourceId            int not null,
    targetId            int not null,
    constraint languagePair_sourceId_targetId_uindex
        unique (sourceId, targetId),
    constraint languagePair_language_id_fk_source
        foreign key (sourceId) references languages (id),
    constraint languagePair_language_id_fk_target
        foreign key (targetId) references languages (id)
)

create table jobs
(
    id                      int auto_increment
        primary key,
    name                    varchar(255)                         null,
    freelancerId            int                                  null,
    languagePairId          int                                  null,
    constraint jobs_freelancers_id_fk
        foreign key (freelancerId) references freelancers (id),
    constraint jobs_languagePairs_id_fk
        foreign key (languagePairId) references languagePairs (id)
)

create table collectiveJobs
(
    id           int auto_increment
        primary key,
    jobId        int      not null,
    freelancerId int      not null,
    constraint collectiveJobs_freelancerId_jobId_uindex
        unique (freelancerId, jobId),
    constraint collectiveJobs_freelancers_id_fk
        foreign key (freelancerId) references freelancers (id),
    constraint collectiveJobs_jobs_id_fk
        foreign key (jobId) references jobs (id)
)

create table freelancers
(
    id    int auto_increment primary key
)

Пример данных:

INSERT INTO datamundi.jobs (id, name, freelancerId, languagePairId) VALUES (1, 'Job 1', 1, 1);
INSERT INTO datamundi.jobs (id, name, freelancerId, languagePairId) VALUES (2, 'Job 2', 1, null);

Если я выполню запрос Только задание 1

MySQL версия на компьютере разработчика: mysql Вер. 8.0.19 для Linux на x86_64 (MySQL Сервер совместной работы - GPL)

MySQL версия на рабочий сервер: mysql Вер. 8.0.17 для Linux на x86_64 (MySQL Сервер совместной работы - GPL)

Вся помощь действительно приветствуется.

Ответы [ 2 ]

2 голосов
/ 21 января 2020

Я не могу углубиться в ваш конкретный пример c, но хорошая новость в том, что вы используете MySQL 8.x. Обходной путь для FULL OUTER JOIN между двумя таблицами (a и b) в MySQL:

select * from a left join b on <predicate>
union
select * from a right join b on <predicate>

Теперь, если вам нужно объединить сложные выборки вместо простых таблиц, эти CTE приходят к вашему спасению. Например, если бы левая сторона была полной SELECT, вы бы сделали:

with s as ( <complex-select-here> )
select * from s left join b on <predicate>
union
select * from s right join b on <predicate>

Если оба являются сложными SELECT, то:

with s as ( <complex-select-here> ),
     t as ( <complex-select-here> )
select * from s left join t on <predicate>
union
select * from s right join t on <predicate>

Без пота.

0 голосов
/ 22 января 2020

Это работает со всеми левыми соединениями, извините, я должен был сначала попробовать.

SELECT jobName, source.name AS source, target.name AS target FROM (
        (SELECT jobs.name AS jobName, lp.sourceId, lp.targetId FROM jobs LEFT JOIN languagePairs lp
            ON jobs.languagePairId = lp.id)
            UNION  
        (SELECT jobs.name AS jobName, lp.sourceId, lp.targetId FROM collectiveJobs JOIN jobs ON jobs.id = collectiveJobs.jobId
            LEFT JOIN languagePairs lp on jobs.languagePairId = lp.id
            WHERE collectiveJobs.freelancerId = 1)
        ) AS jobs LEFT JOIN languages source ON source.id = sourceId LEFT JOIN languages target ON target.id = targetId;

Не уверен, почему я учил, что мне нужно ПОЛНОЕ СОЕДИНЕНИЕ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...