2010-02-12 9 views
16

Mam dane w tabeli mysql w formacie długim/wysokim (opisane poniżej) i chcę przekonwertować go na szeroki format. Czy mogę to zrobić za pomocą samego sql?Mysql, przekształć dane z długich/wysokich na szerokie

Najprościej wyjaśnić na przykładzie. Załóżmy, że masz informacje na temat (kraj, klucz, wartość) dla krajów M, N (np kluczy klucze mogą być dochód, lider polityczny, powierzchnia, kontynent, itd.)

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' 

Czy istnieje sposób, aby utworzyć w SQL nowa tabela z danymi w szerokim formacie?

select distinct key from table; 

// to dostanie mi wszystkie klucze.

1) Jak utworzyć tabelę przy użyciu tych kluczowych elementów?

2) W jaki sposób wypełnić wartości w tabeli?

Jestem prawie pewien, że mogę to zrobić z dowolnym językiem skryptowym (lubię pythona), ale chciałem się dowiedzieć, czy istnieje prosty sposób, aby to zrobić w mysql. Wiele pakietów statystycznych, takich jak R i STATA, ma wbudowane to polecenie, ponieważ jest często używane.

======

Aby być bardziej jasne, tutaj jest to pożądane wyjście wejście dla prostego przypadku:

Wejście:

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

Wyjście

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

Odpowiedz

11

Cross-tabs lub tabel przestawnych jest odpowiedzią. Stamtąd możesz WYBRAĆ Z ... INSERT INTO ... lub stworzyć WIDOK z pojedynczego SELECT.

Coś jak:

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

FROM table 
GROUP BY country; 

Aby uzyskać więcej informacji: http://dev.mysql.com/tech-resources/articles/wizard/index.html

+3

Mój sposób działa. Twoja droga jest znacznie lepsza. KOCHAM CIĘ lub Dziękuję. Wybierz, który z nich wolisz, aby wyrazić uznanie. – chongman

+1

Operator IF jest własnością MySQL. Zamiast tego użyj CASE, aby być zgodnym ze standardowym SQL. Więcej szczegółów tutaj: [SQLite od długich do szerokich formatów?] (Http://www.stackoverflow.com/questions/2444708/sqlite-long-to-wide-formats) – SuperAce99

+0

@mluebke: Twój link jest martwy :( –

3

Jeśli korzystasz z SQL Server, będzie to łatwe przy użyciu UNPIVOT. O ile mi wiadomo, nie jest to zaimplementowane w MySQL, więc jeśli chcesz to zrobić (i odradzam to), prawdopodobnie będziesz musiał generować SQL dynamicznie, a to niechlujnie.

3

Myślę, że znalazłem rozwiązanie, które wykorzystuje VIEWS i INSERT INTO (zgodnie z sugestią e4c5).

Musisz sam dostać listę AttrNames/Keys, ale MYSQL wykonuje inne ciężkie podnoszenie.

Dla prostego przypadku testowego powyżej utwórz nową_tabelę z odpowiednimi kolumnami (nie zapomnij również o kluczu automatycznym). Następnie, jeśli masz więcej attrNames, utwórz po jednym widoku dla każdego, a następnie odpowiednio dostosuj ostatnią instrukcję.

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; 

kilka wskazówek

  • użycie NATURAL LEFT JOIN i nie trzeba określać klauzuli o
Powiązane problemy