AI智能
改变未来

ORACLE實現搖獎的思路

今天在論壇上,又遇到一網友在詢問搖獎的SQL.
這讓我想起rollingpig大師,講過的一句名言:SQL並不能解決一切,這世界上,還有編程語言這種東西!
那如何實現搖獎呢?
1.首先要有基本資料,要有來源數據.然後再根據篩選倏件,讓電腦自動運算.然後輸出結果.
2.電腦運算,就用隨機抽取的方法.ORACLE自帶一個隨機語言包:dbms_random.
3.輸出結果時,回車鍵開始,空格鍵暫停.
範例:我是用4GL語言來實現了一個隨機抽盤.

附上隨機語言包SCRIPT:

<?php

   CREATE OR REPLACE PACKAGE BODY SYS.dbms_random AS
    mem        num_array;           — big internal state hidden from the user
    counter    BINARY_INTEGER := 55;– counter through the results
    saved_norm NUMBER := NULL;      — unused random normally distributed value
    need_init  BOOLEAN := TRUE;     — do we still need to initialize

    — Seed the random number generator with a binary_integer
    PROCEDURE seed(val IN BINARY_INTEGER) IS
    BEGIN
    seed(TO_CHAR(val));
    END seed;

    — Seed the random number generator with a string.
    PROCEDURE seed(val IN VARCHAR2) IS
        junk     VARCHAR2(2000);
        piece    VARCHAR2(20);
        randval  NUMBER;
        mytemp   NUMBER;
        j        BINARY_INTEGER;
    BEGIN
        need_init   := FALSE;
        saved_norm  := NULL;
        counter     := 0;
        junk        := TO_SINGLE_BYTE(val);
        FOR i IN 0..54 LOOP
            piece   := SUBSTR(junk,1,19);
            randval := 0;
            j       := 1;

            — convert 19 characters to a 38-digit number
            FOR j IN 1..19 LOOP
                randval := 1e2*randval + NVL(ASCII(SUBSTR(piece,j,1)),0.0);
            END LOOP;

            — try to avoid lots of zeros
            randval := randval*1e-38+i*.01020304050607080910111213141516171819;
            mem(i)  := randval – TRUNC(randval);

            — we\’ve handled these first 19 characters already; move on
            junk    := SUBSTR(junk,20);
        END LOOP;

    randval := mem(54);
        FOR j IN 0..10 LOOP
            FOR i IN 0..54 LOOP

                — barrelshift mem(i-1) by 24 digits
                randval := randval * 1e24;
                mytemp  := TRUNC(randval);
                randval := (randval – mytemp) + (mytemp * 1e-38);

                — add it to mem(i)
                randval := mem(i)+randval;
                IF (randval >= 1.0) THEN
                    randval := randval – 1.0;
                END IF;

        — record the result
                mem(i) := randval;
            END LOOP;
        END LOOP;
    END seed;

    — give values to the user
    — Delayed Fibonacci, pilfered from Knuth volume 2
    FUNCTION value RETURN NUMBER IS
    randval  NUMBER;
    BEGIN
        counter := counter + 1;
        IF counter >= 55 THEN

            — initialize if needed
            IF (need_init = TRUE) THEN
                seed(TO_CHAR(SYSDATE,\’MM-DD-YYYY HH24:MI:SS\’) ||
                     USER || USERENV(\’SESSIONID\’));
            ELSE
                — need to generate 55 more results
                FOR i IN 0..30 LOOP
                    randval := mem(i+24) + mem(i);
                    IF (randval >= 1.0) THEN
                        randval := randval – 1.0;
                    END IF;
                    mem(i) := randval;
                END LOOP;
                FOR i IN 31..54 LOOP
                    randval := mem(i-31) + mem(i);
                    IF (randval >= 1.0) THEN
                        randval := randval – 1.0;
                    END IF;
                    mem(i) := randval;
                END LOOP;
            END IF;
            counter := 0;
        END IF;
        RETURN mem(counter);
    END value;

    — Random 38-digit number between LOW and HIGH.
    FUNCTION value ( low in NUMBER, high in NUMBER) RETURN NUMBER is
    BEGIN
        RETURN (value*(high-low))+low;
    END value;

    — Random numbers in a normal distribution.
    — Pilfered from Knuth volume 2.
    FUNCTION normal RETURN NUMBER is  — 38 decimal places: Mean 0, Variance 1
        v1  NUMBER;
        v2  NUMBER;
        r2  NUMBER;
        fac NUMBER;
    BEGIN
        IF saved_norm is not NULL THEN     — saved from last time
            v1 := saved_norm;              — to be returned this time
            saved_norm := NULL;
        ELSE
            r2 := 2;
            — Find two independent uniform. variables
            WHILE r2 > 1 OR r2 = 0 LOOP
                v1 := value();
                v1 := v1 + v1 – 1;
                v2 := value();
                v2 := v2 + v2 – 1;
                r2 := v1*v1 + v2*v2;  — r2 is radius
            END LOOP;      — 0 < r2 <= 1:  in unit circle
            /* Now derive two independent normally-distributed variables */
            fac := sqrt(-2*ln(r2)/r2);
            v1 := v1*fac;          — to be returned this time
            saved_norm := v2*fac;  — to be saved for next time
        END IF;
        RETURN v1;
    END  normal;

    — Random string.  Pilfered from Chris Ellis.
    FUNCTION string (opt char, len NUMBER)
        RETURN VARCHAR2 is    — string of characters
        optx char (1)      := lower(opt);
        lo   NUMBER;
        rng  NUMBER;
        n    NUMBER;
        xstr VARCHAR2 (4000) := NULL;
    BEGIN
        IF    ptx = \’u\’ THEN     — upper case alpha characters only
            lo := 65; rng := 26; — ASCII 41 to 5A (hex)
        ELSIF ptx = \’l\’ THEN     — lower case alpha characters only
            lo := 97; rng := 26; — ASCII 61 to 7A (hex)
        ELSIF ptx = \’a\’ THEN     — alpha characters only (mixed case)
            lo := 65; rng := 52; — ASCII 41 to 5A and 61 to 7A (see below)
        ELSIF ptx = \’x\’ THEN      — any alpha-numeric characters (upper)
            lo := 48; rng := 36; — ASCII 30 to 39 and 41 to 5A (see below)
        ELSIF ptx = \’p\’ THEN     — any printable characters
            lo := 32; rng := 95; — ASCII 20 to 7E (hex)
        ELSE
            lo := 65; rng := 26; — default to upper case
        END IF;
        FOR i IN 1 .. least(len,4000) LOOP
            /* Get random ASCII character value in specified range */
            n := lo + TRUNC(rng * value); — between lo and (lo + rng -1)
            /* Adjust FOR split range */
            IF    ptx = \’a\’ AND n > 90 THEN
                n := n+6;               — exclude ASCII characters 5B to 60
            ELSIF ptx = \’x\’ AND n > 57 THEN
                n := n+7;               — exclude ASCII characters 3A to 40
            END IF;
            xstr := xstr||chr(n);    — Append character to string
        END LOOP;
        RETURN xstr;
    END string;

    — For compatibility with 8.1
    PROCEDURE initialize(val IN BINARY_INTEGER) IS
    BEGIN
    seed(to_char(val));
    END initialize;

    — For compatibility with 8.1
    — Random binary_integer, -power(2,31) <= Random < power(2,31)
    — Delayed Fibonacci, pilfered from Knuth volume 2
    FUNCTION random RETURN BINARY_INTEGER IS
    BEGIN
    RETURN TRUNC(Value*4294967296)-2147483648;
    END random;

    — For compatibility with 8.1
    PROCEDURE terminate IS
    BEGIN
    NULL;
    END terminate;

END dbms_random;

?>

1a.GIF2a.GIF

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13856521/viewspace-420425/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/13856521/viewspace-420425/

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » ORACLE實現搖獎的思路