Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL交叉表查询_Sql_Postgresql_Pivot_Case_Crosstab - Fatal编程技术网

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

有人知道如何在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 (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
      ,以确保 输入行的顺序是否正确


    带有JSON聚合的解决方案:

    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)