Question

Say I have a query that returns values like this:

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

There are > 50 million rows and 240 possible "types". I want to make a pivot where there is one row for each id and each type is it's own column:

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

I can do this in SQL server but I don't know how to do it in Teradata. There are too many columns for me to make CASE statements. However, each distinct type is in a table field, if that's any help.

Was it helpful?

Solution

There is no pivot function in Teradata SQL. A similar question was answered here - teradata sql pivot multiple occurrences into additional columns.

To best achieve what you wanted without having to write out 250 cases manually, you should use ordered analytical functions in some kind of a loop or a set. Try searching "loop" tag from Teradata Developer Exchange - http://developer.teradata.com/tag/loop

Here's how I would do it: Use another programming language (Python) to reiterate over a text/premade SQL and change it's only two variables 250 times, from 1 to 250, and generate the full long sql. Only reiterate the part between SELECT DISTINCT id and last FROM mytable row:

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

You can use this 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)

OTHER TIPS

There is a TD_UNPIVOT function which was added in TD 14.10 can be found in TD_SYSFNLIB.

TD_UNPIVOT Function

The PIVOT and UNPIVOT SQL commands were added in Teradata 16 and they can be found in the SQL Functions, Operators, Expressions, and Predicates manual. At this time, I can't find them in an online manual so you will need to download the PDF from Teradata.com.

New TD 16 Features PIVOT and UNPIVOT

Using PIVOT function in Teradata 16 it could look like this (assuming your types are in a table called mytypetable):

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

One drawback is that you cannot decide on the order of the columns though.

Pivot functionality has been added at least as far back as v16.1:

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

Providing some examples for this answer.

v16.2 and newer allows for you to select distinct values from a table in your pivot, where as 16.1 you will need to specify the fields to pivot on. Both examples provided below.

DDL to create sample table:

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

In 16.1 you MUST specify fields to pivot (note double quotes to convert type names into valid column name):

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

16.2 is a little more flexible, eliminating the need to specify pivot fields explicitly:

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

Both results are the same:

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

However, as far as I know -in 16.2 at least-, you can not physicalize results when using a subquery to pivot (e.g. for typ in (Select Distinct typ from tbl ) within the pivot operator. This limits dynamically defined pivots to final results sets. You can however create a view, volatile, or physical table from a pivot when you explicitly define the fields (e.g. for typ in ('1a','1b','1c','2a' )). Hopefully Teradata will enhance this to include subqueries in the future.

You can pivot using multiple aggregate functions:

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

There is also an unpivot function that you can use to convert a long table to wide. Thank you @dnoeth for providing the solution in the comments below.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top