无法在Postgres交叉表查询中使用公用表表达式

时间:2016-08-30 20:36:16

标签: sql postgresql pivot temp-tables crosstab

我正在尝试使用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;

1 个答案:

答案 0 :(得分:5)

您需要做的就是将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