1

我有一个函数可以根据开始和停止时间戳对一系列数据进行一些基本统计:

CREATE OR REPLACE FUNCTION cal(TIMESTAMP, TIMESTAMP, OUT Date_Time timestamp with time zone, OUT avg numeric, OUT stddev numeric, OUT Rstedv_per numeric) 
AS $$
SELECT
    max(datetime) as Date_Time,
    avg(SO2) AS Mean,
    stddev_samp(so2) as STD_DEV,
    stddev_samp(so2)/avg(SO2)*100 as Rstedv_Per
FROM Table43
WHERE datetime > $1 AND datetime < $2;
$$
 LANGUAGE SQL;

这适用于简单的单一选择,例如:

select * FROM
 cal('2014-08-02 05:29:00', '2014-08-02 05:32:00')

但现在我无法创建另一个函数,甚至是一个可以组合多次调用“cal”函数的选择语句。例如,我想返回一个包含三个时间段的表。所以返回将是 4 列乘 3 行:

'2014-08-02 05:29:00', '2014-08-02 05:32:00'
'2014-08-02 05:35:00', '2014-08-02 05:39:00'
'2014-08-02 05:45:00'、'2014-08-02 05:49:00'
4

2 回答 2

0

Use a VALUES expression to provide multiple rows of input dates. Then ...

For all versions of Postgres

SELECT cal(a, b)
FROM  (
   VALUES 
      ('2014-08-02 05:29'::timestamp, '2014-08-02 05:32'::timestamp)
    , ('2014-08-02 05:35', '2014-08-02 05:39')
    , ('2014-08-02 05:45', '2014-08-02 05:39')
   ) v(a, b);

You can replace the VALUES expression with an actual table.

This returns whole rows as a single column (instead of individual columns). You could decompose in place with (cal(a, b)).*. While this works, it is inefficient. Due to a weakness in the Postgres parser, this would result in multiple evaluation of the function. Detailed explanation:

Instead, use a subquery for better performance:

SELECT (rec).*
FROM  (
    SELECT cal(a, b)
    FROM  (
       VALUES 
          ('2014-08-02 05:29'::timestamp, '2014-08-02 05:32'::timestamp)
        , ('2014-08-02 05:35', '2014-08-02 05:39')
        , ('2014-08-02 05:45', '2014-08-02 05:39')
       ) v(a, b)
   ) sub;

SQL Fiddle (for pg 8.3 to demonstrate it works in old versions).

Since set-returning functions in the SELECT list are frowned upon by some, and are non-standard SQL.

Postgres 9.3+

That's the main reason why Postgres 9.3 introduced (SQL-standard compliant) LATERAL JOIN:

SELECT f.*
FROM  (
   VALUES 
      ('2014-08-02 05:29'::timestamp, '2014-08-02 05:32'::timestamp)
    , ('2014-08-02 05:35', '2014-08-02 05:39')
    , ('2014-08-02 05:45', '2014-08-02 05:39')
   ) v(a,b)
  , cal(v.a, v.b) f;

The LATERAL JOIN is implicit here, since the second item in the FROM list references the previous table explicitly. Details:

SQL Fiddle for current Postgres 9.3.

于 2014-08-13T17:10:00.183 回答
0

如果您的日期是参数,您将需要以下内容:

select * 
FROM cal('2014-08-02 05:29:00', '2014-08-02 05:32:00')
union all
select * 
FROM cal('2014-08-02 05:35:00', '2014-08-02 05:39:00')
union all
select * 
FROM cal('2014-08-02 05:45:00', '2014-08-02 05:39:00')

PostgreSQL 9.0+

select cal(a, b)
from 
    values( 
    ('2014-08-02 05:29:00', '2014-08-02 05:32:00'),
    ('2014-08-02 05:29:00', '2014-08-02 05:32:00'),
    ('2014-08-02 05:29:00', '2014-08-02 05:32:00')
    ) as dates (a, b)

如果您的日期来自表格并且您正在使用Postresql 9.3

select cal.*
FROM 
  (select '2014-08-02 05:29:00' a, '2014-08-02 05:32:00' b
      from foo_table) as dates
left join lateral cal(dates.a, dates.b) cal on true
于 2014-08-13T16:23:59.657 回答