PostgreSQL交叉表查询
有人知道如何在PostgreSQL中创建交叉表查询吗?PostgreSQL交叉表查询,sql,postgresql,pivot,case,crosstab,Sql,Postgresql,Pivot,Case,Crosstab,有人知道如何在PostgreSQL中创建交叉表查询吗? 例如,我有下表: 区段状态计数 主动1 A不活跃的2 B活动4 B非活动5 我希望查询返回以下交叉表: 段激活-非激活 A 12 B 4 5 这可能吗?很抱歉,这还不完整,因为我无法在这里进行测试,但它可能会让您朝着正确的方向前进。我在翻译一个类似的查询: select mt.section, mt1.count as Active, mt2.count as Inactive from mytable mt left join (se
例如,我有下表:
区段状态计数
主动1
A不活跃的2
B活动4
B非活动5
我希望查询返回以下交叉表:
段激活-非激活
A 12
B 4 5
这可能吗?很抱歉,这还不完整,因为我无法在这里进行测试,但它可能会让您朝着正确的方向前进。我在翻译一个类似的查询:
select mt.section, mt1.count as Active, mt2.count as Inactive
from mytable mt
left join (select section, count from mytable where status='Active')mt1
on mt.section = mt1.section
left join (select section, count from mytable where status='Inactive')mt2
on mt.section = mt2.section
group by mt.section,
mt1.count,
mt2.count
order by mt.section asc;
我使用的代码是:
select m.typeID, m1.highBid, m2.lowAsk, m1.highBid - m2.lowAsk as diff, 100*(m1.highBid - m2.lowAsk)/m2.lowAsk as diffPercent
from mktTrades m
left join (select typeID,MAX(price) as highBid from mktTrades where bid=1 group by typeID)m1
on m.typeID = m1.typeID
left join (select typeID,MIN(price) as lowAsk from mktTrades where bid=0 group by typeID)m2
on m1.typeID = m2.typeID
group by m.typeID,
m1.highBid,
m2.lowAsk
order by diffPercent desc;
它将返回typeID、最高出价和最低要求价格以及两者之间的差异(正差异意味着可以以低于销售价格的价格购买东西)。您可以使用的
crosstab()
函数-必须为每个数据库安装一次。从PostgreSQL 9.1开始,您可以使用:
CREATE EXTENSION tablefunc;
CREATE EXTENSION IF NOT EXISTS tablefunc;
在你的情况下,我相信会是这样的:
CREATE TABLE t (Section CHAR(1), Status VARCHAR(10), Count integer);
INSERT INTO t VALUES ('A', 'Active', 1);
INSERT INTO t VALUES ('A', 'Inactive', 2);
INSERT INTO t VALUES ('B', 'Active', 4);
INSERT INTO t VALUES ('B', 'Inactive', 5);
SELECT row_name AS Section,
category_1::integer AS Active,
category_2::integer AS Inactive
FROM crosstab('select section::text, status, count::text from t',2)
AS ct (row_name text, category_1 text, category_2 text);
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
每个数据库安装一次,该数据库提供函数crosstab()
。从Postgres 9.1开始,您可以使用:
CREATE EXTENSION tablefunc;
CREATE EXTENSION IF NOT EXISTS tablefunc;
改进的测试用例
简单表单-不适合缺少的属性
交叉表(文本)
带有1输入参数:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
返回:
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | 7 | -- !!
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | | 7 -- !!
返回:
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | 7 | -- !!
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | | 7 -- !!
手册上有
由于您必须在列定义列表中拼出所有列(预定义的crosstabN()
变体除外),通常在值
表达式中提供一个短列表更有效,如所示:
$$VALUES ('Active'::text), ('Inactive')$$)
或(不在手册中):
交叉表(文本,文本)
输出具有不同数据类型的列,只要值列的文本表示形式是目标类型的有效输入。这样,您可能会有不同类型的属性,并为各自的属性输出文本
、日期
、数值
等。本文末尾有一个代码示例- -还演示了提到的“额外列”
psql中的
\crosstabview
Postgres9.6将此元命令添加到其默认交互终端。您可以运行将用作第一个crosstab()
参数的查询,并将其提供给\crosstabview
(立即或在下一步中)。比如:
与上面的结果类似,但它只是客户端的一个表示特性。输入行的处理方式稍有不同,因此不需要排序依据。该页底部有更多的代码示例
Daniel Vérité(psql特性的作者)在dba.SE上的相关回答:
这本书已经过时了
- 函数
的变体已过时。忽略第二个交叉表(文本,整数)
参数。我引述:整数
交叉表(文本sql,int N)
的过时版本。参数交叉表(文本)
现在被忽略, 因为值列的数量始终由调用查询确定N
- 不必要的铸造和重命名
- 如果一行没有所有属性,则失败。请参阅上面带有两个输入参数的安全变量,以正确处理缺少的属性
在ORDER BY
crosstab()的单参数形式中是必需的 实际上,SQL查询应该始终指定
,以确保 输入行的顺序是否正确顺序为1,2
CREATE TEMP TABLE t (
section text
, status text
, ct integer -- don't use "count" as column name.
);
INSERT INTO t VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7);
SELECT section,
(obj ->> 'Active')::int AS active,
(obj ->> 'Inactive')::int AS inactive
FROM (SELECT section, json_object_agg(status,ct) AS obj
FROM t
GROUP BY section
)X
交叉表
功能在tablefunc
扩展下可用。您必须为数据库创建一次此扩展
创建扩展名tablefunc
您可以使用以下代码使用交叉表创建透视表:
创建表测试\u交叉表(节文本,
状态文本,
计数(数字)
插入测试交叉表值('A','Active',1)
,('A','Inactive',2)
,('B','Active',4)
,('B','Inactive',5)
从交叉表中选择*(
选择部分
,状态
,计数
来自测试\u交叉表'
)作为ctab(“部分”文本,“活动”数字,“非活动”数字)
您缺少from子句,否则这是正确的。在我的系统上,解释计划大不相同——交叉表函数的成本为22.5,而左连接方法的成本约为其4倍,成本为91.38。它还产生大约两倍于其他连接类型的物理读取和执行哈希连接,这与其他连接类型相比可能非常昂贵。我已经对另一个答案投了赞成票,但是你的评论值得保留,所以我不会删除这个。如果你在交叉表查询中使用参数,你必须正确地转义它。示例:(从上面)假设您只想要活动的:选择。。。从交叉表('select section::text,status,count::text FROM t,其中status='active',2)作为。。。(注意双引号)。如果用户在运行时传递参数(例如作为函数参数),您可以说:SELECT。。。从交叉表('select section::text,status,count::text FROM t,其中status='''| | | |''',2)作为。。。(这里有三个引号!)。在BIRT中,这也适用于?占位符。有人能解释一下tablefunc模块中的交叉表函数为这个答案添加了什么吗?这个答案既可以完成手头的工作,而且在我看来更容易理解?@JohnBarça:这样一个简单的例子可以很容易地用case语句解决。然而,这种情况得到了解决
CREATE TEMP TABLE t (
section text
, status text
, ct integer -- don't use "count" as column name.
);
INSERT INTO t VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7);
SELECT section,
(obj ->> 'Active')::int AS active,
(obj ->> 'Inactive')::int AS inactive
FROM (SELECT section, json_object_agg(status,ct) AS obj
FROM t
GROUP BY section
)X
create table test_Crosstab( section text,
<br/>status text,
<br/>count numeric)
<br/>insert into test_Crosstab values ( 'A','Active',1)
<br/>,( 'A','Inactive',2)
<br/>,( 'B','Active',4)
<br/>,( 'B','Inactive',5)
select * from crosstab(
<br/>'select section
<br/>,status
<br/>,count
<br/>from test_crosstab'
<br/>)as ctab ("Section" text,"Active" numeric,"Inactive" numeric)