डेन के जवाब में एक वर्ग कानून पेश करने वाले तरीके से स्वयं शामिल होता है। (n*n/2)
शामिल होने के बाद पंक्तियाँ जहाँ तालिका में n पंक्तियाँ हैं।
तालिका को केवल एक बार पार्स करने में सक्षम होने के लिए और अधिक आदर्श क्या होगा।
DECLARE @id int, @weight_sum int, @weight_point int
DECLARE @table TABLE (id int, weight int)
INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)
SELECT @weight_sum = SUM(weight)
FROM @table
SELECT @weight_point = FLOOR(((@weight_sum - 1) * RAND() + 1))
SELECT
@id = CASE WHEN @weight_point < 0 THEN @id ELSE [table].id END,
@weight_point = @weight_point - [table].weight
FROM
@table [table]
ORDER BY
[table].Weight DESC
यह @id
. को सेट करते हुए तालिका के माध्यम से जाएगा प्रत्येक रिकॉर्ड के id
. के लिए एक ही समय में @weight
. को घटाते हुए मान बिंदु। आखिरकार, @weight_point
नकारात्मक जाएगा। इसका मतलब है कि SUM
सभी पूर्ववर्ती भारों में से यादृच्छिक रूप से चुने गए लक्ष्य मान से अधिक है। यह वह रिकॉर्ड है जो हम चाहते हैं, इसलिए उस बिंदु से हम @id
. सेट करते हैं स्वयं के लिए (तालिका में किसी भी आईडी को अनदेखा करना)।
यह केवल एक बार तालिका के माध्यम से चलता है, लेकिन पूरी तालिका के माध्यम से चलना पड़ता है, भले ही चुना गया मान पहला रिकॉर्ड हो। क्योंकि औसत स्थिति तालिका से आधी दूरी पर है (और बढ़ते वजन के आधार पर कम होने पर) लूप लिखना संभवतः तेज़ हो सकता है... (विशेषकर यदि भार सामान्य समूहों में हों):
DECLARE @id int, @weight_sum int, @weight_point int, @next_weight int, @row_count int
DECLARE @table TABLE (id int, weight int)
INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)
SELECT @weight_sum = SUM(weight)
FROM @table
SELECT @weight_point = ROUND(((@weight_sum - 1) * RAND() + 1), 0)
SELECT @next_weight = MAX(weight) FROM @table
SELECT @row_count = COUNT(*) FROM @table WHERE weight = @next_weight
SET @weight_point = @weight_point - (@next_weight * @row_count)
WHILE (@weight_point > 0)
BEGIN
SELECT @next_weight = MAX(weight) FROM @table WHERE weight < @next_weight
SELECT @row_count = COUNT(*) FROM @table WHERE weight = @next_weight
SET @weight_point = @weight_point - (@next_weight * @row_count)
END
-- # Once the @weight_point is less than 0, we know that the randomly chosen record
-- # is in the group of records WHERE [table].weight = @next_weight
SELECT @row_count = FLOOR(((@row_count - 1) * RAND() + 1))
SELECT
@id = CASE WHEN @row_count < 0 THEN @id ELSE [table].id END,
@row_count = @row_count - 1
FROM
@table [table]
WHERE
[table].weight = @next_weight
ORDER BY
[table].Weight DESC