我有这个表以及其他几个列:
months amount
-----------------
Jan 100
Feb 200
Jan 400
我想用这个表创建一个视图,如下所示:
Jan Feb
--------------------
100 200
400 0
我搜索过它并且PL / SQL解决方案只能用SQL查询完成吗? 谢谢
答案 0 :(得分:1)
首先确保您拥有Crosstab
CREATE EXTENSION tablefunc;
要获得交叉,你需要至少三列
例如:
name months amount
-------------------------
Helga Jan 100
Helga Feb 200
Bernd Jan 400
然后你就像这样创建你的Crosstable:
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
如果您打算每个月都有列,请坚持manual
中所述的示例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)
答案 1 :(得分: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。