2010-10-26 2 views
6

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

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

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

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

SELECT * FROM beards WHERE person = "bob" 

и

SELECT * FROM moustaches WHERE person = "bob" 

Но это требует несколько вызовов API MySQL, что представляется неэффективным. Я надеялся, что смогу использовать 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.

+1

Хотя это можно сделать в большинстве баз данных с помощью «ПОЛНОГО ПРИСОЕДИНЯЯ», а в MySQL с обходным решением ITroubs я серьезно сомневаюсь в том, есть ли какое-либо существенное увеличение производительности от этого, и вы, вероятно, только создаете беспорядок неясного кода, ваш преемник не поблагодарит вас. Четкий и точный код перевешивает прирост производительности при очень низких процентах в большинстве случаев. – Wrikken

ответ

7

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

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

Блестящий, работает как шарм. Поэтому, если я правильно понимаю, вы используете LEFT и RIGHT OUTER JOINs, не указав критерии соединения, чтобы добавлять столбцы, полные NULL, к результатам из каждой таблицы (так, чтобы наборы результатов соответствовали таблицам), а затем СОЕДИНЯЯ результаты. – Robert

+2

yep. соединения состоят только в том, чтобы сделать shure, ваш результат имеет все столбцы для бобов и усов, и, сделав оператор ON false, он просто возвращает все строки с бороды или усы в зависимости от используемого соединения. – ITroubs

+0

Итак, чтобы добавить третью таблицу, я бы добавил дополнительный OUTER JOIN ON (0) для каждого из этих SELECT для новой таблицы, плюс UNION ALL и новый оператор select OUTER JOINING для новой таблицы для этих двух таблиц таким же образом. – Robert

0

Регистрации на человеке ....

И.Э.

Выберите t1. (Звездочка), t2. (Звездочка) ИЗ бородами t1 INNER JOIN усы t2 На t2.person = t1.person

+0

Вы попробовали это? INNER JOIN извлекает декартовое произведение совпадающих записей из двух таблиц. Таким образом, один результат для каждой комбинации бороды и усов. Не то, что описано в вопросе вообще. – Robert

+0

@ Robert: Нет, INNER JOIN не производит декартовой продукт. –

+0

Извините, я не очень хорошо разбираюсь в JOIN. В чем разница между INNER JOIN и взятием декартова продукта и фильтрацией по критериям присоединения? – Robert

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

Я ищу, чтобы получить строку для каждой бороды и строки для каждой усы, а не строки для каждой бороды и усы. – Robert

0

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

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 = @[email protected]@ROWCOUNT 

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

select * 
from @facialhair 
0

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

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

+0

и основным недостатком будет накладные расходы на вычисление и ограниченный размер строки mysql для group_concat! взгляните на мое решение. Я думаю, это было бы самым простым способом. – ITroubs

+0

@ITroubs: хорошее решение Я должен сказать – rsc