Mysql,重塑数据从长/高到宽
Posted
技术标签:
【中文标题】Mysql,重塑数据从长/高到宽【英文标题】:Mysql, reshape data from long / tall to wide 【发布时间】:2011-01-16 08:56:12 【问题描述】:我在 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
【问题讨论】:
【参考方案1】:如果您使用的是 SQL Server,则使用 UNPIVOT 会很容易。据我所知,这并没有在 MySQL 中实现,所以如果你想这样做(我建议不要这样做),你可能必须动态生成 SQL,这很麻烦。
【讨论】:
【参考方案2】:我想我找到了解决方案,它使用 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】:交叉表或数据透视表就是答案。从那里您可以 SELECT FROM ... INSERT INTO ... 或从单个 SELECT 创建一个 VIEW。
类似:
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
【讨论】:
我的方法行得通。你的方法好多了。我爱你或谢谢。选择您喜欢的方式来表达感激之情。 IF 运算符是 MySQL 专有的。改为使用 CASE 以符合标准 SQL。更多细节在这里:SQLite long to wide formats? @mluebke: 你的链接失效了:( 为什么每行都必须使用“max()”而不是国家/地区? 因为您是按国家/地区分组的,所以对于组而言,它始终是一个一致的值。以上是关于Mysql,重塑数据从长/高到宽的主要内容,如果未能解决你的问题,请参考以下文章