筛选对具有多个值的crosstab()查询的结果产生意外影响

时间:2019-07-26 14:09:02

标签: sql postgresql pivot-table crosstab

我有一个crosstab()查询,与上一个问题类似:
Unexpected effect of filtering on result from crosstab() query

常见的情况是使用多个值extra1过滤extra1 IN(value1, value2...)字段。对于extra1过滤器中包含的每个值,我都添加了一个类似于(extra1 <> valueN)的排序表达式,如上面提到的帖子所示。结果查询如下:

SELECT *
FROM crosstab(
 'SELECT row_name, extra1, extra2..., another_table.category, value
  FROM   table t
  JOIN   another_table ON t.field_id = another_table.field_id
  WHERE  t.field = certain_value AND t.extra1 IN (val1, val2, ...) --> more values
  ORDER  BY row_name ASC, (extra1 <> val1), (extra1 <> val2)', ... --> more ordering expressions
 'SELECT category_name FROM category_name WHERE field = certain_value'
) AS ct(extra1, extra2...)
WHERE extra1 = val1; --> condition on the result

排序表达式extra1中包含的value1的第一个值将得到正确的结果行。但是,下列value2value3 ...的结果数错误,导致每个结果行较少。为什么会这样?

更新:

将此作为我们的源表(table t):

+----------+--------+--------+------------------------+-------+
| row_name | Extra1 | Extra2 | another_table.category | value |
+----------+--------+--------+------------------------+-------+
| Name1    | 10     | A      | 1                      | 100   |
| Name2    | 11     | B      | 2                      | 200   |
| Name3    | 12     | C      | 3                      | 150   |
| Name2    | 11     | B      | 3                      | 150   |
| Name3    | 12     | C      | 2                      | 150   |
| Name1    | 10     | A      | 2                      | 100   |
| Name3    | 12     | C      | 1                      | 120   |
+----------+--------+--------+------------------------+-------+

这是我们的类别表:

+-------------+--------+
| category_id | value  |
+-------------+--------+
| 1           | Cat1   |
| 2           | Cat2   |
| 3           | Cat3   |
+-------------+--------+

使用CROSSTAB,其想法是得到一个这样的表:

+----------+--------+--------+------+------+------+
| row_name | Extra1 | Extra2 | cat1 | cat2 | cat3 |
+----------+--------+--------+------+------+------+
| Name1    | 10     | A      | 100  | 100  |      |
| Name2    | 11     | B      |      | 200  | 150  |
| Name3    | 12     | C      | 120  | 150  | 150  |
+----------+--------+--------+------+------+------+

想法是能够过滤结果表,以便我得到Extra1列的值为1011的结果,如下所示:

+----------+--------+--------+------+------+------+
| row_name | Extra1 | Extra2 | cat1 | cat2 | cat3 |
+----------+--------+--------+------+------+------+
| Name1    | 10     | A      | 100  | 100  |      |
| Name2    | 11     | B      |      | 200  | 150  |
+----------+--------+--------+------+------+------+

问题在于,在我的查询中,对于Extra1,结果为10,对于Extra1,结果为11,结果大小不同。使用(Extra1 <> 10),我可以在Extra1上获得该值的正确结果大小,但不能以11作为值。

这是一个小提琴,更详细地说明了这个问题:

https://dbfiddle.uk/?rdbms=postgres_11&fiddle=5c401f7512d52405923374c75cb7ff04

1 个答案:

答案 0 :(得分:1)

所有“额外”列均从该组的第一行中复制(如my previous answer中所述)

使用以下方法进行过滤:

.... WHERE extra1 = 'val1';

...在同一列上添加更多ORDER BY表达式是没有意义的。只有其源组中至少有一个extra1 = 'val1'的行才能保留。

从您的各种评论中,我想您可能希望查看extra所有个不同的现有值-在WHERE子句中过滤的集合中-对于同一{ {1}}。如果是这样,请在之前进行汇总。喜欢:

unixdatetime

此外:以下有关第二功能参数的答案也适用于您的情况:

我将相应地演示静态第二个参数查询的替代方法。在进行此操作时,您根本不需要加入SELECT * FROM crosstab( $$ SELECT unixdatetime, x.extras, c.name, s.value FROM ( SELECT unixdatetime, array_agg(extra) AS extras FROM ( SELECT DISTINCT unixdatetime, extra FROM source_table s WHERE extra IN (1, 2) -- condition moves here ORDER BY unixdatetime, extra ) sub GROUP BY 1 ) x JOIN source_table s USING (unixdatetime) JOIN category_table c ON c.id = s.gausesummaryid ORDER BY 1 $$ , $$SELECT unnest('{trace1,trace2,trace3,trace4}'::text[])$$ ) AS final_result (unixdatetime int , extras int[] , trace1 numeric , trace2 numeric , trace3 numeric , trace4 numeric); 。一样,速度越来越快了,

category_table

db <>小提琴here -在小提琴的底部添加了我的查询。