PL/SQL 使用游标进行排名的程序
PL/SQL Program that uses a Cursor to Rank
我想在这里使用 SQL 语句并将其放入游标中。不幸的是,我无法为这个特定的任务使用 Rank() 函数。
CREATE or REPLACE PROCEDURE RankGPA
IS
vSnum student.snum%type;
vSname student.sname%type;
vGPA student.GPA%type;
vMajor student.major%type;
CURSOR rankGPA_cursor IS
SELECT s1.snum, s1.sname, s1.gpa, count( s2.gpa ) + 1 as rank, s1.major
FROM students s1
LEFT JOIN students s2
ON s1.GPA < s2.GPA
GROUP BY s1.snum, s1.sname, s1.gpa, s1.Major
ORDER BY 4;
BEGIN
OPEN rankGPA_cursor;
FETCH rankGPA_cursor INTO vSnum, vSname, vGPA, vMajor;
END;
我试图得到这样的输出:
Rank SNUM SNAME GPA MAJOR
**** **** ***** *** *****
1 101 Bob 4 ENGR
2 102 Cari 3.5 ENGL
您可以考虑使用 windowed functions
:
SELECT s1.snum, s1.sname, s1.gpa, s1.Major,RANK() OVER(ORDER BY s1.gpa) AS r
FROM students s1;
From RANK doc:
RANK calculates the rank of a value in a group of values. The return type is NUMBER.
我已经为 emp table 执行了类似的操作。您可以为学生更改它 table :
1.Without 函数排名:
SELECT x.ranking,ename,sal
FROM emp e,
(
SELECT e2.empno, COUNT(*) AS
ranking
FROM emp e1,emp e2 WHERE e1.sal<=e2.sal
GROUP BY e2.empno
)x
WHERE e.empno=x.empno
ORDER BY sal
2.With 函数排名:
SELECT RANK () OVER (ORDER BY sal DESC ) AS ranking ,empno,ename,sal
FROM emp
注意:如果有并列,可以用DENSE_RANK
SELECT DENSE_RANK () OVER (ORDER BY sal DESC ) AS ranking ,empno,ename,sal
FROM emp
您评论中的措辞有点令人困惑,但听起来他们希望您有一个局部变量来充当 'rank',方法是在获取行时对行进行计数,例如:
DECLARE
counter pls_integer := 0;
CURSOR rankGPA_cursor IS
SELECT s.snum, s.sname, s.gpa, s.major
FROM students s
ORDER BY s.gpa DESC;
BEGIN
FOR rankGPA_row IN rankGPA_cursor LOOP
counter := counter + 1;
dbms_output.put_line(counter
||' '|| rankGPA_row.snum
||' '|| rankGPA_row.sname
||' '|| rankGPA_row.gpa
||' '|| rankGPA_row.major
);
END LOOP;
END;
/
每次循环时 counter
变量都会增加。因为游标查询按 GPA 降序 排序,所以提取的第一行具有最高 GPA,此时计数器为 1。
为此使用 dbms_output
是一种不好的做法,因为在现实世界中您不知道客户端是否启用了该功能,并且您必须做一些工作来整齐地格式化打印结果。但这无论如何都是人为的。
您还需要考虑如果两个学生的 GPA 相同(这似乎很可能),您希望如何对事物进行排名。目前,这将对并列的学生进行任意排名。您可以更改 order by
子句以添加,例如,按名称进行二次排序;但分数相同的学生仍将获得不同的排名。通过跟踪最后一次看到的 GPA 并且仅在新行的值与前一个不同时才递增 rank/counter ,即使使用这种方法也可以给它们相同的排名。不过我不知道你要生产什么。
您可以为此使用任何样式的光标;显式或隐式,如果您愿意,可以使用循环游标或循环关闭中的显式打开获取。
我想在这里使用 SQL 语句并将其放入游标中。不幸的是,我无法为这个特定的任务使用 Rank() 函数。
CREATE or REPLACE PROCEDURE RankGPA
IS
vSnum student.snum%type;
vSname student.sname%type;
vGPA student.GPA%type;
vMajor student.major%type;
CURSOR rankGPA_cursor IS
SELECT s1.snum, s1.sname, s1.gpa, count( s2.gpa ) + 1 as rank, s1.major
FROM students s1
LEFT JOIN students s2
ON s1.GPA < s2.GPA
GROUP BY s1.snum, s1.sname, s1.gpa, s1.Major
ORDER BY 4;
BEGIN
OPEN rankGPA_cursor;
FETCH rankGPA_cursor INTO vSnum, vSname, vGPA, vMajor;
END;
我试图得到这样的输出:
Rank SNUM SNAME GPA MAJOR
**** **** ***** *** *****
1 101 Bob 4 ENGR
2 102 Cari 3.5 ENGL
您可以考虑使用 windowed functions
:
SELECT s1.snum, s1.sname, s1.gpa, s1.Major,RANK() OVER(ORDER BY s1.gpa) AS r
FROM students s1;
From RANK doc:
RANK calculates the rank of a value in a group of values. The return type is NUMBER.
我已经为 emp table 执行了类似的操作。您可以为学生更改它 table :
1.Without 函数排名:
SELECT x.ranking,ename,sal
FROM emp e,
(
SELECT e2.empno, COUNT(*) AS
ranking
FROM emp e1,emp e2 WHERE e1.sal<=e2.sal
GROUP BY e2.empno
)x
WHERE e.empno=x.empno
ORDER BY sal
2.With 函数排名:
SELECT RANK () OVER (ORDER BY sal DESC ) AS ranking ,empno,ename,sal
FROM emp
注意:如果有并列,可以用DENSE_RANK
SELECT DENSE_RANK () OVER (ORDER BY sal DESC ) AS ranking ,empno,ename,sal
FROM emp
您评论中的措辞有点令人困惑,但听起来他们希望您有一个局部变量来充当 'rank',方法是在获取行时对行进行计数,例如:
DECLARE
counter pls_integer := 0;
CURSOR rankGPA_cursor IS
SELECT s.snum, s.sname, s.gpa, s.major
FROM students s
ORDER BY s.gpa DESC;
BEGIN
FOR rankGPA_row IN rankGPA_cursor LOOP
counter := counter + 1;
dbms_output.put_line(counter
||' '|| rankGPA_row.snum
||' '|| rankGPA_row.sname
||' '|| rankGPA_row.gpa
||' '|| rankGPA_row.major
);
END LOOP;
END;
/
每次循环时 counter
变量都会增加。因为游标查询按 GPA 降序 排序,所以提取的第一行具有最高 GPA,此时计数器为 1。
为此使用 dbms_output
是一种不好的做法,因为在现实世界中您不知道客户端是否启用了该功能,并且您必须做一些工作来整齐地格式化打印结果。但这无论如何都是人为的。
您还需要考虑如果两个学生的 GPA 相同(这似乎很可能),您希望如何对事物进行排名。目前,这将对并列的学生进行任意排名。您可以更改 order by
子句以添加,例如,按名称进行二次排序;但分数相同的学生仍将获得不同的排名。通过跟踪最后一次看到的 GPA 并且仅在新行的值与前一个不同时才递增 rank/counter ,即使使用这种方法也可以给它们相同的排名。不过我不知道你要生产什么。
您可以为此使用任何样式的光标;显式或隐式,如果您愿意,可以使用循环游标或循环关闭中的显式打开获取。