【问题标题】:Create function with SELECT CASE使用 SELECT CASE 创建函数
【发布时间】:2016-03-07 16:31:52
【问题描述】:

我想创建一个有 2 个参数的函数。这是我的SELECT 声明:

SELECT CASE 
   WHEN duration <=  10000000 THEN '00-01 sec'
           WHEN duration <=  40000000 THEN '01-04 sec' 
           WHEN duration <= 100000000 THEN '04-10 sec' 
           WHEN duration <= 300000000 THEN '10-30 sec' 
           WHEN duration <= 600000000 THEN '30-60 sec' 
           ELSE 'more than 60 sec' END AS "Kategorien", 
   COUNT(*) AS Requestcounter
FROM tablename
WHERE starttime BETWEEN '2016-03-01 00:00:00' AND '2016-03-08 14:00:00'
GROUP BY
  (CASE WHEN duration <=  10000000 THEN '00-01 sec'
   WHEN duration <=  40000000 THEN '01-04 sec' 
   ELSE 'more than 60 sec' END); 

结果:

 Kategorien | requestcounter
------------+----------------
 00-01 sec  |           2073
 01-04 sec  |              2
(2 rows)

我想从我的函数中得到这个结果。但我得到了错误:

查询没有结果数据的目的地

这是我的功能:

CREATE OR REPLACE FUNCTION requestcounter(mindate timestamptz,maxdate timestamptz) 
RETURNS SETOF integer AS $$ 

BEGIN
SELECT CASE WHEN duration <=  10000000 THEN '00-01 sec'
            WHEN duration <=  40000000 THEN '01-04 sec'  
            ELSE 'more than 60 sec' END AS "Kategorien", 
COUNT(*) AS Requestcounter from tablename where starttime BETWEEN mindate and maxdate
GROUP BY
  (CASE WHEN duration <=  10000000 THEN '00-01 sec' 
        WHEN duration <=  40000000 THEN '01-04 sec'  
        ELSE 'more than 60 sec' END);
Return; 
END;
$$ LANGUAGE plpgsql;

我知道RETURNS SETOF integer 不对,但我不知道如何让它工作?

【问题讨论】:

    标签: sql postgresql plpgsql return-type set-returning-functions


    【解决方案1】:

    @Travis 已经提供了您需要RETURN QUERY 才能从plpgsql function 实际返回查询结果。

    但是对于简单的SELECT,您不需要 plpgsql。请改用plain SQL function。无论哪种方式,您都需要定义返回类型,最好使用RETURNS TABLE,就像@Travis 提供的一样,但实际返回的数据类型必须精确匹配:

    CREATE OR REPLACE FUNCTION requestcounter(_mindate timestamptz, _maxdate timestamptz) 
      RETURNS TABLE (kategorien text, requestcounter int) AS
    $func$ 
    SELECT CASE WHEN duration <= 10000000 THEN '00-01 sec'::text
                WHEN duration <= 40000000 THEN '01-04 sec'
                -- more cases ...
                ELSE 'more than 60 sec' END  -- AS kategorien -- not visible outside function
         , count(*)::int                     -- AS requestcounter
    FROM   tablename
    WHERE  starttime BETWEEN _mindate AND _maxdate
    GROUP  BY 1                              -- simpler with positional reference
    ORDER  BY 1                              -- see below   
    $func$  LANGUAGE sql;                    -- never quote the language name
    
    • count() 返回bigint。如果将返回的列 requestcounter 定义为 int,则必须强制转换:count(*)::int(或返回 bigint 开头。)

    • 在 SQL 函数中,您可以使用普通的 SELECT 返回行。

    • 避免参数和列名之间的命名冲突。一个常见的约定是像我一样为参数添加前缀。

    • GROUP BY 中的位置引用是SELECT 列表中长表达式的一种非常方便的语法快捷方式。这还可以确保 GROUP BY 项目与 SELECT 项目匹配(在您的第一个查询中不是)。

    • 您可能想要添加ORDER BY 1 或者您得到任意顺序。您演示的text发生以正确的顺序排序。

    呼叫:

    SELECT * FROM requestcounter('2015-01-01 00:00+01', '2015-03-01 00:00+01') 
    

    【讨论】:

    • 感谢您的帮助! requestcounter -------------------- ("00-01 sec",2979) ("01-04 sec",2) 这是我的结果 - 有可能它看起来像这样: requestcounter ------------+---------------- 00-01 sec | 2073 01-04 秒 | 2 ?最好的问候所以我有 2 列?
    • @cartmanownz:用SELECT * FROM ...调用你的函数来分解行。
    • 再次非常感谢!!我用 postgres 9.3.8 试试这个 - 它可以工作,但是 8.4 有一个问题。你知道为什么吗?
    • @cartmanownz:SQL 函数从 pg 9.2 开始支持参数名称。更多:stackoverflow.com/a/25090744/939860
    • 再次感谢 - menas _mindate / _maxdate 在 postgres 8.4 中不会起作用。对?我能做些什么?我必须使用 $n 表示法?
    【解决方案2】:

    我想你想返回一个表格,而不是 SETOF INTEGER

    像这样:

    CREATE OR REPLACE FUNCTION requestcounter (mindate timestamptz, maxdate timestamptz) RETURNS TABLE (
        Kategorien text,
        requestcounter int
    ) AS
    $BODY$
    BEGIN
        RETURN QUERY
        SELECT CASE WHEN duration <=  10000000 THEN '00-01 sec'
                    WHEN duration <=  40000000 THEN '01-04 sec'  
                    ELSE 'more than 60 sec' END AS "Kategorien", 
        COUNT(*) AS Requestcounter from tablename where starttime BETWEEN mindate and maxdate GROUP BY
        (CASE WHEN duration <=  10000000 THEN '00-01 sec' 
        WHEN duration <=  40000000 THEN '01-04 sec'  
        ELSE 'more than 60 sec' END);
    END
    $BODY$
    LANGUAGE 'plpgsql';
    

    我认为您编写的函数正在运行一个选择查询,无处发送输出,然后它返回一组空整数。 (这就是您收到该错误的原因。)

    【讨论】:

      猜你喜欢
      • 2019-12-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      • 2021-01-15
      相关资源
      最近更新 更多