2015-09-19 12 views
5

私はこの再帰的なSQL機能を使用しようとしていますが、私が望むことをやり遂げることはできません。私は、私が使用したテーブルの更新スタイルではなく、単一の再帰的なSQLクエリに変換できるかどうかを尋ねて、アンロールされたループでロジックをコーディングしました。Oracle Recursive Subquery Factoring convert

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

ランク付けする6人の選手があります。彼らはID、グループID、スコアとランクを持っています。私は最高の初期のスコアで、人を取り、彼らにランク1を与えたい

初期状態

+----+--------+-------+--------+ 
| 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) | 
+----+--------+-------+--------+ 

は、それから私は、同じグループIDを持つすべての人のスコアに10個のボーナスポイントを適用します。一番高い順位を取ってランク2を割り当て、ボーナスポイントを分配するなど、プレーヤーが残らなくなるまで続きます。

ユーザーIDが結びついています。

ボーナスポイントはランキングを変更します。 id = 4は最初は95で2位、100でリーダーの後ろに10 ptsボーナス、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 | 
+-----+---------+--------+------+ 

答えて

2

これはかなり遅れているが、私は、これは再帰CTEを使用して行うことができるかわかりません。

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; 

それは非常にきれいではない、と私はこれについて移動する良い方法があると疑われるが、それは予想される出力が得られない。しかし私は、MODEL句を使用して解決策を考え出すでした。

警告:

あなたは、行の数よりも多くを持っている場合、反復回数を増やす必要があるだろう。

これは、各反復後のスコアに基づいて完全な再順位付けを行います。したがって、サンプルデータを取ったが、アイテム2の初期スコアを90ではなく95に変更した場合:アイテム1をランキングしてアイテム2に10ポイントのボーナスを与えた後、スコアは105になります。項目1を2に移動します。これが望ましい動作でない場合は、いくつかの変更を加える必要があります。