Cohort-style Table (Diagonal Grid) in SQL

假如想象 提交于 2020-01-25 12:41:51

问题


I need to create a table that is like the image below:

I can create the full 9 row table in sql using this code:

   select a.start_year, a.start_month, b.start_year as order_year, 
          b.start_month as order_month
    from list a
    cross join list b; 

How can I remove the unwanted rows, or just not create them in the first place?


回答1:


in ORACLE 11g

SELECT * FROM
(
  SELECT y, x
  FROM table_name
)
PIVOT
(
  MAX(z)
  FOR x IN (1, 2, 3)
)
ORDER BY y;

in SQL SERVER

SELECT   [y], [1], [2], [3]
FROM   [dbo].[table_name] 
PIVOT
(
       MAX(z)
       FOR [x] IN ([1], [2], [3])
) AS P

in PostgreSQL

First compute the maximum value with the aggregate function max():

SELECT y, x, MAX(z)
FROM   table_name
GROUP  BY 1,2
ORDER  BY 1,2

Then feed the result to the crosstab() function as instructed in great detail in this related answer

Simple form - not fit for missing attributes

crosstab() with one parameter:

SELECT *
FROM   crosstab(
      'SELECT x,y, z
       FROM   table_name
       ORDER  BY 1,2')  -- needs to be "ORDER BY 1,2" here
AS ct ("X" text, "1" text, "2" text, "3" text);

Returns:

   x    |  1  |  2  |  3  
--------+-----+-----+-----
   A    |  a  |  b  |  c  
   B    |  d  |  e  |     
   C    |  f  |     |     
  • No need for casting and renaming.
  • Note the incorrect result for C the value f is filled in for the first column.

Safe form

crosstab() with two parameters:

SELECT * FROM crosstab(
       'SELECT x, y, z
        FROM   table_name
        ORDER  BY 1,2'  -- could also just be "ORDER BY 1" here

      ,$$VALUES ('1'::text), ('2'), ('3')$$)
AS ct ("X" text, "1" text, "2" text, "3" text);

Returns:

   x    |  1  |  2  |  3  
--------+-----+-----+-----
   A    |  a  |  b  |  c  
   B    |  d  |  e  |     
   C    |     |     |  f 
  • Note the correct result for C.

  • The second parameter can be any query that returns one row per attribute matching the order of the column definition at the end. Often you will want to query distinct attributes from the underlying table like this:

    'SELECT DISTINCT attribute FROM table_name ORDER BY 1'
    

    That's in the manual.

    Since you have to spell out all columns in a column definition list anyway (except for pre-defined crosstabN() variants), it is regularly more efficient to provide a short list in a VALUES expression like I demonstrate:

    $$VALUES ('1'::text), ('2'), ('3')$$)
    

    Or:

    $$SELECT unnest('{1,2,3}'::text[])$$ -- shorter for long lists
    

    That's not in the manual.

    I used dollar quoting to make quoting easier.

sqlpostgresqloraclesqlserver



来源:https://stackoverflow.com/questions/38365078/cohort-style-table-diagonal-grid-in-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!