0

我有这张表以及其他几列:

months    amount
-----------------
 Jan       100
 Feb       200
 Jan       400 

我想用这个表创建一个视图,使它像这样:

Jan    Feb
--------------------
100    200
400    0

我搜索了它并得到了 PL/SQL 解决方案不能只用 SQL 查询来完成吗?谢谢你

4

2 回答 2

1

首先确保您有可用的交叉表

CREATE EXTENSION tablefunc;

要获得您想要的交叉表,您至少需要三列

例如:

name    months    amount
-------------------------
Helga    Jan       100
Helga    Feb       200
Bernd    Jan       400 

然后你像这样创建你的交叉表:

SELECT * FROM 
   crosstab('SELECT name, month, amount from temp')
 AS ct(name varchar, jan int, feb int);

name       jan       feb
--------------------------
Helga     100        200
Bernd     400

如果您打算每个月都有列,请按照手册中所述的示例进行操作

create table sales(year int, month int, qty int);
insert into sales values(2007, 1, 1000);
insert into sales values(2007, 2, 1500);
insert into sales values(2007, 7, 500);
insert into sales values(2007, 11, 1500);
insert into sales values(2007, 12, 2000);
insert into sales values(2008, 1, 1000);

select * from crosstab(
  'select year, month, qty from sales order by 1',
  'select m from generate_series(1,12) m'
) as (
  year int,
  "Jan" int,
  "Feb" int,
  "Mar" int,
  "Apr" int,
  "May" int,
  "Jun" int,
  "Jul" int,
  "Aug" int,
  "Sep" int,
  "Oct" int,
  "Nov" int,
  "Dec" int
);
 year | Jan  | Feb  | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov  | Dec
------+------+------+-----+-----+-----+-----+-----+-----+-----+-----+------+------
 2007 | 1000 | 1500 |     |     |     |     | 500 |     |     |     | 1500 | 2000
 2008 | 1000 |      |     |     |     |     |     |     |     |     |      |
(2 rows)
于 2012-05-29T10:40:30.050 回答
1

你的逻辑有问题,SQL怎么知道它应该是

Jan     Feb
100     200
400     0

并不是

Jan     Feb
400     200
100     0

我认为这意味着列应该按升序排列,(除了因为没有足够的数据而值为 0 的地方):

WITH CTE AS
(   SELECT  Month, Amount, ROW_NUMBER() OVER(PARTITION BY Month ORDER BY Amount) AS RowNumber
    FROM    T
)
SELECT  COALESCE(Jan.Amount, 0) AS Jan,
        COALESCE(Feb.Amount, 0) AS Feb,
        COALESCE(Mar.Amount, 0) AS Mar
FROM    (   SELECT  RowNumber, Amount
            FROM    CTE
            WHERE   Month = 'Jan'
        ) jan
        FULL JOIN 
        (   SELECT  RowNumber, Amount
            FROM    CTE
            WHERE   Month = 'Feb'
        ) feb
            ON feb.RowNumber = Jan.RowNumber
        FULL JOIN 
        (   SELECT  RowNumber, Amount
            FROM    CTE
            WHERE   Month = 'Mar'
        ) Mar
            ON Mar.RowNumber = Jan.RowNumber

此逻辑已在SQL Fiddle中进行了测试,但是我相当确定您可以将 Rownumber 的使用应用于 CROSSTAB 以解决您当前在使用 CROSSTAB 时遇到的问题。RowNumber 成为你的行值,我从未在 postgres 中使用过 Crosstab,但我认为你最终会得到这样的结果:

SELECT  *
FROM    CROSSTAB('SELECT ROW_NUMBER() OVER(PARTITION BY Month ORDER BY Amount) AS RowNumber, Month, Amount FROM T',
                 'SELECT DISTINCT ROW_NUMBER() OVER(PARTITION BY Month ORDER BY Amount) AS RowNumber FROM  T') 
        AS (RowNumber INT, Jan INT, Feb INT, Mar INT);

我无法在 SQL Fiddle 上使用它,但我认为这是因为 CROSSTAB 未启用,因为即使 Postgres 文档中的示例也不适用于 SQL Fiddle。

于 2012-05-29T10:57:57.640 回答