Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
列上的PLpgSQL(或ANSI SQL?)条件计算_Sql_Postgresql_Stored Procedures_Plpgsql - Fatal编程技术网

列上的PLpgSQL(或ANSI SQL?)条件计算

列上的PLpgSQL(或ANSI SQL?)条件计算,sql,postgresql,stored-procedures,plpgsql,Sql,Postgresql,Stored Procedures,Plpgsql,我想编写一个存储过程,对列执行条件计算。理想情况下,SP的实现将与db无关——如果可能的话。如果不是,底层数据库是PostgreSQL(v8.4),因此优先 正在查询的基础表如下所示: CREATE TABLE treatment_def ( id PRIMARY SERIAL KEY, name VARCHAR(16) NOT NULL ); CREATE TABLE foo_group_

我想编写一个存储过程,对列执行条件计算。理想情况下,SP的实现将与db无关——如果可能的话。如果不是,底层数据库是PostgreSQL(v8.4),因此优先

正在查询的基础表如下所示:

CREATE TABLE treatment_def (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL
                 );

CREATE TABLE foo_group_def (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL
                 );

CREATE TABLE foo (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL,
                    trtmt_id   INT REFERENCES treatment_def(id) ON DELETE RESTRICT,
                    foo_grp_id INT REFERENCES foo_group_def(id) ON DELETE RESTRICT,
                    is_male    BOOLEAN NOT NULL,
                    cost       REAL NOT NULL
             );
CREATE FUNCTION somefunc()
 RETURNS TABLE (
  treatment_name varchar(16)
, foo_group_name varchar(16)
, averaged_cost double precision)
AS
$BODY$

    SELECT t.name          -- AS treatment_name
         , g.name          -- AS group_name
         , CASE WHEN f.is_male THEN sum(f.cost)
                               ELSE avg(f.cost) END -- AS averaged_cost  
    FROM   foo f 
    JOIN   treatment_def t ON t.id = f.trtmt_id
    JOIN   foo_group_def g ON g.id = f.foo_grp_id
    GROUP  BY 1, 2, f.is_male;

$BODY$ LANGUAGE sql;
我想编写一个返回以下“表”结果集的SP:

治疗名称、食物组名称、平均成本

如果平均成本的计算方式不同,取决于行字段*是男性*标志设置为真还是假

出于这个问题的目的,假设如果is_-male标志设置为true,则平均成本计算为分组成本值的,如果is_-male标志设置为false,则成本值计算为分组成本值的平均

(显然)数据是按trmt_id、foo_grp_id(是否为男性?)分组的

如果在is_-male标志上没有条件测试,我大致了解了如何编写SQL。但是,在编写上面定义的SP时,我需要一些帮助

这是我的第一次尝试:

CREATE TYPE FOO_RESULT AS (treatment_name VARCHAR(16), foo_group_name VARCHAR(64), averaged_cost DOUBLE);      

// Outline plpgsql (Pseudo code)

CREATE FUNCTION somefunc() RETURNS SETOF FOO_RESULT AS $$
BEGIN
   RETURN QUERY SELECT t.name treatment_name, g.name group_name, averaged_cost  FROM foo f 
                     INNER JOIN treatment_def t ON t.id = f.trtmt_id
                     INNER JOIN foo_group_def g ON g.id = f.foo_grp_id
                GROUP BY f.trtmt_id, f.foo_grp_id;
END;
$$ LANGUAGE plpgsql;

关于如何正确编写此SP以实现“结果”列中的条件计算,我将不胜感激。您应该能够使用
CASE
语句:

SELECT t.name treatment_name, g.name group_name, 
  CASE is_male WHEN true then SUM(cost)
   ELSE AVG(cost) END AS averaged_cost  
FROM foo f 
  INNER JOIN treatment_def t ON t.id = f.trtmt_id
  INNER JOIN foo_group_def g ON g.id = f.foo_grp_id
GROUP BY 1, 2, f.is_male;
我不熟悉
PLpgSQL
,因此我不确定
BOOLEAN
列的确切语法,但以上内容至少可以让您从正确的方向开始。

可能如下所示:

CREATE TABLE treatment_def (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL
                 );

CREATE TABLE foo_group_def (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL
                 );

CREATE TABLE foo (  id         PRIMARY SERIAL KEY,
                    name       VARCHAR(16) NOT NULL,
                    trtmt_id   INT REFERENCES treatment_def(id) ON DELETE RESTRICT,
                    foo_grp_id INT REFERENCES foo_group_def(id) ON DELETE RESTRICT,
                    is_male    BOOLEAN NOT NULL,
                    cost       REAL NOT NULL
             );
CREATE FUNCTION somefunc()
 RETURNS TABLE (
  treatment_name varchar(16)
, foo_group_name varchar(16)
, averaged_cost double precision)
AS
$BODY$

    SELECT t.name          -- AS treatment_name
         , g.name          -- AS group_name
         , CASE WHEN f.is_male THEN sum(f.cost)
                               ELSE avg(f.cost) END -- AS averaged_cost  
    FROM   foo f 
    JOIN   treatment_def t ON t.id = f.trtmt_id
    JOIN   foo_group_def g ON g.id = f.foo_grp_id
    GROUP  BY 1, 2, f.is_male;

$BODY$ LANGUAGE sql;
要点
  • 我使用了
    sql
    函数,而不是
    plpgsql
    。你可以使用任何一个,我只是为了缩短代码
    plpgsql
    可能会稍微快一点,因为查询计划是缓存的

  • 我跳过了自定义复合类型。你可以用更简单的方法

  • 我通常建议使用而不是
    varchar(n)
    。让你的生活更轻松

  • 注意不要在函数体中使用没有表限定符(
    tbl.col
    )的返回参数的名称,否则会产生命名冲突。这就是为什么我对别名进行了注释

  • 我根据子句调整了
    分组。原来的不起作用。(@Ken的答案中的答案也是如此。)


+1表示干净简单且有效的ANSI SQL。你又一次救了我!:)