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

bos*_*cko 7 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
  );
Run Code Online (Sandbox Code Playgroud)

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

name | foo     | bar
text | integer | integer
---- | ------- | -------
A    |       1 |       2
B    |       3 |       4
Run Code Online (Sandbox Code Playgroud)

但是相同的查询,这次使用公用表表达式不会运行:

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
  )
Run Code Online (Sandbox Code Playgroud)

并产生以下错误:

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
Run Code Online (Sandbox Code Playgroud)

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


注:tablefunc扩展名必须为启用CROSSTAB可用:

CREATE EXTENSION IF NOT EXISTS tablefunc;
Run Code Online (Sandbox Code Playgroud)

Kam*_*ski 6

您需要做的就是将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
  );
Run Code Online (Sandbox Code Playgroud)

结果

 name | foo | bar
------+-----+-----
 A    |   1 |   2
 B    |   3 |   4
Run Code Online (Sandbox Code Playgroud)

  • 关于一些替代方法的任何想法?我在一些查询中使用了一系列 CTE,在 CROSSTAB 中使用 cte 或临时表的能力会很棒。 (2认同)