PostgreSQL 动态列数结果
Posted
技术标签:
【中文标题】PostgreSQL 动态列数结果【英文标题】:PostgreSQL Dynamic Number of Column Result 【发布时间】:2018-06-27 06:14:18 【问题描述】:我有这样的桌子
id | firstname | lastname | object | total
--------------------------------------------
1 | John | Doe | obj1 | 2
2 | Mark | Dew | obj3 | 1
3 | Steve | Foey | obj1 | 4
4 | John | Doe | obj4 | 2
5 | Mark | Dew | obj2 | 5
6 | Steve | Foey | obj3 | 1
-- | -- | -- | -- | --
20 | Mark | Dew | obj10 | 1
并期待这样的结果:
id | name | obj1 | obj2 | obj3 | obj4 | .. | obj10 |
------------------------------------------------------------
1 | John Doe | 2 | 0 | 0 | 2 | .. | 0 |
2 | Mark Dew | 0 | 5 | 1 | 0 | .. | 1 |
3 | Steve Foey | 4 | 0 | 1 | 0 | .. | 0 |
我的问题的最佳解决方案(查询)是什么?我是 sql 新手。请帮我。谢谢。
【问题讨论】:
多次出现的人的价值观呢?它们应该相加吗?还是您想要每个 id 一行,而不是每人一行? @a_horse_with_no_name 是的。它们应该相加。 Sabari 的回答对我有用。但我仍然对交叉表感到好奇(仍然不起作用)。 在这种情况下:您希望在结果中看到哪个id
值。 Sabari 的答案包括 group by 中的 id
,因此,如果一个人对相同的 object
具有相同的 id
,您只会看到总数(您的示例数据似乎并非如此)。如果您的 id=42 和 id=45 具有相同的对象,例如约翰·多?那你想看什么?
我删除了 id
和 concat firstname
和 lastname
。我还没有尝试过与具有相同object
的人发生多次。
【参考方案1】:
这是一种新的旋转方式,希望能有所帮助
SELECT FIRSTNAME ,LASTNAME , CASE WHEN POSITION ( 'OBJ1') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ1' IN STR )+5 ,1) :: INT END AS OBJ1,
CASE WHEN POSITION ( 'OBJ2') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ2' IN STR )+5 ,1) :: INT END AS OBJ2,
CASE WHEN POSITION ( 'OBJ3') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ3' IN STR )+5 ,1) :: INT END AS OBJ3,
CASE WHEN POSITION ( 'OBJ4') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ4' IN STR )+5 ,1) :: INT END AS OBJ4,
CASE WHEN POSITION ( 'OBJ5') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ5' IN STR )+5 ,1) :: INT END AS OBJ5,
CASE WHEN POSITION ( 'OBJ6') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ6' IN STR )+5 ,1) :: INT END AS OBJ6,
CASE WHEN POSITION ( 'OBJ7') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ7' IN STR )+5 ,1) :: INT END AS OBJ7,
CASE WHEN POSITION ( 'OBJ8') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ8' IN STR )+5 ,1) :: INT END AS OBJ8,
CASE WHEN POSITION ( 'OBJ9') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ9' IN STR )+5 ,1) :: INT END AS OBJ9,
CASE WHEN POSITION ( 'OBJ10') IN STR ) = 0 THEN NULL ELSE SUBSTR( STR ,POSITION ('OBJ10' IN STR )+6 ,1) :: INT END AS OBJ10
FROM
( SELECT ID, FIRSTNAME ,LASTNAME , STRING_AGG(OBJECT :: TEXT || '$' || TOTAL ::TEXT ,',') AS
FROM YOURTABLE
WHERE OBJECT
GROUP BY ID, FIRSTNAME ,LASTNAME )A
【讨论】:
【参考方案2】:在 postgresql 中,当与 filter 子句一起使用时,pivot 非常简单。
选择 名, 姓, 合并(总和(总)过滤器(其中对象='obj1'),0)作为obj1, 合并(总和(总)过滤器(其中对象='obj2'),0)作为obj2, 合并(总和(总)过滤器(其中对象='obj3'),0)作为obj3, 合并(总和(总)过滤器(其中对象='obj4'),0)作为obj4, 合并(总和(总)过滤器(其中对象='obj5'),0)作为obj5, 合并(总和(总)过滤器(其中对象='obj6'),0)作为obj6, 合并(总和(总)过滤器(其中对象='obj7'),0)作为obj7, 合并(总和(总)过滤器(其中对象='obj8'),0)作为obj8, 合并(总和(总)过滤器(其中对象='obj9'),0)作为obj9, 合并(总和(总)过滤器(其中对象='obj10'),0)作为obj10 从表 1 按名字、姓氏分组【讨论】:
它的工作!但是如何用0
替换null
值?
我已经编辑了答案并添加了 coalesce()。这将用 0@JimJohnson 替换空值
但是.. 我有一个问题。如果我用新的object
添加新的人怎么办?让我们说'obj100'。如何在不添加where object=obj100
的情况下使该查询工作?
我认为如果您需要“obj100”作为列之一,那么您必须添加“where object=obj100”。否则,您可以将 json 类型用作列,将数据用作 (key,value) = (obj,total) .i.e. 'obj1': 5, 'obj2': 6,...'obj100': 8 for each人。以上是关于PostgreSQL 动态列数结果的主要内容,如果未能解决你的问题,请参考以下文章