Eine Übersetzung aus dem Englischen. Original von Rob van Wijk
Chen Shapira verwies mich auf ein SQL Rätsel von Iggy Fernandez. Laurent Schneider hat bereits eine beeindruckend einfache Lösung mittels hierarchischer Abfrage und der XMLQuery Funktion gezeigt. Ich verwendete die SQL Model Clause (natürlich) um dasselbe Ergebnis zu erzielen:
SQL> select * from die order by face_id 2 / FACE_ID FACE_VALUE PROBABILITY ---------- ---------- ----------- 1 1 ,25 2 3 ,25 3 4 ,25 4 5 ,083333333 5 6 ,083333333 6 8 ,083333333 6 Zeilen ausgewählt. SQL> var N number SQL> exec :N := 2 PL/SQL-Prozedur erfolgreich abgeschlossen. SQL> with number_of_dies as (select count(*) cnt from die) 2 , all_probabilities as 3 ( select sum_value 4 , prob 5 , i 6 from (select level l from number_of_dies connect by level <= power(cnt,:N)) 7 , number_of_dies 8 model 9 reference r on (select face_id, face_value, probability from die) 10 dimension by (face_id) 11 measures (face_value,probability) 12 main m 13 partition by (l rn, cnt) 14 dimension by (0 i) 15 measures (0 die_face_id, 0 sum_value, 1 prob, l remainder) 16 rules iterate (1000) until (iteration_number + 1 = :N) 17 ( die_face_id[0] = 1 + mod(remainder[0]-1,cv(cnt)) 18 , remainder[0] = ceil((remainder[0] - die_face_id[0] + 1) / cv(cnt)) 19 , sum_value[0] = sum_value[0] + face_value[die_face_id[0]] 20 , prob[0] = prob[0] * probability[die_face_id[0]] 21 ) 22 ) 23 select sum_value "Sum" 24 , sum(prob) "Probability" 25 from all_probabilities 26 group by rollup(sum_value) 27 order by sum_value 28 / Sum Probability ---------- ----------- 2 ,0625 4 ,125 5 ,125 6 ,104166667 7 ,166666667 8 ,104166667 9 ,125 10 ,048611111 11 ,055555556 12 ,048611111 13 ,013888889 14 ,013888889 16 ,006944444 1 14 Zeilen ausgewählt. SQL> exec :N := 3 PL/SQL-Prozedur erfolgreich abgeschlossen. SQL> with number_of_dies as (select count(*) cnt from die) 2 , all_probabilities as 3 ( select sum_value 4 , prob 5 , i 6 from (select level l from number_of_dies connect by level <= power(cnt,:N)) 7 , number_of_dies 8 model 9 reference r on (select face_id, face_value, probability from die) 10 dimension by (face_id) 11 measures (face_value,probability) 12 main m 13 partition by (l rn, cnt) 14 dimension by (0 i) 15 measures (0 die_face_id, 0 sum_value, 1 prob, l remainder) 16 rules iterate (1000) until (iteration_number + 1 = :N) 17 ( die_face_id[0] = 1 + mod(remainder[0]-1,cv(cnt)) 18 , remainder[0] = ceil((remainder[0] - die_face_id[0] + 1) / cv(cnt)) 19 , sum_value[0] = sum_value[0] + face_value[die_face_id[0]] 20 , prob[0] = prob[0] * probability[die_face_id[0]] 21 ) 22 ) 23 select sum_value "Sum" 24 , sum(prob) "Probability" 25 from all_probabilities 26 group by rollup(sum_value) 27 order by sum_value 28 / Sum Probability ---------- ----------- 3 ,015625 5 ,046875 6 ,046875 7 ,0625 8 ,109375 9 ,09375 10 ,125 11 ,098958333 12 ,104166667 13 ,088541667 14 ,057291667 15 ,05787037 16 ,032986111 17 ,027777778 18 ,012731481 19 ,008680556 20 ,006944444 21 ,001736111 22 ,001736111 24 ,000578704 1 21 Zeilen ausgewählt.
Und mit einem traditionellen Würfel:
SQL> update die 2 set face_value = face_id 3 , probability = 1/6 4 / 6 Zeilen wurden aktualisiert. SQL> select * from die order by face_id 2 / FACE_ID FACE_VALUE PROBABILITY ---------- ---------- ----------- 1 1 ,166666667 2 2 ,166666667 3 3 ,166666667 4 4 ,166666667 5 5 ,166666667 6 6 ,166666667 6 Zeilen ausgewählt. SQL> with number_of_dies as (select count(*) cnt from die) 2 , all_probabilities as 3 ( select sum_value 4 , prob 5 , i 6 from (select level l from number_of_dies connect by level <= power(cnt,:N)) 7 , number_of_dies 8 model 9 reference r on (select face_id, face_value, probability from die) 10 dimension by (face_id) 11 measures (face_value,probability) 12 main m 13 partition by (l rn, cnt) 14 dimension by (0 i) 15 measures (0 die_face_id, 0 sum_value, 1 prob, l remainder) 16 rules iterate (1000) until (iteration_number + 1 = :N) 17 ( die_face_id[0] = 1 + mod(remainder[0]-1,cv(cnt)) 18 , remainder[0] = ceil((remainder[0] - die_face_id[0] + 1) / cv(cnt)) 19 , sum_value[0] = sum_value[0] + face_value[die_face_id[0]] 20 , prob[0] = prob[0] * probability[die_face_id[0]] 21 ) 22 ) 23 select sum_value "Sum" 24 , sum(prob) "Probability" 25 from all_probabilities 26 group by rollup(sum_value) 27 order by sum_value 28 / Sum Probability ---------- ----------- 3 ,00462963 4 ,013888889 5 ,027777778 6 ,046296296 7 ,069444444 8 ,097222222 9 ,115740741 10 ,125 11 ,125 12 ,115740741 13 ,097222222 14 ,069444444 15 ,046296296 16 ,027777778 17 ,013888889 18 ,00462963 1 17 Zeilen ausgewählt. SQL> exec :N := 4 PL/SQL-Prozedur erfolgreich abgeschlossen. SQL> with number_of_dies as (select count(*) cnt from die) 2 , all_probabilities as 3 ( select sum_value 4 , prob 5 , i 6 from (select level l from number_of_dies connect by level <= power(cnt,:N)) 7 , number_of_dies 8 model 9 reference r on (select face_id, face_value, probability from die) 10 dimension by (face_id) 11 measures (face_value,probability) 12 main m 13 partition by (l rn, cnt) 14 dimension by (0 i) 15 measures (0 die_face_id, 0 sum_value, 1 prob, l remainder) 16 rules iterate (1000) until (iteration_number + 1 = :N) 17 ( die_face_id[0] = 1 + mod(remainder[0]-1,cv(cnt)) 18 , remainder[0] = ceil((remainder[0] - die_face_id[0] + 1) / cv(cnt)) 19 , sum_value[0] = sum_value[0] + face_value[die_face_id[0]] 20 , prob[0] = prob[0] * probability[die_face_id[0]] 21 ) 22 ) 23 select sum_value "Sum" 24 , sum(prob) "Probability" 25 from all_probabilities 26 group by rollup(sum_value) 27 order by sum_value 28 / Sum Probability ---------- ----------- 4 ,000771605 5 ,00308642 6 ,007716049 7 ,015432099 8 ,027006173 9 ,043209877 10 ,061728395 11 ,080246914 12 ,096450617 13 ,108024691 14 ,112654321 15 ,108024691 16 ,096450617 17 ,080246914 18 ,061728395 19 ,043209877 20 ,027006173 21 ,015432099 22 ,007716049 23 ,00308642 24 ,000771605 1 22 Zeilen ausgewählt.
Über die Lösung: sie generiert so viele Zeilen wie es Kombinationen gibt (power(cnt,:N)). Mit der die_face_id und den verbleibenden Größenwerten (measures), wird jede generierte Zeile in N face_id's mit N Wiederholungen umgewandelt. Der face_value und die Wahrscheinlichkeiten werden über ein Referenz Modell geholt. Zuletzt summiert nur noch die äußere Abfrage alle Wahrscheinlichkeiten.
Die SQL Sprache ist nicht "komplett", aber seit Version 10 wundere ich mich ernsthaft ob es Probleme gibt, die nicht mit SQL gelöst werden können. Auch wenn es für manche wie eine Breze (die pretzel, die von Steven Feuerstein erwähnt wurde) wirkt bin ich sicher, dass es mit einigen Kommentaren gar nicht so schwer wartbar ist.