PostgreSQL交叉表问题/“返回和SQL元组描述不兼容”

时间:2019-05-12 20:55:40

标签: postgresql

下午好,我正在使用POSTGRESql 9.2版,并且试图使用交叉表函数来转置表上的两列,以便以后可以将其连接到其他SELECT查询中。

我已经安装了tablefunc扩展名。

但是,我不断收到此“返回和SQL元组描述不兼容”错误,这似乎是由于类型转换造成的。
我不需要它们是特定类型。

我原来的SELECT查询是这个

SELECT inventoryid, ttype, tamount

FROM inventorytesting

哪个给我以下结果:

inventoryid           ttype    tamount
2451530088940460        7       0.2
2451530088940460        2       0.5
2451530088940460        8       0.1
2451530088940460        1       15.7
8751530077940461        7       0.7
8751530077940461        2       0.2
8751530077940461        8       1.1
8751530077940461        1       19.2

我的目标是像这样:

inventoryid          7      2       8       1
8751530077940461    0.7    0.2     1.1     19.2
2451530088940460    0.2    0.5     0.1     15.7

“ ttype”字段具有49个固定的不同值,例如“ 7”,“ 2”,“ 8”,“ 1”。
“ tamount”字段根据“ inventoryid”字段的不同而有所不同,但即使其值为零,也始终有49个。它永远不会为“ null”。

我尝试了一些可以在互联网上找到的变化,总结如下:

SELECT *

FROM    crosstab (

    $$SELECT inventoryid, ttype, tamount
    FROM inventorytesting
    WHERE inventoryid = '2451530088940460'
    ORDER BY inventoryid, ttype$$
) 
AS ct("inventoryid" text,"ttype" smallint,"tamount" numeric) 

库存测试表上的字段类型为

select column_name, data_type from information_schema.columns
where table_name = 'inventorytesting'  

结果:

column_name    data_type
id             bigint
ttype          smallint
tamount        numeric
tunit          text
tlessthan      smallint
plantid        text
sessiontime    bigint
deleted        smallint
inventoryid    text
docdata        text
docname        text
labid          bigint

任何指针都很棒。

2 个答案:

答案 0 :(得分:0)

demo:db<>fiddle

结果表定义必须包含您期望的表结构-透视表-而不是给定表的结构:

SELECT *
FROM crosstab(
    $$SELECT inventoryid, ttype, tamount
    FROM inventorytesting
    WHERE inventoryid = '2451530088940460'
    ORDER BY inventoryid, ttype$$
) 
AS ct("inventoryid" text,"type1" numeric,"type2" numeric,"type7" numeric,"type8" numeric) 

另外,不需要使用crosstab函数。您只需使用标准的CASE函数即可实现枢纽:

SELECT
    inventoryid,
    SUM(CASE WHEN ttype = 1 THEN tamount END) AS type1,
    SUM(CASE WHEN ttype = 2 THEN tamount END) AS type2,
    SUM(CASE WHEN ttype = 7 THEN tamount END) AS type7,
    SUM(CASE WHEN ttype = 8 THEN tamount END) AS type8
FROM
    inventorytesting
GROUP BY 1

如果您使用的是9.4或更高版本,则可以使用Postgres专用的FILTER子句:

SELECT
    inventoryid,
    SUM(tamount) FILTER (WHERE ttype = 1) AS type1,
    SUM(tamount) FILTER (WHERE ttype = 2) AS type2,
    SUM(tamount) FILTER (WHERE ttype = 7) AS type7,
    SUM(tamount) FILTER (WHERE ttype = 8) AS type8
FROM
    inventorytesting
GROUP BY 1

demo:db<>fiddle

答案 1 :(得分:0)

使用crosstab,您可以定义实际结果表(基本上是数据透视表的结果)。输入查询定义三列,然后将其处理为:

  1. 将列分组会产生实际的行
  2. 枢轴列
  3. 枢轴列的值

对于您而言,crosstab因此需要定义为:

ct(
    "inventoryid" text,
    "tamount_1" numeric,
    "tamount_2" numeric,
    "tamount_3" numeric,
    ...
)

然后,列标题将按照内部查询的ttype所定义的顺序与列ORDER BY的某个值相关联。

crosstab的问题是缺少ttype的值(例如,为4返回了一些值,但没有为3返回),结果列将为{{1 }},12,...,其中缺少4。在这里,您必须确保(如果需要一致的输出)内部查询至少返回3行(例如,通过NULL)。