【问题标题】:Dynamic column alias from another column value in SELECTSELECT 中另一个列值的动态列别名
【发布时间】:2021-10-05 07:17:16
【问题描述】:

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

鉴于此表:

id key value
1 a d
2 a e
3 b f

结果如下:

id a b
1 d NULL
2 e NULL
3 NULL f

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

这是一个可能的(不工作的)查询:

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

【问题讨论】:

  • 你想要的是一个 PIVOT,我认为它在 postgres 中被称为交叉表
  • 这只能使用动态 SQL。

标签: sql postgresql select crosstab


【解决方案1】:

在 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;

【讨论】:

  • 感谢您的回复...也许我不够清楚:如果我从一开始就知道列值,您的解决方案就可以工作...但是如果我不知道它就行不通.. .
  • 或者:max(value) filter (where key = 'a')
【解决方案2】:

似乎没有办法在不知道从一开始就知道值的情况下动态创建列别名。正如许多人评论的那样,实现这种“表重新映射”的唯一方法是使用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/

【讨论】:

    猜你喜欢
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    相关资源
    最近更新 更多