似乎没有办法在不知道从一开始就知道值的情况下动态创建列别名。正如许多人评论的那样,实现这种“表重新映射”的唯一方法是使用crosstab 函数。
交叉表函数总结
这个函数有 2 个参数:
- 第一个是必须返回 3 列的 SQL 语句:
- 第一列包含标识每个实例的值,必须对其进行分组才能获得最终结果。
- 第二列包含在最终数据透视表中用作类别的值:每个值将创建一个单独的列。
- 第三列包含用于编译形成的新列的值:对于每个类别,此列具有原始表中具有类别值的实例的值。
- 第二个参数不是强制性的,它是一个 SQL 语句,它返回函数应用作类别的不同值。
示例
在上面的示例中,我们必须向交叉表传递一个查询:
- 作为第一列返回每个最终实例的标识符(在本例中为
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);
由于交叉表函数需要为最终数据透视表定义列,因此无法动态确定列别名。
使用客户端动态推断列名
使用 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/