2013-07-10 2 views
1

Я не уверен, что это возможно, и это, безусловно, сложно описать.MySQL - SubQuery внутри a Выберите

Я хотел бы вернуть SELECT запрос таким образом:

 
pID | Name | Email   | Dog Name | Fish Name 
------------------------------------------------------- 
44 | John | [email protected] | Scruffy | 
56 | Jane | [email protected] |   | Puffer 
72 | Joe | [email protected] | Sparky | Gill 

Есть 3 таблицы: tbl_option_fields tbl_person tbl_person_optionals

Первая таблица просто определяет неограниченное количество дополнительных полей. Вот столбцы:

 
optid | opttitle 
------------------ 
1  | Dog Name 
2  | Fish Name 
3  | Email 

Вторая таблица является просто где я держу данные для людей:

 
pID | Name 
--------------- 
44 | John 
56 | Jane 
72 | Joe 

В последней таблице давайте мне хранить любую дополнительную информацию, которая существует для pID

 
ID | pID | optid | optval 
---------------------------------- 
1 | 44 | 1 | Scruffy 
2 | 56 | 2 | Puffer 
3 | 72 | 1 | Sparky 
4 | 72 | 2 | Gill 
5 | 72 | 3 | [email protected] 
6 | 56 | 3 | [email protected] 
7 | 44 | 3 | [email protected] 

Результат оператора SELECT должен отображать opttitle в заголовке результата. Я не разбираюсь в подзапросах, и это может быть doozy.

Вот моя попытка:

SELECT p.*, opt.optval 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
WHERE 1 

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

 
pID | Name | optval    
----------------------------- 
44 | John | [email protected] 
44 | John | Scruffy 

56 | Jane | [email protected] 
56 | Jane | Puffer 

72 | Joe | [email protected] 
72 | Joe | Sparky 
72 | Joe | Gill 

Надеюсь, я объясняю, что я хочу, чтобы отобразить Необязательные поля по горизонтали, а не новой записи в строках. Можно ли это сделать?

+1

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

+0

И это, наверное, то, что мне нужно было услышать. благодаря! – coffeemonitor

ответ

0

Что вы в основном хотите, это сводная таблица. Это можно сделать в MySQL, например this article describes in full, glorious detail.

Однако для того, чтобы то, что вы АРХИВ хотите с вашим текущим дизайном таблицы вы должны добавить SELECT -оператора для каждый вариант вы имеете в таблице tbl_option_fields. Имея только несколько вариантов, это управляемо, но чем больше вариантов у вас есть, тем более грязным будет ваш оператор (и в конечном итоге медленнее выполнять).

Еще один недостаток - ваше утверждение должно корректироваться каждый раз, когда появляются новые варианты.

В принципе, вам нужно жить с ним или настраивать дизайн стола. Возможно, есть еще несколько вариантов, но я думаю, это сводится к этим двум.

0

Вот одно решение:

SELECT p.pID, p.Name, 
    MAX(IF(opt.optid=3, opt.optval, NULL)) AS `Email`, 
    MAX(IF(opt.optid=1, opt.optval, NULL)) AS `Dog Name`, 
    MAX(IF(opt.optid=2, opt.optval, NULL)) AS `Fish Name` 
FROM `tbl_person` p 
LEFT OUTER JOIN `tbl_person_optionals` opt ON p.pID = opt.pID 
GROUP BY p.pID; 

Вы должны знать все optid и их колонна этикетки перед тем написания этого запроса. Это относится и к MySQL, но это относится и к брендам RDBMS, которые поддерживают собственные команды PIVOT (например, Microsoft SQL Server). SQL требует, чтобы вы определяли столбцы запроса до того, как он начнет изучение данных; запрос не может «добавить» больше столбцов, поскольку обнаруживает разные значения данных.

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

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

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

0

Вы можете сделать это путем объединения таблиц вместе и агрегирование результатов:

select po.pid, p.name, 
     MAX(case when o.optId = 'Email' then po.optval end) as Email, 
     MAX(case when o.optId = 'Dog Name' then po.optval end) as DogName, 
     MAX(case when o.optId = 'Fish Name' then po.optval end) as FishName 
from tbl_person_optionals po join 
    tbl_person p 
    on p.pId = p.pId join 
    tbl_optionfields o 
    on p.optid = o.optid 
group by po.pid, p.name; 

Это предполагает, что вы знаете, что вы хотите в столбцах. Операторы Select могут возвращать только фиксированный набор столбцов, поэтому, если вы хотите вернуть отдельный столбец для каждого значения в tbl_optionfields, вам понадобится динамический SQL (т. Е. Использовать инструкцию подготовки).