过滤对crosstab()查询结果的意外影响

时间:2019-07-25 19:40:48

标签: sql postgresql sql-order-by distinct crosstab

我有一个crosstab()查询,如下所示:

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 = val1
  ORDER  BY row_name ASC',
 'SELECT category_name FROM category_name WHERE field = certain_value'
) AS ct(row_name text, extra1 text, extra2 text, ...)

简化的示例,实际查询确实很复杂,并且包含重要信息。上面的查询用table.extra1 = val1过滤后返回 N 个结果行。

当我如下更改查询时:

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, ...) --> more values
  ORDER  BY row_name ASC',
 'SELECT category_name FROM category_name WHERE field = certain_value'
) AS ct(row_name text, extra1 text, extra2 text, ...)
WHERE extra1 = val1; --> condition on the result

添加了更多可能的值table.extra1 IN (val1, ...)和最终条件WHERE extra1 = val1。现在我得到的行比原始行少了。更糟糕的是,如果我向IN (val1, ...)添加更多值,则会得到更少行。为什么会这样?

1 个答案:

答案 0 :(得分:1)

extra1, extra2, ...是交叉表术语中的“额外的列”
The manual for the tablefunc module解释了规则:

  

它也可能有一个或多个“额外”列。 row_name列必须   成为第一。类别和value列必须是最后两列,   以该顺序。 row_namecategory之间的所有列均被处理   作为“额外”。 所有具有相同row_name值的行的“额外”列均应相同。

再往下走:

  

输出row_name列以及所有“额外”列都是从该组的第一行中复制的。。

我大胆强调关键部分。

您只能按row_name进行排序:

ORDER  BY row_name ASC

在第一个示例中使用以下内容进行过滤并不重要:

WHERE ... t.extra1 = 'val1'  -- single quotes by me

所有输入行总有extra1 = 'val1'。但这在第二个示例中很重要,您可以在其中进行过滤:

WHERE ... t.extra1 IN('val1', ...) --> More values

现在,额外的列extra1违反了上面的第一个粗体要求。虽然第一个输入查询的排序顺序是不确定的,但是“额外”列extra1的结果值是任意选择的。 extra1的可能值越多,最终带有'val1'的行越少:这就是您所观察到的。

您仍然可以使用它:对至少有一个extra1 = 'val1'报告row_name,将ORDER BY更改为:

ORDER  BY row_name, (extra1 <> 'val1')

在顶部排序“ val1”。该boolean表达式的说明(带有更多链接):

在排序顺序不确定时,仍然可以任意选择其他“额外”列。

交叉表基础知识: