下面的代码对我来说很好看,但是很有用。该功能应根据考试成绩显示学生的成绩水平,但不会运行最后两个其他陈述,因此,如果学生得分低于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;
有人能指出我的问题吗?
答案 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;