Mysql, изменить данные от длинного / высокого к широкому - PullRequest
23 голосов
/ 13 февраля 2010

У меня есть данные в таблице mysql в длинном / высоком формате (описано ниже) и я хочу преобразовать их в широкоформатный. Могу ли я сделать это, используя только sql?

Проще всего объяснить на примере. Предположим, у вас есть информация (страна, ключ, значение) для M стран, N ключей (например, ключами могут быть доход, политический лидер, регион, континент и т. Д.)

Long format has 3 columns: country, key, value
  - M*N rows.
  e.g. 
  'USA', 'President', 'Obama'
   ...
  'USA', 'Currency', 'Dollar'

Wide format has N=16 columns: county, key1, ..., keyN
  - M rows
example: 
   country, President, ... , Currency
   'USA', 'Obama', ... , 'Dollar'

Есть ли способ в SQL создать новую таблицу с данными в широком формате?

select distinct key from table;

// это даст мне все ключи.

1) Как мне тогда создать таблицу, используя эти ключевые элементы?

2) Как мне тогда заполнить таблицу значений?

Я почти уверен, что могу сделать это с любым языком сценариев (мне нравится python), но я хотел знать, есть ли простой способ сделать это в mysql. Во многих статистических пакетах, таких как R и STATA, эта команда встроена, потому что она часто используется.

======

Чтобы быть более понятным, вот желаемый входной вывод для простого случая:

Введите:

country    attrName    attrValue     key  (these are column names)
US         President   Obama         2
US         Currency    Dollar        3
China      President   Hu            4
China      Currency    Yuan          5

выход

country    President    Currency    newPkey
US         Obama        Dollar      1
China      Hu           Yuan        2

Ответы [ 3 ]

20 голосов
/ 25 февраля 2010

Кросс-таблицы или сводные таблицы является ответом. Оттуда вы можете ВЫБРАТЬ ИЗ ... ВСТАВИТЬ В ... или создать ВИД из одного ВЫБОР.

Что-то вроде:

SELECT country, 
       MAX( IF( key='President', value, NULL ) ) AS President,
       MAX( IF( key='Currency', value, NULL ) ) AS Currency,
       ...

FROM table 
GROUP BY country;

Для получения дополнительной информации: http://dev.mysql.com/tech-resources/articles/wizard/index.html

5 голосов
/ 25 февраля 2010

Я думаю, что нашел решение, которое использует VIEWS и INSERT INTO (как предложено e4c5).

Вы должны получить свой список AttrNames / Keys самостоятельно, но MYSQL выполняет другую тяжелую работу.

В приведенном выше простом тестовом примере создайте new_table с соответствующими столбцами (не забудьте также иметь первичный ключ с автоинкрементом). Тогда

CREATE VIEW a
AS SELECT country, attrValue
WHERE attrName="President";

CREATE VIEW b
AS SELECT country, attrValue
WHERE attrName="Currency";


INSERT INTO newtable(country, President, Currency)
SELECT a.country, a.attrValue, b.attrValue
FROM  a
INNER JOIN b  ON a.country=b.country;

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

INSERT INTO newtable(country, President, Currency, Capital, Population)
SELECT a.country, a.attrValue, b.attrValue, c.attrValue, d.attrValue
FROM  a
INNER JOIN b  ON a.country=b.country
INNER JOIN c  ON a.country=c.country
INNER JOIN d  ON a.country=d.country;

Еще несколько советов

  • используйте NATURAL LEFT JOIN, и вам не нужно указывать предложение ON
3 голосов
/ 13 февраля 2010

Если бы вы использовали SQL Server, это было бы легко с помощью UNPIVOT . Насколько мне известно, это не реализовано в MySQL, поэтому, если вы хотите сделать это (и я бы посоветовал против этого), вам, вероятно, придется генерировать SQL динамически, и это грязно.

...