我想创建一个postgres的功能,建立设置的列它 返回飞行;总之,它应该采取一系列的钥匙,建立 一个列每关键,并回归创纪录的组成不管那套 列。简单地说,这里的代码:

CREATE OR REPLACE FUNCTION reports.get_activities_for_report() RETURNS int[] AS $F$
BEGIN
    RETURN ARRAY(SELECT activity_id FROM public.activity WHERE activity_id NOT IN (1, 2));
END;
$F$
LANGUAGE plpgsql
STABLE;

CREATE OR REPLACE FUNCTION reports.get_amount_of_time_query(format TEXT, _activity_id INTEGER) RETURNS TEXT AS $F$
DECLARE
    _label TEXT;
BEGIN
    SELECT label INTO _label FROM public.activity WHERE activity_id = _activity_id;
    IF _label IS NOT NULL THEN
        IF lower(format) = 'percentage' THEN
            RETURN $$TO_CHAR(100.0 *$$ ||
            $$ (SUM(CASE WHEN activity_id = $$ || _activity_id || $$ THEN EXTRACT(EPOCH FROM ended - started) END) /$$ ||
            $$ SUM(EXTRACT(EPOCH FROM ended - started))),$$ ||
            $$ '990.99 %') AS $$ || quote_ident(_label);
        ELSE
            RETURN $$SUM(CASE WHEN activity_id = $$ || _activity_id || $$ THEN ended - started END)$$ ||
            $$ AS $$ || quote_ident(_label);
        END IF;
    END IF;
END;
$F$
LANGUAGE plpgsql
STABLE;

CREATE OR REPLACE FUNCTION reports.build_activity_query(format TEXT, activities int[]) RETURNS TEXT AS $F$
DECLARE
    _activity_id INT;
    query TEXT;
    _activity_count INT;
BEGIN
    _activity_count := array_upper(activities, 1);
    query := $$SELECT agent_id, portal_user_id, SUM(ended - started) AS total$$;
    FOR i IN 1.._activity_count LOOP
        _activity_id := activities[i];

        query := query || ', ' || reports.get_amount_of_time_query(format, _activity_id);
    END LOOP;
    query := query || $$ FROM public.activity_log_final$$ ||
    $$ LEFT JOIN agent USING (agent_id)$$ ||
    $$ WHERE started::DATE BETWEEN actual_start_date AND actual_end_date$$ ||
    $$ GROUP BY agent_id, portal_user_id$$ ||
    $$ ORDER BY agent_id$$;
    RETURN query;
END;
$F$
LANGUAGE plpgsql
STABLE;

CREATE OR REPLACE FUNCTION reports.get_agent_activity_breakdown(format TEXT, start_date DATE, end_date DATE) RETURNS SETOF RECORD AS $F$
DECLARE
    actual_end_date DATE;
    actual_start_date DATE;
    query TEXT;
    _rec RECORD;
BEGIN
    actual_start_date := COALESCE(start_date, '1970-01-01'::DATE);
    actual_end_date := COALESCE(end_date, now()::DATE);
    query := reports.build_activity_query(format, reports.get_activities_for_report());

    FOR _rec IN EXECUTE query LOOP
        RETURN NEXT _rec;
    END LOOP;
END
$F$
LANGUAGE plpgsql;

这建立的查询,看起来(大约)这样的:

SELECT agent_id, 
    portal_user_id, 
    SUM(ended - started) AS total, 
    SUM(CASE WHEN activity_id = 3 THEN ended - started END) AS "Label 1"
    SUM(CASE WHEN activity_id = 4 THEN ended - started END) AS "Label 2"
FROM public.activity_log_final 
    LEFT JOIN agent USING (agent_id) 
WHERE started::DATE BETWEEN actual_start_date AND actual_end_date 
GROUP BY agent_id, portal_user_id 
ORDER BY agent_id

当我试着叫 get_agent_activity_breakdown() 功能,我得到这个错误:

psql:2009-10-22_agent_activity_report_test.sql:179: ERROR:  a column definition list is required for functions returning "record"
CONTEXT:  SQL statement "SELECT * FROM reports.get_agent_activity_breakdown('percentage', NULL, NULL)"
PL/pgSQL function "test_agent_activity" line 92 at SQL statement

诀窍是,当然,列标'标1"和"标签 2'依赖于该组的活动定义的内容 活动表,我无法预测的时候叫的功能。如何 我可以创建一个功能访问这个信息?

有帮助吗?

解决方案 3

两西蒙斯和凯文的答案是好的,但是我做了是分裂的调用数据库,为两个查询:

  1. 建立查询使用的查询的构造方法包括我在这个问题,返回得到应用程序。
  2. 呼叫查询的直接和返回的数据。

这是安全在我的情况,因为动态的列名单不经常更改,所以我不需要担心查询的目标数据的变化之间的这些话。否则,虽然,我的方法可能不起作用。

其他提示

如果你真的想动态创建这样的表,可能只是在函数中创建一个临时表,这样它就可以有你想要的任何列。让函数将所有行插入表中而不是返回它们。该函数只能返回表的名称,或者您只能拥有一个您知道的确切表名。运行该功能后,您只需从表中选择数据即可。该函数还应检查临时表是否存在,以便删除或截断它。

西蒙的答案最终可能会更好,我只是告诉你如何在不改变你的情况的情况下做到这一点。

来自文档

  

from_item可以是以下之一:

...
function_name ( [ argument [, ...] ] ) [ AS ] alias [ ( column_alias [, ...] | column_definition [, ...] ) ]
function_name ( [ argument [, ...] ] ) AS ( column_definition [, ...] )

换句话说,后来它说:

  

如果该功能已被定义为   然后返回记录数据类型   别名或关键字AS必须是   目前,后面是一个专栏   表格中的定义清单(   column_name data_type [,...])。该   列定义列表必须匹配   列的实际数量和类型   由函数返回。

我认为别名只是一个选项,如果你已经在某个地方预定了一个类型(比如你是在模仿预定义表的输出,或者实际上已经使用了CREATE TYPE ......请不要引用我但是。)

所以,我认为你需要这样的东西:

SELECT *
  FROM reports.get_agent_activity_breakdown('percentage', NULL, NULL)
    AS (agent_id integer, portal_user_id integer, total something, ...)

问题在于 ... 。在执行查询之前,您需要知道所有列的名称和类型 - 因此您最终将选择public.activity两次。

你不能改变输出列的数量,但你可以使用refcursor,你可以返回打开的游标。

更多信息,请访问 http://okbob.blogspot的.com / 2008/08 /使用游标换产生-cross.html

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top