今天在論壇上,又遇到一網友在詢問搖獎的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.GIF
2a.GIF
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/13856521/viewspace-420425/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/13856521/viewspace-420425/