Oracle递归子查询因子转换

时间:2015-09-19 08:36:37

标签: oracle recursion

我试图使用这种递归的SQL功能,但不能让它做我想做的事情,甚至不能关闭。我在一个展开的循环中对逻辑进行了编码,询问它是否可以转换为单个递归SQL查询,而不是我使用的表更新样式。

http://sqlfiddle.com/#!4/b7217/1

有六名球员排名。他们有id,group id,得分和排名。

初始状态

+----+--------+-------+--------+
| id | grp_id | score |  rank  |
+----+--------+-------+--------+
| 1  |     1  |  100  | (null) |
| 2  |     1  |   90  | (null) |
| 3  |     1  |   70  | (null) |
| 4  |     2  |   95  | (null) |
| 5  |     2  |   70  | (null) |
| 6  |     2  |   60  | (null) |
+----+--------+-------+--------+

我想带一个初始得分最高的人并给他们排名1.然后我将10个奖励积分应用于拥有相同组ID的每个人的得分。取下一个最高,分配等级2,分配奖励积分等等,直到没有玩家离开。

用户ID打破了关系。

奖励积分会改变排名。 id = 4最初看起来是第二位置95,在领先者后面有100但是有10点奖金,id = 2向上移动并占据了位置。

最终状态

+-----+---------+--------+------+
| ID  | GRP_ID  | SCORE  | RANK |
+-----+---------+--------+------+
|  1  |      1  |   100  |    1 |
|  2  |      1  |   100  |    2 |
|  4  |      2  |    95  |    3 |
|  3  |      1  |    90  |    4 |
|  5  |      2  |    80  |    5 |
|  6  |      2  |    80  |    6 |
+-----+---------+--------+------+

1 个答案:

答案 0 :(得分:2)

这已经相当晚了,但我不确定是否可以使用递归CTE来完成。然而,我确实使用MODEL子句提出了一个解决方案:

WITH SAMPLE (ID,GRP_ID,SCORE,RANK) AS (
SELECT 1,1,100,NULL FROM DUAL UNION
SELECT 2,1,90,NULL FROM DUAL UNION
SELECT 3,1,70,NULL FROM DUAL UNION
SELECT 4,2,95,NULL FROM DUAL UNION
SELECT 5,2,70,NULL FROM DUAL UNION
SELECT 6,2,60,NULL FROM DUAL)
SELECT ID,GRP_ID,SCORE,RANK FROM SAMPLE
MODEL
DIMENSION BY (ID,GRP_ID)
MEASURES (SCORE,0 RANK,0 LAST_RANKED_GRP,0 ITEM_COUNT,0 HAS_RANK)
RULES
ITERATE (1000) UNTIL (ITERATION_NUMBER = ITEM_COUNT[1,1]) --ITERATE ONCE FOR EACH ITEM TO BE RANKED
(
RANK[ANY,ANY] = CASE WHEN SCORE[CV(),CV()] = MAX(SCORE) OVER (PARTITION BY HAS_RANK) THEN RANK() OVER (ORDER BY SCORE DESC,ID) ELSE RANK[CV(),CV()] END, --IF THE CURRENT ITEM SCORE IS EQUAL TO THE MAX SCORE OF UNRANKED, ASSIGN A RANK
LAST_RANKED_GRP[ANY,ANY] = FIRST_VALUE(GRP_ID) OVER (ORDER BY RANK DESC),
SCORE[ANY,ANY] = CASE WHEN RANK[CV(),CV()] = 0 AND CV(GRP_ID) = LAST_RANKED_GRP[CV(),CV()] THEN SCORE[CV(),CV()]+10 ELSE SCORE[CV(),CV()] END,
ITEM_COUNT[ANY,ANY] = COUNT(*) OVER (),
HAS_RANK[ANY,ANY] = CASE WHEN RANK[CV(),CV()] <> 0 THEN 1 ELSE 0 END --TO SEPARATE RANKED/UNRANKED ITEMS
)
ORDER BY RANK;

它不是很漂亮,我怀疑有更好的方法可以解决这个问题,但它确实提供了预期的输出。

警告:

如果行数超过此数量,则必须增加迭代次数。

根据每次迭代后的得分进行完全重新排名。因此,如果我们获取您的样本数据,但将项目2的初始分数更改为95而不是90:在排名第1项并将第10项奖励提供给第2项后,它现在得分为105.因此我们将其排名为第1并将第1项下移至第2项。如果这不是理想的行为,您必须做一些修改。