在postgresql函数中如何使用case

时间:2011-10-31 06:41:13

标签: function postgresql return-value

我是postgresql的新手,我可以编写一些简单的pg函数。现在我遇到了麻烦。 我想用case来获取四列,我该怎么办?

我的sql:

CREATE OR REPLACE FUNCTION get_grade(IN integer, out integer,out integer,out      integer,out integer)  AS
$BODY$
begin
    select 
    sum(case when t.pirority = 66 then 1 else 0 end) as I ,
    sum(case when t.pirority = 67 then 1 else 0 end) as II,
    sum(case when t.pirority = 68 then 1 else 0 end) as III,
    sum(case when t.pirority = 225 then 1 else 0 end) as IIII 
    from dt_info t 
    where t.registrant = $1
end
$BODY$
LANGUAGE 'plpgsql' VOLATILE

当我使用

select * from get_grade(22);

它没有按预期工作。

CREATE OR REPLACE FUNCTION get_grade(IN integer) returns setof record AS
$BODY$
    select
    sum(case when t.pirority = 66 then 1 else 0 end) as I,
    sum(case when t.pirority = 67 then 1 else 0 end) as II,
    sum(case when t.pirority = 68 then 1 else 0 end) as III,
    sum(case when t.pirority = 225 then 1 else 0 end) as IIII
    from dt_info t 
    where t.registrant = $1
$BODY$
LANGUAGE 'sql' VOLATILE;

然后我执行它:

select * from get_grade(25) as (v1 integer, v2 integer, v3 integer, v4 integer)
发生

错误:

ERROR:  function return row and query-specified return row do not match

3 个答案:

答案 0 :(得分:2)

我觉得有必要再加上一个答案。到目前为止,我对这些不满意 试试这个:

CREATE OR REPLACE FUNCTION get_grade(integer)
RETURNS TABLE (
 i    int4
,ii   int4
,iii  int4
,iiii int4) AS
$BODY$
SELECT sum(case when t.priority = 66  then 1 else 0 end)::int4  -- as I
      ,sum(case when t.priority = 67  then 1 else 0 end)::int4  -- as II
      ,sum(case when t.priority = 68  then 1 else 0 end)::int4  -- as III
      ,sum(case when t.priority = 225 then 1 else 0 end)::int4  -- as IIII 
FROM   dt_info t 
WHERE  t.registrant = $1;
$BODY$
LANGUAGE sql;

主要观点:

  • 可以使用LANGUAGE plpgsql编写这样的简单查询。您也可以使用LANGUAGE sql。无论哪种方式都有一定的优势。我在这里使用了sql。不需要使用sqlplpgsql字样的引号。

  • 不带引号的大写标识符是PostgreSQL中的错误样式。无论如何,它们都折叠成小写,只会让人感到困惑。

  • 函数体内的列别名在外部不可见。在这种情况下,它们只能作为文档。您必须明确命名您的OUT参数才能获得结果集的列名。否则,您必须为每个呼叫指定列列表。我不会这样做。

  • OUT参数的名称与函数体中的其他名称共享名称空间。表限定了与OUT参数冲突的列名。不要使用会冲突的别名。我在这里替换你的别名评论。

  • 返回列的类型必须与标头中的声明完全匹配。 sum()返回bigint 。您必须明确强制转换为整数或收到错误消息。

  • 我使用了列名priority而不是pirority。正如@Mu所指出的,这可能是一个错字(?)。

答案 1 :(得分:0)

我认为您想要使用RETURN QUERYsetof record返回类型:

CREATE OR REPLACE FUNCTION get_grade(IN integer, out bigint, out bigint, out bigint, out bigint)
returns setof record AS
$BODY$
begin
    return query select 
        sum(case when t.pirority = 66 then 1 else 0 end) as I,
        sum(case when t.pirority = 67 then 1 else 0 end) as II,
        sum(case when t.pirority = 68 then 1 else 0 end) as III,
        sum(case when t.pirority = 225 then 1 else 0 end) as IIII 
        from dt_info t 
        where t.registrant = $1;
end
$BODY$
LANGUAGE plpgsql VOLATILE;

您可以将其作为纯SQL函数执行:

CREATE OR REPLACE FUNCTION get_grade(IN integer, out bigint, out bigint, out bigint, out bigint)
returns setof record AS
$BODY$
    select 
        sum(case when t.pirority = 66 then 1 else 0 end) as I,
        sum(case when t.pirority = 67 then 1 else 0 end) as II,
        sum(case when t.pirority = 68 then 1 else 0 end) as III,
        sum(case when t.pirority = 225 then 1 else 0 end) as IIII 
    from dt_info t 
    where t.registrant = $1;
$BODY$
LANGUAGE sql VOLATILE;

BTW,t.pirority应该是t.priority还是真正的列名?

答案 2 :(得分:0)

我不确定如果我理解你说的很好。以下只是一个测试。

--create table 
skytf=> create table grade (registrant integer, pirority integer);
CREATE TABLE
skytf=> insert into grade values (1,66);
INSERT 0 1
skytf=> insert into grade values (1,66);
INSERT 0 1
skytf=> insert into grade values (1,67);
INSERT 0 1
skytf=> insert into grade values (1,67);
INSERT 0 1
skytf=> insert into grade values (1,67);
INSERT 0 1
skytf=> insert into grade values (1,68);
INSERT 0 1
skytf=> insert into grade values (1,225);
INSERT 0 1
skytf=> insert into grade values (1,225);
INSERT 0 1
skytf=> insert into grade values (1,225);
INSERT 0 1
skytf=> insert into grade values (1,225);
INSERT 0 1
skytf=> select * from grade;
 registrant | pirority 
------------+----------
          1 |       66
          1 |       66
          1 |       67
          1 |       67
          1 |       67
          1 |       68
          1 |      225
          1 |      225
          1 |      225
          1 |      225


--create function
CREATE OR REPLACE FUNCTION get_grade( in_reg integer ) RETURNS  RECORD AS
$$
DECLARE
    g_user record;
BEGIN
    select 
    sum(case when t.pirority = 66 then 1 else 0 end) as I ,
    sum(case when t.pirority = 67 then 1 else 0 end) as II,
    sum(case when t.pirority = 68 then 1 else 0 end) as III,
    sum(case when t.pirority = 225 then 1 else 0 end) as IIII 
    into g_user
    from grade  t 
    where t.registrant = in_reg;
    return g_user;
END;
$$
LANGUAGE PLPGSQL;          


--execute function
skytf=> select get_grade(1);
 get_grade 
-----------
 (2,3,1,4)
(1 row)