将一个查询的查询结果转换为另一个查询的列

时间:2012-11-15 19:18:47

标签: mysql sql join pivot

我有两张表与一对多的关系,让我说我有这个。

**Table Owners**
K  Owner
1  Fred
2  Jason
3  Tonya

Table Cars

K CarBrand
1 Mitsubishi 
1 Honda
1 VW
2 Toyota
3 Ford

而不是得到这个:

K Owner CarBrand 
1 Fred  Mitsubishi 
1 Fred  Honda
1 Fred  VW

我想用这样的结果进行查询:

K Owner CarBrand1 CarBrand2 Carbrand3
1 Fred  Mitsubishi Honda     VW

我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:2)

不是真的,但这很接近

Select k, owner, group_concat(carbrand)
FROM owners, cars
WHERE
owner.k = cars.k
GROUP BY car brand

对不起格式化,我会解决这个问题。

答案 1 :(得分:2)

看起来您希望将数据从单列,多行转换为多列,每行一行。这基本上是PIVOT但不幸的是MySQL没有PIVOT函数,所以你需要使用带有CASE语句的聚合函数来复制它。

如果你知道你将拥有多少个carbrands,你可以对这些值进行硬编码,类似于:

select k, owner,
  max(case when nameRn = 'CarBrand1' then carbrand end) CarBrand1,
  max(case when nameRn = 'CarBrand2' then carbrand end) CarBrand2,
  max(case when nameRn = 'CarBrand3' then carbrand end) CarBrand3
from
(
  select k, owner, carbrand,
    concat('CarBrand', @num := if(@owner = `owner`, @num + 1, 1)) as nameRn,
    @owner := `owner` as dummy
  from
  (
    select k, owner, carbrand, @rn:=@rn+1 overall_row_num
    from
    (
      select o.k, o.owner, c.carbrand
      from owners o
      inner join cars c
        on o.k = c.k
      order by carbrand
    ) oc, (SELECT @rn:=0) r
    order by k 
  ) r
) src
group by k, owner

请参阅SQL Fiddle with Demo

但是,如果您有一个未知数量的值,那么您可以使用预准备语句生成此动态版本:

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when nameRn = ''',
      nameRn,
      ''' then carbrand end) AS ',
      nameRn
    )
  ) INTO @sql
FROM 
(
  select k, owner, carbrand,
    concat('CarBrand', @num := if(@owner = `owner`, @num + 1, 1)) as nameRn,
    @owner := `owner` as dummy
  from
  (
    select k, owner, carbrand, @rn:=@rn+1 overall_row_num
    from
    (
      select o.k, o.owner, c.carbrand
      from owners o
      inner join cars c
        on o.k = c.k
      order by carbrand
    ) oc, (SELECT @rn:=0) r
    order by k 
  ) r
) src;


SET @sql = CONCAT('SELECT k, owner, ', @sql, ' 
                  from
                  (
                    select k, owner, carbrand,
                      concat(''CarBrand'', @num := if(@owner = `owner`, @num + 1, 1)) as nameRn,
                      @owner := `owner` as dummy
                    from
                    (
                      select k, owner, carbrand, @rn:=@rn+1 overall_row_num
                      from
                      (
                        select o.k, o.owner, c.carbrand
                        from owners o
                        inner join cars c
                          on o.k = c.k
                        order by carbrand
                      ) oc, (SELECT @rn:=0) r
                      order by k 
                    ) r
                  ) src
                   GROUP BY k, owner');

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

请参阅SQL Fiddle with Demo

两者的结果相同:

| K | OWNER | CARBRAND1 | CARBRAND2 |  CARBRAND3 |
--------------------------------------------------
| 1 |  Fred |        VW |     Honda | Mitsubishi |
| 2 | Jason |    Toyota |    (null) |     (null) |
| 3 | Tonya |      Ford |    (null) |     (null) |