【问题标题】:Accomplish pivot in teradata sql在 teradata sql 中完成数据透视
【发布时间】:2014-04-15 15:54:23
【问题描述】:

假设我有一个返回值如下的查询:

id    type     value
aaa   1a        10
aaa   1b        20
aaa   1c        7
bbb   2a        10
bbb   1a        5

有 > 5000 万行和 240 种可能的“类型”。我想做一个支点,每个id 有一行,每个type 是它自己的列:

id   1a   1b   1c   2a
aaa  10   20   7    
bbb  5              10

我可以在 SQL Server 中执行此操作,但我不知道如何在 Teradata 中执行此操作。我的列太多了,无法进行 CASE 陈述。但是,如果有帮助的话,每个不同的 type 都在一个表字段中。

【问题讨论】:

    标签: teradata


    【解决方案1】:

    Teradata SQL 中没有数据透视函数。这里回答了一个类似的问题 - teradata sql pivot multiple occurrences into additional columns

    为了最好地实现您想要的,而不必手动写出 250 个案例,您应该在某种循环或集合中使用有序分析函数。尝试从 Teradata Developer Exchange 搜索“循环”标签 - http://developer.teradata.com/tag/loop

    我会这样做:使用另一种编程语言 (Python) 重复文本/预制 SQL,并将其仅更改两个变量 250 次,从 1 到 250,然后生成完整的长 sql。只重申SELECT DISTINCT id 和最后FROM mytable 行之间的部分:

    SELECT DISTINCT
    id
    -- reiteration starts here
    ,(SELECT SUM(value) -- assuming you have unique types for every id
      FROM (SELECT DISTINCT
        id
        ,value
        ,type
        FROM mytable
        QUALIFY (RANK() OVER(PARTITION BY type ORDER BY id ASC))=1 -- variable 1
        )
    ) AS type_1 -- variable 2
    -- reiteration ends here
    FROM mytable
    

    你可以使用这个python:

    for i in range(1,251):
        print " \
    ,(SELECT SUM(value) -- assuming you have unique types for every id \
    FROM (SELECT DISTINCT \
    id \
    ,value \
    ,type \
    FROM mytable \
    QUALIFY (RANK() OVER(PARTITION BY type ORDER BY id ASC))=%d -- variable 1 \
    ) \
    ) AS type_%d -- variable 2 \
    " % (i,i)
    

    【讨论】:

      【解决方案2】:

      TD_SYSFNLIB 中可以找到 TD 14.10 中添加的 TD_UNPIVOT 函数。

      TD_UNPIVOT Function

      PIVOT 和 UNPIVOT SQL 命令是在 Teradata 16 中添加的,它们可以在 SQL 函数、运算符、表达式和谓词手册中找到。目前,我无法在在线手册中找到它们,因此您需要从 Teradata.com 下载 PDF。

      New TD 16 Features PIVOT and UNPIVOT

      【讨论】:

      【解决方案3】:

      在 Teradata 16 中使用 PIVOT 函数可能如下所示(假设您的类型位于名为 mytypetable 的表中):

      SELECT 
        *
      FROM 
        mytable PIVOT (SUM("value") FOR "type" IN (SELECT "Type" FROM mytypetable)) AS Temp_pivot
      ORDER BY 
        id
      

      一个缺点是您无法决定列的顺序。

      【讨论】:

        【解决方案4】:

        至少早在 v16.1 中就已经添加了 Pivot 功能:

        https://docs.teradata.com/r/756LNiPSFdY~4JcCCcR5Cw/GnnbigJTnAWrDfLbecAN7Q

        为此答案提供一些示例。

        v16.2 和更高版本允许您从数据透视表中的表中选择不同的值,而在 16.1 中,您需要指定要透视的字段。下面提供了两个示例。

        DDL 创建示例表:

        Create table tbl(id varchar(3), typ varchar(2), val smallint);
        insert into  tbl ('aaa',   '1a',  10);
        insert into  tbl ('aaa',   '1b',  20);
        insert into  tbl ('aaa',   '1c',  7);
        insert into  tbl ('bbb',   '2a',  10);
        insert into  tbl ('bbb',   '1a',  5);
        

        在 16.1 中,您必须指定要转置的字段(注意双引号将类型名称转换为有效的列名称):

        Select *
        from tbl pivot (sum(val)
                        for typ in ('1a' as "1a" ,'1b' as "1b",'1c' as "1c",'2a' as "2a" )
            ) tmp
        

        16.2 更灵活一些,无需显式指定数据透视字段:

        SELECT *
        from tbl pivot (sum(val)
                        for typ in (Select distinct typ from tbl)
            ) tmp
        order by 1
        

        两个结果是一样的:

        id 1a 1b 1c 2a
        aaa 10 20 7 NULL
        bbb 5 NULL NULL 10

        但是,据我所知 - 至少在 16.2 中 - 在枢轴运算符中使用子查询进行枢轴(例如 for typ in (Select Distinct typ from tbl )时,您无法物理化结果。这将动态定义的枢轴限制为最终结果集。但是,当您明确定义字段时(例如for typ in ('1a','1b','1c','2a' )),您可以从数据透视表创建视图、易失性或物理表。希望 Teradata 能够增强这一功能,以便在未来包含子查询。

        您可以使用多个聚合函数进行透视:

        SELECT *
        from tbl pivot (sum(val) as "Sum", count(val) as "Count"
                        for typ in (Select distinct typ from tbl)
            ) tmp
        order by 1
        
        id 2a_Sum 1c_Sum 1a_Sum 1b_Sum 2a_Count 1c_Count 1a_Count 1b_Count
        aaa NULL 7 10 20 0 1 1 1
        bbb 10 NULL 5 NULL 1 0 1 0

        还有一个 unpivot 函数可用于将长表转换为宽表。感谢@dnoeth 在下面的 cmets 中提供解决方案。

        【讨论】:

        • for typ in (Select ... 被限制为 16 个值,并且无法对列进行排序,两者都使其无用。
        • 感谢@dnoeth 提供额外的上下文。我认为它在有限的上下文中可能很有用(在较小范围内的快速临时查询),但我同意它严重缺乏。
        • 关于您使用 UNPIVOT 的问题,此方法有效:SELECT * FROM y UNPIVOT ( val FOR typ IN (a1, b1, c1, a2) ) tmp
        猜你喜欢
        • 1970-01-01
        • 2011-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多