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

Posted

技术标签:

【中文标题】过滤对 crosstab() 查询结果的意外影响【英文标题】:Unexpected effect of filtering on result from crosstab() query 【发布时间】:2019-07-25 19:40:48 【问题描述】:

我有一个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。现在我得到 less 行比原来的行。更糟糕的是,如果我向IN (val1, ...) 添加更多值,我会得到更少 行。这是为什么呢?

【问题讨论】:

【参考方案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”的行就越少:这就是您观察到的。

您仍然可以使其工作:为每个至少具有其中一个的 row_name 报告 extra1 = 'val1',请将 ORDER BY 更改为:

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

将“val1”排在最前面。 boolean 表达式的解释(带有更多链接):

PostgreSQL: Grouping then filtering table, with condition for nonexistence

其他“额外”列仍然是任意选择的,而排序顺序不确定。

交叉表基础知识:

PostgreSQL Crosstab Query Postgresql crosstab query with multiple "row name" columns

【讨论】:

我仍然有多个值的一些问题。例如,如果我用val2 过滤extra1,我会得到100 个结果。但是,如果我使用...t.extra1 IN('val1', 'val2')...(extra1 &lt;&gt; 'val1'), (extra1 &lt;&gt; 'val2'),对于那些在80 附近有extra1 和'val2' 的人,我会得到不同的结果大小。 在这种情况下,您可以ORDER BY row_name, (extra1 &lt;&gt; 'val2') 在任何可用的地方获取“val2”。 (从列表中删除 (extra1 &lt;&gt; 'val1')。) 问题是extra1 可以从允许值列表['value1', 'value2', 'value3'...'valueN'] 中获得一个值。正常情况是允许过滤多个值['value1', 'value2'] 而不仅仅是一个。是否仍然可以使用&lt;&gt; 运算符来实现它? 请提出一个包含所有必要细节的新问题。评论不是地方...(您可以随时链接到这个以获得上下文,并在此处的 cmets 中放回链接以引起我的注意。) 你是对的:)。这里出现了一个新问题***.com/questions/57221777/…

以上是关于过滤对 crosstab() 查询结果的意外影响的主要内容,如果未能解决你的问题,请参考以下文章

MySQL select_expr 意外影响查询执行计划

排序查询 Crosstab Postgres

MS Access CrossTab 查询 - 跨 3 个表

将 Access Crosstab/PIVOT 查询转换为 T-SQL

如何在 django 中过滤对另一个结果的查询?

BI Answers/OBIEE- 在不影响行结果的情况下在列上创建过滤器