如何通过利用PostgreSQL中的Join子句将交叉表与动态的列数一起使用

时间:2020-07-08 10:33:46

标签: sql postgresql postgres-crosstab

我正在尝试使用 Crosstab 以垂直方式获取表数据。更精确地说,我需要同时按前缀和后缀分组并获取汇总。在这种情况下,我应该加入2个表并获取唯一前缀和后缀的名称。列数可能会有所不同,具体取决于 income_account_setting 表的值。就我而言,我有20多个不同的名称,这意味着我应该具有code_account和20列。我尝试在 Crosstab 的帮助下进行操作,但是在Internet上给出了固定列数的示例

我的桌子: main_client_profit

id     |  code_account      | summa       | prefix     | postfix  |   oper_month   |
------------------------------------------------------------------------------------
1      |  04315187          | 72871232.77 | 45233      |  222     |  2020-04       |
2      |  00524154          | 89753426.58 | 45294      |  100     |  2020-01       |
3      |  02115187          | 23224345.89 | 45249      |  204     |  2020-03       |
4      |  00388996          | 119030.87   | 45294      |  246     |  2020-05       |
5      |  04222959          | 105000.00   | 45233      |  222     |  2020-04       |
6      |  04315187          | 92871232.77 | 45233      |  222     |  2020-04       |
1      |  04222959          | 1020458.40  | 45233      |  421     |  2020-01       |

收入帐户设置

id    |  prefix    |  postfix   |  name          |
-------------------------------------------------------------------------------------
1     |  45233     |  222       |   A            |
1     |  45294     |  100       |   B            |
1     |  45249     |  204       |   C            |
1     |  45294     |  246       |   E            |
1     |  45233     |  421       |   F            |

我需要取得的结果

------------------------------------------------------------------------------------
code_account      | A         | B           |  C          |  D   |    E  |
----------------------------------------------------------
04315187          | 165742465 | 0           |  0          | 0    |   0   |
00524154          |           | 89753426.58 |  0          | 0    |   0   |
02115187          |    0      |             | 23224345.89 | 0    |   0   |

and etc ....

到目前为止我尝试过的方法,但是没有用

SELECT *
FROM crosstab('SELECT m.code_account, a.name, evaluation_result 
        FROM main_client_profit m
             INNER JOIN income_account_setting a 
            ON m.prefix = a.prefix AND m.postfix = a.postfix
        GROUP BY CONCAT(m.prefix,m.postfix)
        ORDER BY 1,2') 
   AS final_result(code character varying(20),) 

在上面的代码中,我不知道在final_result中将什么写为列。

是否可以使用Crosstab来完成此任务?还是有其他方法可以实现?可以提供任何帮助。

2 个答案:

答案 0 :(得分:1)

我的观点是,crosstab()函数通常会使事情变得更加复杂,反而会有所帮助。而且,它不能克服以下限制:必须在运行语句之前 知道结果的所有列。

我会这样:

SELECT m.code_account,
       sum(m.summa) filter (where a.name = 'A') as "A",
       sum(m.summa) filter (where a.name = 'B') as "B",
       sum(m.summa) filter (where a.name = 'C') as "C",
       sum(m.summa) filter (where a.name = 'D') as "D",
       sum(m.summa) filter (where a.name = 'E') as "E"
FROM main_client_profit m
  LEFT JOIN income_account_setting a
         ON m.prefix = a.prefix 
        AND m.postfix = a.postfix
GROUP BY m.code_account
ORDER BY m.code_account

答案 1 :(得分:0)

您可以使用JSON打包/解压缩,但是您需要恢复正确的数据类型。

[这不是真正的动态,您仍然必须在列名列表中输入。因此可以通过动态SQL实现自动化]


WITH omg AS ( -- Pack into json
        SELECT m.code_account
        , json_object_agg(a.name, summa) AS zooi
        FROM main_client_profit m
        JOIN income_account_setting a
        ON m.prefix = a.prefix AND m.postfix = a.postfix
        GROUP BY m.code_account
        ORDER BY 1
        )
SELECT o.code_account -- And unpack it. Still need to cast to the wanted type
        , (o.zooi->>'A')::DECIMAL(10,2) AS A
        , (o.zooi->>'B')::DECIMAL(10,2) AS B
        , (o.zooi->>'C')::DECIMAL(10,2) AS C
        , (o.zooi->>'D')::DECIMAL(10,2) AS D
        , (o.zooi->>'E')::DECIMAL(10,2) AS E
        , (o.zooi->>'F')::DECIMAL(10,2) AS F
FROM omg o
ORDER BY 1
        ;