2014-01-14 6 views
10

Скажем, у меня есть две таблицы в базе данных MySQL.Объедините несколько строк в одну строку MySQL

Таблица 1:

ID Name 
1  Jim 
2  Bob 
3  John 

Таблица 2:

ID key   value 
1  address  "X Street" 
1  city   "NY" 
1  region  "NY" 
1  country  "USA" 
1  postal_code "" 
1  phone   "123456789" 

При выборе строки из базы данных, есть ли способ, чтобы присоединиться строки из второй таблицы в качестве столбцов первой таблицы?

Желаемый результат прямо из запроса MySQL является:

ID Name address city region country postal_code phone 
1  Jim  X Street NY  NY  USA  NULL   123456789 
2  Bob  NULL  NULL NULL  NULL  NULL   NULL 
3  John NULL  NULL NULL  NULL  NULL   NULL 

Спасибо за любую помощь!

ответ

23

Этот тип преобразования данных известен как PIVOT. MySQL не имеет функцию поворота, но вы можете повторить его с помощью агрегатной функции с выражением CASE:

select t1.id, 
    t1.name, 
    max(case when t2.`key` = 'address' then t2.value end) address, 
    max(case when t2.`key` = 'city' then t2.value end) city, 
    max(case when t2.`key` = 'region' then t2.value end) region, 
    max(case when t2.`key` = 'country' then t2.value end) country, 
    max(case when t2.`key` = 'postal_code' then t2.value end) postal_code, 
    max(case when t2.`key` = 'phone' then t2.value end) phone 
from table1 t1 
left join table2 t2 
    on t1.id = t2.id 
group by t1.id, t1.name 

См SQL Fiddle with Demo.

Это также может быть написан с использованием нескольких объединений на вашем table2 и вы должны включить фильтр на объединение для каждого key:

select t1.id, 
    t1.name, 
    t2a.value address, 
    t2c.value city, 
    t2r.value region, 
    t2y.value country, 
    t2pc.value postal_code, 
    t2p.value phone 
from table1 t1 
left join table2 t2a 
    on t1.id = t2a.id 
    and t2a.`key` = 'address' 
left join table2 t2c 
    on t1.id = t2c.id 
    and t2c.`key` = 'city' 
left join table2 t2r 
    on t1.id = t2r.id 
    and t2c.`key` = 'region' 
left join table2 t2y 
    on t1.id = t2y.id 
    and t2c.`key` = 'country' 
left join table2 t2pc 
    on t1.id = t2pc.id 
    and t2pc.`key` = 'postal_code' 
left join table2 t2p 
    on t1.id = t2p.id 
    and t2p.`key` = 'phone'; 

См SQL Fiddle with Demo.

Эти две версии будут работать отлично, если у вас есть ограниченное число значений key. Если у Вас есть неизвестное число значений, то вы хотите посмотреть на использование подготовленного оператора для создания динамического SQL:

SET @sql = NULL; 
SELECT 
    GROUP_CONCAT(DISTINCT 
    CONCAT(
     'max(case when t2.`key` = ''', 
     `key`, 
     ''' then t2.value end) AS `', 
     `key`, '`' 
    ) 
) INTO @sql 
from Table2; 

SET @sql 
    = CONCAT('SELECT t1.id, t1.name, ', @sql, ' 
       from table1 t1 
       left join table2 t2 
       on t1.id = t2.id 
       group by t1.id, t1.name;'); 

PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

См SQL Fiddle with Demo

Все версии даст результат:

| ID | NAME | ADDRESS | CITY | REGION | COUNTRY | POSTAL_CODE |  PHONE | 
|----|------|----------|--------|--------|---------|-------------|-----------| 
| 1 | Jim | X Street |  NY | (null) | (null) |  (null) | 123456789 | 
| 2 | Bob | (null) | (null) | (null) | (null) |  (null) | (null) | 
| 3 | John | (null) | (null) | (null) | (null) |  (null) | (null) | 
+0

bluefeet, когда я запускаю этот динамический запрос, он дает мне это сообщение об ошибке: «# 1243 - Неизвестный подготовленный обработчик инструкций (stmt), данный EXECUTE " – n0nnus

+0

@ n0nnus К сожалению, я не эксперт MySQL, чтобы помочь вам отлаживать, но я нашел несколько других вопросов здесь, которые могут помочь [ссылка 1] (http://stackoverflow.com/questions/17418809/mysql-1243-error-while-executing-it-through-phpmyadmin), [Ссылка 2] (http://stackoverflow.com/questions/14840592/unknown-prepared-statement-handler-0-given-to-mysql -stmt-execute-in-php-code) и [Ссылка 3] (http: // stackoverflow.ком/вопросы/16074952/MySQL-1243 неизвестный подготовленный-оператор-обработчик-STMT-данных к казнить). Вы, вероятно, найдете какую-нибудь помощь здесь или Google, чтобы разрешить ошибку. – Taryn

+0

спасибоz в любом случае !! ;) – n0nnus

2

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

select t1.name, 
     max(case when `key` = 'address' then value end) as address, 
     max(case when `key` = 'city' then value end) as city, 
     max(case when `key` = 'region' then value end) as region, 
     max(case when `key` = 'country' then value end) as country, 
     max(case when `key` = 'postal_code' then value end) as postal_code, 
     max(case when `key` = 'phone' then value end) as phone 
from table1 t1 left join 
    table2 t2 
    on t1.id = t2.id 
group by t1.name; 

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

select t1.name, address.value, city.value, . . . 
from table1 t1 left join 
    table2 address 
    on t1.id = address.id and address.`key` = 'Address' left join 
    table2 city 
    on t1.id = city.id and city.`key` = 'City' . . . 

В зависимости от структуры данных, метод join может на самом деле Быстрее в MySQL, когда он использует соответствующую индексацию. (Другие базы данных были алгоритмами для агрегации, поэтому метод group by часто хорошо работает в других базах данных.)

+0

Мне любопытно, почему подход № 1 здесь (с использованием case case), похоже, не работает в этом (http://stackoverflow.com/questions/23377374/using-case-to-convert-column- value-to-row-values-in-mysql) case? – JackhammersForWeeks

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