来自 SELECT 中另一个列值的动态列别名

Dynamic column alias from another column value in SELECT

我想知道是否有一种方法,在 Postgres 的 SELECT 语句中,用同一数据集中另一列的值作为别名。

鉴于此 table:

id 关键 价值
1 一个 d
2 一个 e
3 b f

这将是结果:

id 一个 b
1 d
2 e
3 f

对于每个实例,列的名称由 key 的值确定,而值是列 value 的值,不知道将提供什么样的值key.

这是一个可能的(无效的)查询:

SELECT "id", "value" AS "t"."key" FROM testTable as t;

在 Postgres 中实现数据透视的一种方法是使用 CASE :

select id,
  max(case when (key='a') then value else NULL end) as a,
  max(case when (key='b') then value else NULL end) as b
  FROM TestTable
 group by id
 order by id;

似乎无法动态创建列别名而不从一开始就知道这些值。正如许多人评论的那样,实现这种“table 重新映射”的唯一方法是使用 crosstab 函数。

交叉表函数汇总

这个函数有两个参数:

  • 第一个是 SQL 语句,必须 return 3 列:
    • 第一列包含标识每个实例的值,必须对其进行分组才能获得最终结果。
    • 第二列包含在最终数据透视表中用作类别的值table:每个值将创建一个单独的列。
    • 第三列包含用于编译形成的新列的值:对于每个类别,此列具有原始 table 中具有类别值的实例的值。
  • 第二个参数不是必需的,它是一个 SQL 语句,其中 return 是函数应该用作类别的不同值。

例子

在上面的示例中,我们必须将查询传递给交叉表:

  • Returns 作为第一列每个最终实例的标识符(在本例中 id
  • 第二列用作类别的值(key 中的所有值)
  • 第三列用于填充类别的值(value 中的所有值)

所以最终的查询应该是:

select * from crosstab(
    'select "id", "key", "value" from testTable order by 1, 2;',
    'select distinct "key" from testTable order by 1;'
) as result ("id" int8, "a" text, "b" text);

由于交叉表函数需要最终数据透视表的列定义 table,因此无法动态确定列别名。

使用客户端动态推断列名称

使用 PostgreSQL 客户端的一种可能方法是启动我们作为参数传递给交叉表的第二个查询,以检索最终列,然后推断最终交叉表查询。

举个例子,用伪javascript:

const client;

const aliases = client.query(`select distinct "key" from testTable order by 1;`);

const finalTable = client.query(`select * from crosstab(
    'select "id", "key", "value" from testTable order by 1, 2;',
    'select distinct "key" from testTable order by 1;'
) as result ("id" int8, ${aliases.map(v => v + ' data_type').join(',')});`)

有用的文章

https://learnsql.com/blog/creating-pivot-tables-in-postgresql-using-the-crosstab-function/