Как объединить результаты из нескольких таблиц с разными колонками?

у меня есть несколько таблиц с разными номерами и типами столбцов и один общий столбец.

+--------+---------+------------+-------------+
| person | beardID | beardStyle | beardLength |
+--------+---------+------------+-------------+

+--------+-------------+----------------+
| person | moustacheID | moustacheStyle |
+--------+-------------+----------------+

Я хочу получить все результаты, которые соответствуют заданному значению общего столбца. Я могу сделать это, используя несколько операторов select, таких как:

SELECT * FROM beards WHERE person = "bob"

и

SELECT * FROM moustaches WHERE person = "bob"

но для этого требуется несколько вызовов mysql API, что кажется неэффективным. Я надеялся, что смогу использовать UNION ALL для получения всех результатов в одном вызове API, но UNION требует что таблицы имеют одинаковое количество и одинаковый тип столбцов. Я мог бы написать инструкцию SELECT, которая вручную добавит результаты из каждой таблицы, добавив столбцы со значениями NULL, но это быстро станет неуправляемым для нескольких таблиц с несколькими столбцами.

Я ищу набор результатов примерно так:

+--------+---------+------------+-------------+-------------+----------------+
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 1       | rasputin   | 1           |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 2       | samson     | 12          |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    |         |            |             | 1           | fu manchu      |
+--------+---------+------------+-------------+-------------+----------------+

есть ли способ достичь этого быстро и ремонтопригодно? Или мне лучше запустить отдельный запрос для каждого стол?

пояснение:

Я не ищу декартово произведение. Я не хочу ссориться из-за каждой комбинации бороды и усов, я хочу ссориться из-за каждой бороды и ссориться из-за каждого уса.

поэтому, если есть 3 одинаковых бороды и 2 одинаковых уса, я должен получить 5 строк, а не 6.

5 ответов


это должно работать нормально:

SELECT * FROM `beards` b LEFT OUTER JOIN `mustaches` ON (0) WHERE  person = "bob"
UNION ALL
SELECT * FROM `beards` b RIGHT OUTER JOIN `mustaches` ON (0) WHERE  person = "bob"

вам не нужно обрабатывать столбцы самостоятельно. левый и правый внешние соединения делают эту работу. к сожалению, mysql не имеет полного соединения. вот почему вы должны сделать это таким образом с Союзом

SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0)
UNION
SELECT * FROM `customer` b RIGHT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0)
UNION
SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) RIGHT OUTER JOIN `day` ON (0)

это локальный тест, который я сделал


присоединиться к человеку....

т. е.

выберите Т1.(asterix), t2.(звездочка) ОТ бороды Т1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ усы Т2 на Т2.person = t1.персона


SELECT *
FROM   beards
       JOIN moustaches
         ON moustaches.person = beards.person
WHERE  person = "bob"  

мне было весело с этим, не уверен, что это полностью управляемо с тем, что еще вам нужно добавить, но он достиг цели.

create table beard (
person varchar(20)
,beardID int
,beardStyle varchar(20)
,beardLength int )

create table moustache(
person varchar(20)
,moustacheID int
,moustacheStyle varchar(20))


insert into beard 
select 'bob', 1, 'rasputin', 1
union select 'bob', 2, 'samson', 12

insert into moustache
select 'bob', 1, 'fu manchu'

declare @facialhair table (
person varchar(20)
,beardID int
,beardStyle varchar(20)
,beardLength int
,moustacheID int
,moustacheStyle varchar(20))

declare @i int
declare @name varchar(20)

set @name = 'bob'
set @i = (select COUNT(*) from beard where person = @name)
        + (select COUNT(*) from moustache where person = @name) 

print @i

while @i > 0
    begin 
        insert into @facialhair (person, beardID, beardStyle, beardLength)
        select person, beardID, beardStyle, beardLength
        from beard
        where person = @name
    set @i = @i-@@ROWCOUNT

        insert into @facialhair (person, moustacheID, moustacheStyle)
        select person, moustacheID, moustacheStyle
        from moustache
        where person = @name
    set @i = @i-@@ROWCOUNT
    end

select *
from @facialhair

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

одна из других возможностей - объединить данные из всех столбцов в одну большую строку (вы можете выбрать какой-то знак для разделения значений столбца), тогда вы сможете использовать предложение union all для объединения результатов из каждого запроса-но тогда вам придется анализировать каждую строку.. И типы данных будут потеряны.