SQL:将行转换为列 [英] Sql: Transposing rows into columns

查看:101
本文介绍了SQL:将行转换为列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下示例,其中有一个包含人记录的 Person 表和一个包含与人相关的可选属性的 PersonAttribute 表:



表:人员

 
ID名称
1 Joe Bloggs
2 Jane Doe

表PersonAttribute

 
PersonId键值
1年龄27
2 HairColor棕色

我编写一个查询,使所有具有属性的人都像列一样返回?我需要的结果集是:

 
ID名称年龄HairColor
1 Joe Bloggs 27
2 Jane Doe Brown

因此,基本上我需要编写一个查询,该查询将所有具有所有唯一属性键的人记录转换为列,并包含每条人记录的值。 / p>

请注意, PersonAttribute 表上的主键是 PersonID Key 我们不会重复输入特定的键和人员。



很明显,我可以添加 Age HairColor 作为 Person 表中的字段,根本不使用 PersonAttribute 表,但这仅是说明问题的一个示例。实际上,我有大量的自定义属性,这些属性对于不同的人记录而言千差万别,因此这样做是不现实的。

解决方案

我无法谈论MySQL,但是在PostgreSQL中,您可以使用 tablefunc 模块:

 创建或替换视图PersonAttributePivot AS 
SELECT PersonId AS ID,年龄,发色
从交叉表

'选择PersonId,键,来自PersonAttribute的值',
'从个人属性ORDER BY BY键中选择不同的键'

AS

PersonId整数,
年龄文本,
HairColor文本
);

加入查询:

 选择id,名称,年龄,发色
FROM Person JOIN PersonAttributePivot USING(id)
ORDER BY id;

想要的结果:

  id |名称|年龄| haircolor 
---- + ------------ + ----- + -----------
1 |乔·博格斯| 27 |
2 |简·杜|棕色
(2行)

如您所见,我在<$中放置了明确的列列表c $ c> PersonAttributePivot 视图。我不知道使用隐式列列表的任何自动旋转创建方式。



编辑:



对于巨大列列表(假定总是 text 类型)作为一种变通办法,我看到了这么小的修改方法:



动态类型创建(此处基于Java):



  Class.forName(  org.postgresql.Driver); 
连接c =
DriverManager.getConnection( jdbc:postgresql:// localhost / postgres, postgres, 12345);
语句s = c.createStatement();
ResultSet rs = s.executeQuery(从PersonAttribute ORDER BY键中选择DISTINCT键);
List< String>列=新的ArrayList< String>();

而(rs.next())
columns.add(rs.getString(1));

System.out.println(创建类型PersonAttributePivotType AS();
System.out.println( \tPersonId整数,);
用于(int i = 0; i< columns.size(); ++ i)
{
System.out.print( \t + columns.get(i)+ text);
if(i!= columns.size()-1)
System.out.print(,);
System.out.println();
}
System.out.println(););

结果:

 创建类型PersonAttributePivotType AS(
PersonId整数,
年龄文本,
HairColor文本
);



函数包装:



 创建或替换功能crosstabPersonAttribute(text,text)
返回setofPersonAttributePivotType
AS'$ libdir / tablefunc','crosstab_hash'语言C稳定的语法;



自动创建视图:



 创建或替换视图PersonAttributePivot AS 
SELECT * FROM crosstabPersonAttribute

'SELECT PersonId,Key,Value FROM PersonAttribute',
'SELECT DISTINCT Key FROM PersonAttribute ORDER BY键'
);

结果:

  TABLE PersonAttributePivot; 
personid |年龄| haircolor
---------- + ----- + -----------
1 | 27 |
2 | |棕色
(2行)


Consider the example below where I have a Person table containing person records and a PersonAttribute table which contains optional attributes linked to a person:

Table: Person

ID    Name
1     Joe Bloggs
2     Jane Doe

Table PersonAttribute

PersonId  Key         Value
1         Age         27            
2         HairColor   Brown

How would I write a query that returns all people with the attributes as if they were columns? The resultset I require is:

ID    Name        Age    HairColor
1     Joe Bloggs  27     
2     Jane Doe           Brown

So essentially I need to write a query that gets all Person Records with all unique Attribute Keys transposed as columns with the value for each person record.

Note that the primary key on the PersonAttribute table is PersonID and Key combined so we wont have duplicate entries for a specific key and person.

Obviously I could add the Age and HairColor as fields in the Person table and not use the PersonAttribute table at all, but this is just an example to illustrate the problem. In reality I have a huge number of custom attributes that vary wildly for different person records so it is not practical to do it that way.

解决方案

I can't speak about MySQL, but in PostgreSQL you could use crosstab function from tablefunc module:

CREATE OR REPLACE VIEW PersonAttributePivot AS
    SELECT PersonId AS ID, Age, HairColor
    FROM crosstab
    (
       'SELECT PersonId, Key, Value FROM PersonAttribute',
       'SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key'
    )
    AS
    (
        PersonId integer,
        Age text,
        HairColor text
    );

Join query:

SELECT id, name, age, haircolor
FROM Person JOIN PersonAttributePivot USING(id)
ORDER BY id;

Wanted result:

 id |    name    | age | haircolor 
----+------------+-----+-----------
  1 | Joe Bloggs | 27  | 
  2 | Jane Doe   |     | Brown
(2 rows)

As you see I put explicit list of columns in PersonAttributePivot view. I don't know any "automatic-pivot" creation way with implicit column list.

EDIT:

For huge column list (assuming always text type) as a workaround I see such little modified approach:

Dynamic type creation (here trivially Java based):

Class.forName("org.postgresql.Driver");
Connection c =
        DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "postgres", "12345");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key");
List<String> columns = new ArrayList<String>();

while (rs.next())
    columns.add(rs.getString(1));

System.out.println("CREATE TYPE PersonAttributePivotType AS (");
System.out.println("\tPersonId integer,");
for (int i = 0; i < columns.size(); ++i)
{
    System.out.print("\t" + columns.get(i) + " text");
    if (i != columns.size() - 1)
        System.out.print(",");
    System.out.println();
}
System.out.println(");");

Result:

CREATE TYPE PersonAttributePivotType AS (
    PersonId integer,
    Age text,
    HairColor text
);

Function wrapper:

CREATE OR REPLACE FUNCTION crosstabPersonAttribute(text, text)
    RETURNS setof PersonAttributePivotType
    AS '$libdir/tablefunc','crosstab_hash' LANGUAGE C STABLE STRICT;

Automatic view creation:

CREATE OR REPLACE VIEW PersonAttributePivot AS
    SELECT * FROM crosstabPersonAttribute
    (
       'SELECT PersonId, Key, Value FROM PersonAttribute',
       'SELECT DISTINCT Key FROM PersonAttribute ORDER BY Key'
    );

Result:

TABLE PersonAttributePivot;
 personid | age | haircolor
----------+-----+-----------
        1 | 27  |
        2 |     | Brown
(2 rows)

这篇关于SQL:将行转换为列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆