2016-01-14 4 views
3

У меня есть две таблицы, и я пытаюсь объединить их вместе определенным образом. Результаты Я ищу бы:MySQL теряет строки в соединении

site statusname total 
2 Follow-Up 0 
2 Off Study 0 
2 Screening 1 
2 Treatment 0 
1 Follow-Up 0 
1 Off Study 0 
1 Screening 2 
1 Treatment 0 

Однако, это то, что возвращается:

site statusname total 
1 Follow-Up 0 
1 Off Study 0 
1 Screening 2 
2 Screening 1 
1 Treatment 0 

Мой фактический запрос (тот, который возвращает неправильные результаты) выглядит следующим образом:

SELECT 
    sitestatus.site         AS site, 
    sitestatus.statusname       AS statusname, 
    count(participant.id)       AS total 
FROM 
    (SELECT DISTINCT 
     participant.`site`       AS site, 
     participant_status.`name`     AS statusname, 
     participant_status.`id`      AS status 
    FROM 
     participant_status 
    CROSS JOIN 
     participant) AS sitestatus 
LEFT JOIN 
    participant 
ON 
    participant.`site` = sitestatus.`site`   AND 
    participant.`status` = sitestatus.`status` 
GROUP BY 
    sitestatus.`statusname`, 
    participant.`site` 

Однако, если я сделаю небольшую (но неприемлемую) модификацию, добавив в подзапрос пункт WHERE и используя UNION, я получу желаемые результаты. Вот запрос:

SELECT 
    sitestatus.site         AS site, 
    sitestatus.statusname       AS statusname, 
    count(participant.id)       AS total 
FROM 
    (SELECT DISTINCT 
     participant.`site`       AS site, 
     participant_status.`name`     AS statusname, 
     participant_status.`id`      AS status 
    FROM 
     participant_status 
    CROSS JOIN 
     participant 
    WHERE site=1) AS sitestatus 
LEFT JOIN 
    participant 
ON 
    participant.`site` = sitestatus.`site`   AND 
    participant.`status` = sitestatus.`status` 
GROUP BY 
    sitestatus.`statusname`, 
    participant.`site` 

UNION 

SELECT 
    sitestatus.site         AS site, 
    sitestatus.statusname       AS statusname, 
    count(participant.id)       AS total 
FROM 
    (SELECT DISTINCT 
     participant.`site`       AS site, 
     participant_status.`name`     AS statusname, 
     participant_status.`id`      AS status 
    FROM 
     participant_status 
    CROSS JOIN 
     participant 
    WHERE site=2) AS sitestatus 
LEFT JOIN 
    participant 
ON 
    participant.`site` = sitestatus.`site`   AND 
    participant.`status` = sitestatus.`status` 
GROUP BY 
    sitestatus.`statusname`, 
    participant.`site`; 

Я не могу понять, куда идут мои недостающие строки.

Вот соответствующие схемы:

CREATE TABLE `participant` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `site` int(10) unsigned NOT NULL, 
    `status` int(10) unsigned NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`) 
) 

и

CREATE TABLE `participant_status` (
    `id` int(10) unsigned NOT NULL, 
    `name` varchar(100) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `name` (`name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Спасибо за любую помощь вы можете предоставить.

(EDIT:. Теперь, используя CROSS JOIN как предложил Тим)

+0

использовать союз всех операторов между двумя запросами. –

+0

Проверьте [этот вопрос] (https://stackoverflow.com/questions/30752391/full-join-on-group), он может помочь вам, он находится в Oracle, но он обращается к той же логике – simsim

+0

, возможно, вы должны быть правильно ли получить нулевые строки? – pratz9999

ответ

3

UNION оператор имеет поведение по умолчанию удаление повторяющихся записей, которые происходят в обоих наборах результатов, которые в настоящее время агрегируются. Если вы хотите сохранить все записи из обоих запросов, вы должны использовать UNION ALL оператор:

query1 
UNION ALL 
query2 

Вот моя попытка на то, что правильный подход к этому запросу может быть:

SELECT t2.site, t2.name AS statusname, t1.total 
FROM 
(
    SELECT site, status, COUNT(*) AS total 
    FROM participant 
    GROUP BY site, status 
) t1 
INNER JOIN 
(
    (SELECT DISTINCT site FROM participant) 
    CROSS JOIN 
    participant_status 
) t2 
ON t1.site = t2.site AND t1.status = t2.id 
+0

Я не хочу, чтобы мой запрос имел _any_ 'UNION' оператора. То, что я надеялся показать с помощью примера UNION, состояло в том, что я ожидал, что в исходном запросе будет возвращено больше данных. –

+0

hi @tim ... я не уверен, что понимаю. в запросе, который работает некорректно, у меня нет предложения WHERE. в очень длинном запросе, который работает (пока есть только два сайта), у меня есть предложение WHERE, но я не хочу использовать этот запрос. цель длинного запроса (с 'WHERE' и' UNION') должна показать, что я считаю, что внутренний запрос возвращает все, что я хочу, но внешний запрос или 'LEFT JOIN' отбрасывает данные –

+1

Извините, я чтобы сказать, не делайте присоединения, говоря «FROM table1, table2», потому что неясно, что такое столбец соединения. Чтобы получить ответ, вы действительно хотите, чтобы кто-то (или что-то) должен был переписать запрос. Ваша нынешняя структура делает это намного сложнее. –

0

С помощь @Tim, я смог прийти к ответу:

SELECT t2.site, t2.statusname AS statusname, COALESCE(t1.total,0) AS total 
FROM 
(
    SELECT site, status, COUNT(*) AS total 
    FROM participant 
    GROUP BY site, status 
) AS t1 
RIGHT JOIN 
(
    SELECT DISTINCT participant_status.id AS status, participant_status.name AS statusname, participant.site FROM participant 
    CROSS JOIN 
    participant_status 
    ORDER BY status, site 
) AS t2 
ON t1.site = t2.site AND t1.status = t2.status 
+1

Точки стиля: Обычно лучше сделать ссылку 'FROM' _always_ иметь строку, а в последующих ссылках _maybe_ иметь строку (IOW, переключить ваши два подзапроса и сделать ее« LEFT JOIN »). Также обычно лучше поставить 'ORDER BY' на самый внешний уровень - я не уверен, как гарантированный заказ после присоединения –

Смежные вопросы