简体   繁体   English

将多行合并为一行MySQL

[英]Combine multiple rows into one row MySQL

Say I have two tables in a MySQL Database. 假设我在MySQL数据库中有两个表。

Table 1: 表格1:

ID    Name
1     Jim
2     Bob
3     John

Table 2: 表2:

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

When selecting rows from the database, is there any way to join rows from the second table as columns to the first table? 从数据库中选择行时,是否有任何方法可以将第二个表中的行作为列连接到第一个表中?

The desired result right from the MySQL query is: 直接从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

Thanks for any help! 谢谢你的帮助!

This type of data transformation is known as a PIVOT. 这种数据转换类型称为PIVOT。 MySQL doesn't have a pivot function but you can replicate it using an aggregate function with a CASE expression: 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

See SQL Fiddle with Demo . 请参阅带有演示的SQL Fiddle

This could also be written using multiple joins on your table2 and you would include a filter on the join for each key : 这也可以在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';

See SQL Fiddle with Demo . 请参阅带有演示的SQL Fiddle

The above two versions will work great if you have a limited number of key values. 如果key数量有限,则以上两个版本将非常有用。 If you have an unknown number of values, then you will want to look at using a prepared statement to generate dynamic SQL: 如果您有未知数量的值,那么您将需要查看使用准备好的语句来生成动态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;

See SQL Fiddle with Demo 参见带有演示的SQL Fiddle

All versions will give a result: 所有版本都会给出结果:

| 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) |

You have a structure called entity-attribute-value in the second table. 在第二个表中,您有一个称为entity-attribute-value的结构。 There are two ways to do the combination. 有两种方法可以进行组合。 I think the aggregation method is the easier to express: 我认为聚合方法更易于表达:

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;

The second method is to do separate joins for each value: 第二种方法是对每个值进行单独的联接:

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' . . .

Depending on the structure of the data, the join method can actually be faster in MySQL when it uses appropriate indexing. 根据数据的结构,当使用适当的索引时, join方法在MySQL中实际上可以更快。 (Other databases have been algorithms for aggregation, so the group by method often works well in other databases.) (其他数据库一直是聚合算法,因此group by方法通常在其他数据库中运行良好。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM