【问题标题】:Unable to use Common Table Expressions in Postgres Crosstab Query无法在 Postgres 交叉表查询中使用公用表表达式
【发布时间】:2016-08-30 20:36:15
【问题描述】:

我正在尝试使用 Postgres 的 tablefunc 扩展的 CROSSTAB 函数对某些数据执行透视操作。数据需要先进行一些转换,我在一些常用的表表达式中进行。

但是,CROSSTAB 似乎看不到这些表达式的结果。

例如,从 临时表 中获取数据的查询可以正常工作:

CREATE TEMPORARY TABLE
  temporary_table
    (name, category, category_value)
ON COMMIT DROP
AS (
  VALUES
    ('A',  'foo',    1             ),
    ('A',  'bar',    2             ),
    ('B',  'foo',    3             ),
    ('B',  'bar',    4             )
);

SELECT * FROM
  CROSSTAB(
    'SELECT * FROM temporary_table',
    $$
      VALUES
        ('foo'),
        ('bar')
    $$
  ) AS (
    name TEXT,
    foo  INT,
    bar  INT
  );

并且,正如预期的那样,产生以下输出:

name | foo     | bar
text | integer | integer
---- | ------- | -------
A    |       1 |       2
B    |       3 |       4

但是同样的查询,这次使用通用表表达式没有运行:

WITH
  common_table
    (name, category, category_value)
AS (
  VALUES
    ('A',  'foo',    1             ),
    ('A',  'bar',    2             ),
    ('B',  'foo',    3             ),
    ('B',  'bar',    4             )
)
SELECT * FROM
  CROSSTAB(
    'SELECT * FROM common_table',
    $$
      VALUES
        ('foo'),
        ('bar')
    $$
  ) AS (
    name TEXT,
    foo  INT,
    bar  INT
  )

并产生以下错误:

ERROR:  relation "common_table" does not exist
LINE 1: SELECT * FROM common_table
                      ^
QUERY:  SELECT * FROM common_table

********** Error **********

ERROR: relation "common_table" does not exist
SQL state: 42P01

我认为这意味着文本查询 (SELECT * FROM common_table) 在某种不同的上下文中运行?


注意:必须启用tablefunc 扩展才能使CROSSTAB 可用:

CREATE EXTENSION IF NOT EXISTS tablefunc;

【问题讨论】:

    标签: sql postgresql pivot temp-tables crosstab


    【解决方案1】:

    您需要做的就是将您的CTE 作为crosstab(text, text) 函数的第一个参数移动到字符串中,就像您对select 语句所做的那样。它将被正确解析和执行。这是因为您提供了在第一个参数中生成源集的完整 SQL 语句。

    您需要在字符串内加倍引号或使用美元引用$$,就像您对第二个参数所做的那样,我在下面做了:

    SELECT * FROM
      CROSSTAB(
        $$
        WITH common_table(name, category, category_value) AS (
          VALUES
            ('A',  'foo',    1             ),
            ('A',  'bar',    2             ),
            ('B',  'foo',    3             ),
            ('B',  'bar',    4             )
        )
        SELECT * FROM common_table $$,
        $$
          VALUES
            ('foo'),
            ('bar')
        $$
      ) AS (
        name TEXT,
        foo  INT,
        bar  INT
      );
    

    结果

     name | foo | bar
    ------+-----+-----
     A    |   1 |   2
     B    |   3 |   4
    

    【讨论】:

    • 对一些替代方法有什么想法吗?我在一些查询中使用了一系列 CTE,在 CROSSTAB 中使用 cte 或 temp 表的能力会很棒。
    • 您可以根据需要使用尽可能多的 CTE 作为交叉表的来源。最后,它们都是一个声明的一部分。如果您需要进一步的帮助并发现您的情况有所不同,请务必寻找解决方案。如果运气不好,请在 StackOverflow 上发布一个单独的问题 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    • 2019-05-25
    • 1970-01-01
    相关资源
    最近更新 更多