如何在列定义列表中使用动态名称?

问题描述 投票:0回答:1

我查询 Postgres 数据库以获取过去 4 年的统计数据。
但是,我无法找出正确的语法来用函数(列定义列表)替换查询的

AS
部分中的硬编码日期。

说:

date_part('year',current_date)-1
而不是
"2012"

SELECT * FROM crosstab('
SELECT client,date_part (''year'',date) as SalesDate
       ,Sum(total)::integer AS Synthese
FROM statistic
WHERE date_part(''year'',date)>date_part(''year'',current_date)-5
AND date_part(''year'',date)<date_part(''year'',current_date)
GROUP BY client,SalesDate
ORDER BY 1,2',
$$VALUES 
(date_part('year',current_date)-4),
(date_part('year',current_date)-3),
(date_part('year',current_date)-2),
(date_part('year',current_date)-1)$$)
AS ( client text, "2009" text, "2010" text , "2011" text, "2012" text);
sql postgresql pivot-table plpgsql
1个回答
2
投票

回答

SQL 的一个原则:您可以动态提供 ,但标识符是静态的。

外部调用是一个基本的SQL语句,列定义列表由标识符组成,而不是值。 (这就是为什么您被迫双引号以数字开头的非法标识符。)因此,您不能在这个地方使用函数调用。只是不可能。

可能的解决方法

有一些棘手的方法可以解决这个问题.. 您可以创建一个返回多态复合类型的 plpgsql 函数,并传入一个定义明确的复合类型的参数,该参数还带有列名称。但这是非常先进的东西。为此,您需要跟上 plpgsql 的步伐。

考虑我在此相关问题下的全面回答:
重构 PL/pgSQL 函数以返回各种 SELECT 查询的输出
答案的后半部分是给你的。

由于您需要一个定义明确的复合类型,因此您必须在以这种方式调用函数之前创建一个类型。或者只是创建一个临时表(自动提供类型)。您可以使用

DO
语句自动执行此操作,该语句使用动态 SQL 从当前日期派生列名称...我从未说过这很简单,但这是可能的。

基础查询

同时,您的

crosstab()
查询可以得到改进:

SELECT * FROM crosstab(
    $$
    SELECT client
          ,date_part ('year', date) AS salesdate
          ,sum(total)::int AS synthese
    FROM   statistic
    WHERE  date >= date_trunc('year', now()) - interval '5y'
    AND    date <  date_trunc('year', now())
    GROUP  BY 1,2
    ORDER  BY 1,2
    $$

    ,$$VALUES 
         (date_part('year', now()) - 4)
        ,(date_part('year', now()) - 3)
        ,(date_part('year', now()) - 2)
        ,(date_part('year', now()) - 1)
    $$
    )
AS  (client text
     ,"2009" text
     ,"2010" text
     ,"2011" text
     ,"2012" text);

剩下的就是品味和风格的问题。

© www.soinside.com 2019 - 2024. All rights reserved.