我有这张表以及其他几列:
months amount
-----------------
Jan 100
Feb 200
Jan 400
我想用这个表创建一个视图,使它像这样:
Jan Feb
--------------------
100 200
400 0
我搜索了它并得到了 PL/SQL 解决方案不能只用 SQL 查询来完成吗?谢谢你
我有这张表以及其他几列:
months amount
-----------------
Jan 100
Feb 200
Jan 400
我想用这个表创建一个视图,使它像这样:
Jan Feb
--------------------
100 200
400 0
我搜索了它并得到了 PL/SQL 解决方案不能只用 SQL 查询来完成吗?谢谢你
首先确保您有可用的交叉表
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)
你的逻辑有问题,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。