代码适用于某一点

时间:2011-12-07 18:08:12

标签: postgresql stored-procedures plpgsql

下面的代码对我来说很好看,但是很有用。该功能应根据考试成绩显示学生的成绩水平,但不会运行最后两个其他陈述,因此,如果学生得分低于50,该功能仍显示“通过”。

CREATE OR REPLACE FUNCTION stud_Result(integer,numeric) RETURNS text
AS 
$$
DECLARE
    stuNum ALIAS FOR $1;
    grade ALIAS FOR $2;
    result TEXT;
BEGIN
    IF grade >= 70.0 THEN SELECT 'distinction' INTO result FROM student,entry
        WHERE student.sno = entry.sno AND student.sno = stuNum;

    ELSIF grade >=50.0 OR grade <=70.0 THEN SELECT 'pass' INTO result FROM student,entry
        WHERE student.sno = entry.sno AND student.sno = stuNum;

    ELSIF grade >0 OR grade< 50.0 THEN SELECT 'fail' INTO result FROM student,entry
        WHERE student.sno = entry.sno AND student.sno = stuNum;

    ELSE SELECT 'NOT TAKEN' INTO result FROM student,entry
        WHERE student.sno = entry.sno AND student.sno = stuNum;
    END IF;

    RETURN result;
END;$$
LANGUAGE PLPGSQL;

有人能指出我的问题吗?

4 个答案:

答案 0 :(得分:1)

这是一个PostgreSQL陷阱,也使我绊倒了。您需要将ELSE IF替换为ELSIF

您看到了这个错误,因为每个连续的ELSE IF都被解释为启动嵌套的IF块,该块需要自己的END IF;

有关正确语法的详细信息,请参阅the documentation on conditionals

答案 1 :(得分:0)

你在条件中的逻辑有点奇怪。你有这些:

  • grade >= 70.0
  • grade >= 50.0 OR grade <= 70.0
  • grade > 0 OR grade < 50.0

注意,零满足第二个条件,就像在条件的那个分支中你不想要的许多其他值一样。我想你想要这些:

  • grade >= 70.0
  • grade >= 50.0 AND grade <= 70.0
  • grade > 0 AND grade < 50.0

你似乎也在使用你的SELECT来检查这个人是否在课程中但是如果给出了grade并且他们不在课程中,那么你最终会得到一个NULL {{1} }。 “在课程中”检查应该在您的函数之外,或者您应该在返回之前将NULL result转换为result

这看起来像是作业,所以我不会比这更明确。

答案 2 :(得分:0)

通常,我不认为在代码中隐藏数据是个好主意。数据属于表格:

SET search_path='tmp';

-- create some data
DROP TABLE tmp.student CASCADE;
CREATE TABLE tmp.student
    ( sno INTEGER NOT NULL
    , grade INTEGER
    , sname varchar
    );
INSERT INTO tmp.student(sno) SELECT generate_series(1,10);
UPDATE tmp.student SET grade = sno*sno;

DROP TABLE tmp.entry CASCADE;
CREATE TABLE tmp.entry
    ( sno INTEGER NOT NULL
    , sdate TIMESTAMP
    );
INSERT INTO tmp.entry(sno) SELECT generate_series(1,10);

-- table with interval lookup
DROP TABLE tmp.lookup CASCADE;
CREATE TABLE tmp.lookup
    ( llimit NUMERIC NOT NULL
    , hlimit NUMERIC
    , result varchar
    );

INSERT INTO lookup (llimit,hlimit,result)  VALUES(70, NULL, 'Excellent'), (50, 70, 'Passed'), (30, 50, 'Failed')
    ;

CREATE OR REPLACE FUNCTION stud_result(integer,numeric) RETURNS text
AS $BODY$
DECLARE
    stunum ALIAS FOR $1;
    grade ALIAS FOR $2;
    result TEXT;
BEGIN

SELECT COALESCE(lut.result, 'NOT TAKEN')  INTO result
    FROM student st, entry en
    LEFT JOIN lookup lut ON (grade >= lut.llimit
                    AND (grade < lut.hlimit OR lut.hlimit IS NULL) )
    WHERE st.sno = en.sno
     AND st.sno = stunum
    ;
  RETURN result;
END; $BODY$ LANGUAGE PLPGSQL;

-- query joining students with their function values
SELECT st.*
    , stud_result (st.sno, st.grade)
    FROM student st
    ;

但是等一下:你也可以没有丑陋的功能:

-- Plain query
SELECT
    st.sno, st.sname, st.grade
    , COALESCE(lut.result, 'NOT TAKEN') AS result
    FROM student st
    LEFT JOIN lookup lut ON ( 1=1
        AND   lut.llimit <= st.grade
        AND ( lut.hlimit > st.grade OR lut.hlimit IS NULL)
        )
    JOIN entry en ON st.sno = en.sno
    ;

结果:

 sno | grade | sname | stud_result 
-----+-------+-------+-------------
   1 |     1 |       | NOT TAKEN
   2 |     4 |       | NOT TAKEN
   3 |     9 |       | NOT TAKEN
   4 |    16 |       | NOT TAKEN
   5 |    25 |       | NOT TAKEN
   6 |    36 |       | Failed
   7 |    49 |       | Failed
   8 |    64 |       | Passed
   9 |    81 |       | Excellent
  10 |   100 |       | Excellent
(10 rows)

 sno | sname | grade |  result   
-----+-------+-------+-----------
   1 |       |     1 | NOT TAKEN
   2 |       |     4 | NOT TAKEN
   3 |       |     9 | NOT TAKEN
   4 |       |    16 | NOT TAKEN
   5 |       |    25 | NOT TAKEN
   6 |       |    36 | Failed
   7 |       |    49 | Failed
   8 |       |    64 | Passed
   9 |       |    81 | Excellent
  10 |       |   100 | Excellent
(10 rows)

答案 3 :(得分:-1)

完全摆脱这个功能并使用查询:

SELECT 
  s.*, 
  CASE e.grade 
    WHEN >= 0 AND < 50 THEN 'failed'
    WHEN >= 50 AND < 70 THEN 'passed'
    WHEN >= 70 AND <= 100 THEN 'excellent'
    ELSE 'not taken'
  END
FROM 
 student s,
 entry e
WHERE
 s.sno = e.sno; 
相关问题