簡體   English   中英

Sql:將行轉換為列

[英]Sql: Transposing rows into columns

考慮下面的示例,其中我有一個包含人員記錄的Person表和一個包含鏈接到人員的可選屬性的PersonAttribute表:

表:人

ID    Name
1     Joe Bloggs
2     Jane Doe

表 PersonAttribute

PersonId  Key         Value
1         Age         27            
2         HairColor   Brown

我將如何編寫一個查詢來返回所有具有屬性的人,就好像他們是列一樣? 我需要的結果集是:

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

所以基本上我需要編寫一個查詢,獲取所有具有唯一屬性鍵的所有人員記錄,並將其轉換為具有每個人員記錄值的列。

請注意, PersonAttribute表上的主鍵是PersonIDKey組合,因此我們不會有特定鍵和人員的重復條目。

顯然,我可以將AgeHairColor作為字段添加到Person表中,而根本不使用PersonAttribute表,但這只是說明問題的一個示例。 實際上,我有大量的自定義屬性,這些屬性因不同的人員記錄而有很大差異,因此這樣做是不切實際的。

我不能談論 MySQL,但在 PostgreSQL 中,您可以使用來自tablefunc模塊的交叉表 function:

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
    );

加盟查詢:

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

想要的結果:

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

如您所見,我在PersonAttributePivot視圖中放置了明確的列列表。 我不知道任何帶有隱式列列表的“自動樞軸”創建方式。

編輯:

對於巨大的列列表(假設總是text類型)作為一種解決方法,我看到了這樣一些修改過的方法:

動態類型創建(這里基於 Java):

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(");");

結果:

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

Function 包裝:

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

自動視圖創建:

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

結果:

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

將基於行的數據集轉換為基於列的數據集的過程稱為透視。 您可能會在此鏈接上對如何執行此操作有所了解: 如何 pivot a MySQL 實體-屬性-值模式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM