web-dev-qa-db-ja.com

2つの列に基づいて行を列に動的に変換するMysqlクエリ

ここでは 質問 に従って、Mysqlクエリを使用して行を列に動的に変換しました。これは正常に機能しますが、2つの列に基づいてこれを変換する必要があります。

上記のリンクで言及されているクエリは、単一の列「data」に対して機能しますが、「data」と「price」の2つの列に対して機能したいと思います。

ここに例を追加しました、

次のようなテーブルAが与えられます

Table A

|  id|order|data|item|Price|
-----+-----+----------------
|   1|    1|   P| 1  | 50  |
|   1|    1|   P| 2  | 60  |
|   1|    1|   P| 3  | 70  |
|   1|    2|   Q| 1  | 50  |
|   1|    2|   Q| 2  | 60  |
|   1|    2|   Q| 3  | 70  |
|   2|    1|   P| 1  | 50  |
|   2|    1|   P| 2  | 60  |
|   2|    1|   P| 4  | 80  |
|   2|    3|   S| 1  | 50  |
|   2|    3|   S| 2  | 60  |
|   2|    3|   S| 4  | 80  |

次のようなクエリを作成するのが好きです。

Result Table

|  id|order1|order2|order3|item1|item2|item3|item4|
-----+-----+---------------------------------------
|   1|    P |    Q |      | 50  | 60  | 70  |     |
|   2|    P |      |    S | 50  | 60  |     | 80  |

これを実現するために、2つの異なるクエリを作成してから結合を作成しようとしましたが、それは適切な解決策ではない可能性があります。上記のリンクで述べたのと同じ解決策を誰かが提案できますか?.

ありがとう

8
Moon

orderitemの両方に既知の数の値がある場合は、クエリを次のようにハードコーディングできます。

select id,
  max(case when `order` = 1 then data end) order1,
  max(case when `order` = 2 then data end) order2,
  max(case when `order` = 3 then data end) order3,
  max(case when item = 1 then price end) item1,
  max(case when item = 2 then price end) item2,
  max(case when item = 3 then price end) item3,
  max(case when item = 4 then price end) item4
from tableA
group by id;

デモ を参照してください。しかし、発生する問題の一部は、データの複数の列を変換しようとしているためです。最終結果を得るための私の提案は、最初にデータのピボットを解除することです。 MySQLにはピボット解除機能はありませんが、UNION ALLを使用して、列の複数のペアを行に変換できます。ピボットを解除するコードは次のようになります。

select id, concat('order', `order`) col,  data value
from tableA
union all
select id, concat('item', item) col, price value
from tableA;

デモ を参照してください。この結果は次のようになります。

| ID |    COL | VALUE |
-----------------------
|  1 | order1 |     P |
|  1 | order1 |     P |
|  1 | order1 |     P |
|  1 |  item1 |    50 |
|  1 |  item2 |    60 |
|  1 |  item3 |    70 |

ご覧のとおり、これはorder/dataitem/priceの複数の列を取得し、複数の行に変換しています。それが完了したら、CASEを使用した集計関数を使用して、値を列に戻すことができます。

select id, 
  max(case when col = 'order1' then value end) order1,
  max(case when col = 'order2' then value end) order2,
  max(case when col = 'order3' then value end) order3,
  max(case when col = 'item1' then value end) item1,
  max(case when col = 'item2' then value end) item2,
  max(case when col = 'item3' then value end) item3
from
(
  select id, concat('order', `order`) col,  data value
  from tableA
  union all
  select id, concat('item', item) col, price value
  from tableA
) d
group by id;

デモ を参照してください。最後に、上記のコードを動的なプリペアドステートメントクエリに変換する必要があります。

SET @sql = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'max(case when col = ''',
      col,
      ''' then value end) as `', 
      col, '`')
  ) INTO @sql
FROM
(
  select concat('order', `order`) col
  from tableA
  union all
  select concat('item', `item`) col
  from tableA
)d;

SET @sql = CONCAT('SELECT id, ', @sql, ' 
                  from
                  (
                    select id, concat(''order'', `order`) col,  data value
                    from tableA
                    union all
                    select id, concat(''item'', item) col, price value
                    from tableA
                  ) d
                  group by id');

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

SQL Fiddle with demo を参照してください。これにより、次の結果が得られます。

| ID | ORDER1 | ORDER2 | ORDER3 | ITEM1 | ITEM2 |  ITEM3 |  ITEM4 |
-------------------------------------------------------------------
|  1 |      P |      Q | (null) |    50 |    60 |     70 | (null) |
|  2 |      P | (null) |      S |    50 |    60 | (null) |     80 |
18
Taryn