2015-09-19 12 views
5

Bu özyinelemeli SQL özelliğini kullanmaya çalışıyorum ama istediğimi yapmak için alamıyorum, hatta yakın değil. Ben mantıksız bir döngü içinde kodlanmış ettik, ben kullandım tablo güncelleştirme stili değil, tek bir özyinelemeli SQL sorgusuna dönüştürülebilir olup olmadığını soran. sırada yer almak altı oyuncusuOracle Recursive Subquery Factoring dönüştürmek

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

bulunmaktadır. Kimlik, grup kimliği, skor ve rütbeleri var.

İlk durum Ben en yüksek ilk skora sahip kişi alıp onlara rütbe 1. vermek istiyorum

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

Sonra aynı grup kimliği var herkesin puanına 10 bonus puan geçerlidir. Bir sonraki en yüksek puanı alın, 2. sıra belirleyin, bonus puanları dağıtın ve oyuncu kalmayıncaya kadar devam edin.

Kullanıcı kimliği kopma bağları.

Bonus puanları sıralamayı değiştirir. id = 4 başlangıçta 95 ile ikinci sırada, 100'ün arkasında ise 10 puanlık bonusla beliriyor, id = 2 yukarı çıkıyor ve noktayı alıyor.

Final devlet

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

cevap

2

Bu geç biraz, ama bu özyinelemeli CTE kullanılarak yapılabilir emin değilim.

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; 

Çok hoş değil ve bu konuda gitmek için daha iyi bir yol yoktur sanıyorum, ancak beklenen çıkışı veriyor: Ben ancak MODEL maddesini kullanarak bir çözüm geldi.

Uyarılar:

Sen satır o sayıdan fazla varsa yineleme sayısını artırmak gerekir.

Bu, her yinelemeden sonra skora dayanan tam bir yeniden sıralama yapar. Eğer örnek verilerinizi alırsak, ancak madde 1'den 95 yerine 90'ıncu maddenin ilk skorunu değiştirirsek: 1. maddeyi sıraladıktan ve 10 puanlık bonusu madde 2'ye verdikten sonra, şimdi 105 puan alır. Böylece 1. olarak sıralarız. ve madde 1'i 2'ye indirin. İstenilen davranış değilse, birkaç değişiklik yapmanız gerekir.