मैं TSQL चयन में प्रत्येक पंक्ति के लिए यादृच्छिक संख्या कैसे उत्पन्न करूं?


328

मुझे अपनी तालिका में प्रत्येक पंक्ति के लिए एक अलग यादृच्छिक संख्या चाहिए। निम्नलिखित प्रतीत होता है स्पष्ट कोड प्रत्येक पंक्ति के लिए समान यादृच्छिक मूल्य का उपयोग करता है।

SELECT table_name, RAND() magic_number 
FROM information_schema.tables 

मैं इसमें से एक INT या FLOAT प्राप्त करना चाहूंगा। शेष कहानी मैं इस यादृच्छिक संख्या का उपयोग एक ज्ञात तिथि से एक यादृच्छिक तिथि ऑफसेट बनाने के लिए करने जा रहा हूं, उदाहरण के लिए प्रारंभ तिथि से 1-14 दिन ऑफसेट।

यह Microsoft SQL Server 2000 के लिए है।


4
क्या इसका कोई समाधान है जो NEWID () का उपयोग नहीं करता है? मैं एक दिए गए बीज के लिए यादृच्छिक संख्याओं के समान अनुक्रम को उत्पन्न करने में सक्षम होना चाहता हूं।
रॉरी मैकलेओड

@ नियम पूछें कि नए प्रश्न के रूप में, इसे अधिक ध्यान मिलेगा। (मेरा जवाब यादृच्छिक संख्याओं की निश्चित तालिकाओं का उपयोग करना होगा, उदाहरण के लिए। यादृच्छिक संख्या के इस प्रसिद्ध मानक सेट के लिए: rand.org/pubs/monograph_reports/MR1418/index.html )
मैथार्टिन


रैंड को 2005 में पेश किया गया था, यह सवाल 2009 में पूछा गया था, किन संगठनों ने अभी भी SQL 2000 का उपयोग किया था क्योंकि यह 1 संस्करण था जो हमेशा के लिए उपयोग करने के लिए पर्याप्त था।
मत्तीमार्टिन

रोरी मैकलेओड ने पूछा, "क्या इसका कोई समाधान है जो NEWID () का उपयोग नहीं करता है? मैं एक दिए गए बीज के लिए यादृच्छिक संख्याओं के समान अनुक्रम को उत्पन्न करने में सक्षम होना चाहता हूं।" इसका उत्तर हाँ है, लेकिन इसका परिणाम थोड़ा जटिल है। 1. एक दृश्य बनाएं जो चुनिंदा रैंड () देता है 2. एक यूडीएफ बनाएं जो दृश्य से मूल्य का चयन करता है। 3. अपना डेटा चुनने से पहले, रैंड () फ़ंक्शन को सीड करें। 4. अपने चुनिंदा कथन में यूडीएफ का उपयोग करें। मैं नीचे एक पूर्ण उदाहरण पोस्ट
करूंगा

जवाबों:


516

SQL सर्वर पर एक नज़र डालें - आधारित रैंडम नंबर सेट करें जिसमें बहुत विस्तृत विवरण है।

संक्षेप में, निम्नलिखित कोड एक समान वितरण के साथ 0 और 13 के बीच एक यादृच्छिक संख्या उत्पन्न करता है:

ABS(CHECKSUM(NewId())) % 14

अपनी सीमा बदलने के लिए, अभिव्यक्ति के अंत में बस संख्या को बदलें। अतिरिक्त सावधानी बरतें यदि आपको एक ऐसी सीमा की आवश्यकता है जिसमें सकारात्मक और नकारात्मक दोनों संख्याएँ शामिल हैं। यदि आप इसे गलत करते हैं, तो संख्या 0 को दोगुना करना संभव है।

कमरे में गणित पागल के लिए एक छोटी सी चेतावनी: इस कोड में बहुत मामूली पूर्वाग्रह है। CHECKSUM()उन संख्याओं में परिणाम जो sql Int डेटाटाइप की पूरी रेंज में समान हैं, या कम से कम इतना निकट है जितना कि मेरा (संपादक) परीक्षण दिखा सकता है। हालाँकि, कुछ पूर्वाग्रह होंगे जब CHECKSUM () उस श्रेणी के बहुत ऊपरी छोर पर एक संख्या का उत्पादन करता है। किसी भी समय आपको अधिकतम संभव पूर्णांक और अपनी इच्छित श्रेणी के आकार के अंतिम सटीक एकाधिक (इस मामले में 14) के बीच एक संख्या मिलती है, इससे पहले कि अधिकतम पूर्णांक, वे परिणाम आपकी सीमा के शेष भाग के पक्ष में होते हैं, जिनसे उत्पादन नहीं किया जा सकता है 14 के पिछले कई।

एक उदाहरण के रूप में, कल्पना करें कि इंट की पूरी रेंज केवल 19 है। 19 सबसे बड़ा संभव पूर्णांक है जिसे आप पकड़ सकते हैं। जब CHECKSUM () 14-19 में परिणाम होता है, तो ये परिणाम 0-5 के अनुरूप होते हैं। उन संख्याओं की जाएगी भारी , 6-13 से अधिक इष्ट क्योंकि अंततः () दो बार के रूप में उन्हें उत्पन्न करने के लिए की संभावना है। यह नेत्रहीन प्रदर्शित करना आसान है। नीचे हमारी काल्पनिक पूर्णांक श्रेणी के लिए परिणामों का पूरा संभव सेट दिया गया है:

चेकसम इंटेगर: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
रेंज रिजल्ट: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 1 2 3 4 5

आप यहां देख सकते हैं कि दूसरों की तुलना में कुछ संख्याओं का उत्पादन करने की अधिक संभावना है: पूर्वाग्रह। शुक्र है, इंट प्रकार की वास्तविक सीमा बहुत अधिक है बड़ी है ... इतना अधिक है कि ज्यादातर मामलों में पूर्वाग्रह लगभग undetectable है। हालाँकि, यदि आप कभी भी अपने आप को गंभीर सुरक्षा कोड के लिए ऐसा करते हुए पाते हैं, तो यह जागरूक होना चाहिए।


28
इस लिंक किए गए पृष्ठ का हल था: ABS (CHECKSUM (NewId ())% 14
मैथ्मार्टिन

7
% 14 0 और 13 के बीच की संख्या में लौटेगा
कोडरडेन

7
@ डेनिस पामर, बस 1
KM

59
हमने बस इसके साथ एक जीन बग की खोज की। क्योंकि चेकसम एक इंट लौटाता है, और एक इंट की रेंज -2 ^ 31 (-2,147,483,648) से 2 ^ 31-1 (2,147,483,647) है, एब्स () फ़ंक्शन ओवरफ्लो कर सकता है यदि परिणाम बिल्कुल -2,147,483,648 हो। ! संभावना स्पष्ट रूप से बहुत कम है, लगभग 1 से 4 बिलियन में, हालांकि हम इसे हर दिन ~ 1.8b पंक्ति तालिका पर चला रहे थे, इसलिए यह सप्ताह में एक बार हो रहा था! फिक्स को एब्स से पहले चेकइन को बिगिंट में डालना है।
एविलपुपेटमैस्टर

17
मुझे लगता है कि इसे "एक समान वितरण" कहना चाहिए "सामान्यीकृत वितरण" नहीं - प्रत्येक संख्या समान रूप से होने की संभावना है, यह एक घंटी वक्र नहीं है। "सामान्यीकृत" का एक विशिष्ट गणितीय अर्थ है।
अन्यपेकर

95

जब एक ही बैच में कई बार कॉल किया जाता है, तो रैंड () एक ही नंबर देता है।

मैं बीज तर्क के रूप में कन्वर्ट ( varbinary, newid()) का उपयोग करने का सुझाव दूंगा:

SELECT table_name, 1.0 + floor(14 * RAND(convert(varbinary, newid()))) magic_number 
FROM information_schema.tables

newid() हर बार एक अलग मूल्य वापस करने की गारंटी दी जाती है, जिसे एक ही बैच के भीतर भी कहा जाता है, इसलिए इसे बीज के रूप में उपयोग करने से प्रत्येक बार एक अलग मूल्य देने के लिए रैंड () का संकेत मिलेगा।

1 से 14 तक यादृच्छिक पूरी संख्या प्राप्त करने के लिए संपादित।


आपको एक गाइड या वैरिनरी से एक नंबर कैसे मिलता है? मैं यह इंगित करने के लिए प्रश्न अपडेट करूंगा कि मैं पूर्णांक के लिए आशा कर रहा हूं।
मैथ्मार्टिन

1
आप इसे एक संख्या से गुणा करते हैं और इसे फर्श करते हैं :) इसलिए यदि आप पांच अंक चाहते हैं, तो 100000 से गुणा करें, और एक इंट में कनवर्ट करें। बदसूरत, लेकिन करने के लिए काफी सरल।
जेरेमी स्माइथ

1
एक और परिशिष्ट के रूप में - कि तुम दे देंगे अप करने के लिए पाँच अंक - अगर आप शून्य पैड करना चाहते हैं यह, आप 5 अंक के लिए शून्य पैड अप करने के लिए एक चार डेटाप्रकार, और उपयोग को दोहराने का उपयोग करना होगा।
जेरेमी स्मिथ

आप मंजिल के बजाय छत फ़ंक्शन का उपयोग करें, तो आप 1. जोड़ने की जरूरत नहीं है
PopeDarren

यहां तक ​​कि जब मैं इसका उपयोग करता हूं, तो कई बार ऐसा होता है कि रैंड () मुझे हमेशा एक ही परिणाम देता है। यहां तक ​​कि अजनबी भी, कई बार यह गलत व्यवहार के लिए सही से कूदता है जो मैं इसे उपयोग कर रहा हूं। मैं एक रैंडम इनर जोइन को लागू करने की कोशिश कर रहा हूं और अगर मैं 19 से अधिक (!!!) पंक्तियों के लिए कहता हूं, तो यह मुझे हमेशा एक ही परिणाम देना शुरू कर देता है ...
जोहान्स वेन्टू

72
RAND(CHECKSUM(NEWID()))

उपरोक्त 0 और 1, अनन्य के बीच एक (छद्म) यादृच्छिक संख्या उत्पन्न करेगा। यदि एक चयन में उपयोग किया जाता है, क्योंकि प्रत्येक पंक्ति के लिए बीज का मूल्य बदल जाता है, तो यह प्रत्येक पंक्ति के लिए एक नया यादृच्छिक संख्या उत्पन्न करेगा (हालांकि यह प्रति पंक्ति एक अद्वितीय संख्या उत्पन्न करने की गारंटी नहीं है)।

10 की ऊपरी सीमा के साथ संयुक्त होने पर उदाहरण (संख्या 1 - 10 का उत्पादन करता है):

CAST(RAND(CHECKSUM(NEWID())) * 10 as INT) + 1

लेनदेन-एसक्यूएल प्रलेखन:

  1. CAST(): https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
  2. RAND(): http://msdn.microsoft.com/en-us/library/ms177610.aspx
  3. CHECKSUM(): http://msdn.microsoft.com/en-us/library/ms189788.aspx
  4. NEWID(): https://docs.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql

39

1000 और 9999 के बीच यादृच्छिक संख्या पीढ़ी:

FLOOR(RAND(CHECKSUM(NEWID()))*(9999-1000+1)+1000)

"+1" - ऊपरी बाध्य मानों को शामिल करने के लिए (पिछले उदाहरण के लिए 9999)


ऊपरी बाउंड इस पद्धति के साथ विशिष्ट है, इसलिए यदि आप शीर्ष नंबर को शामिल करना चाहते हैं तो आपको करना होगाFLOOR(RAND(CHECKSUM(NEWID()))*(10000-1000)+1000)
vaindil

20

पुराने प्रश्न का उत्तर दे रहा है, लेकिन यह उत्तर पहले प्रदान नहीं किया गया है, और उम्मीद है कि यह किसी खोज इंजन के माध्यम से इस परिणाम को खोजने के लिए उपयोगी होगा।

SQL सर्वर 2008 के साथ, एक नया फ़ंक्शन पेश किया गया है CRYPT_GEN_RANDOM(8), जो क्रिप्टोग्राफी का उपयोग क्रिप्टोग्राफिक रूप से मजबूत यादृच्छिक संख्या का उत्पादन करने के लिए करता है, जैसा कि लौटा दिया गया है VARBINARY(8000)। यहाँ दस्तावेज़ पृष्ठ है: https://docs.microsoft.com/en-us/sql/t-sql/functions/crypt-gen-random-transact-sql

तो एक यादृच्छिक संख्या प्राप्त करने के लिए, आप बस फ़ंक्शन को कॉल कर सकते हैं और इसे आवश्यक प्रकार में डाल सकते हैं:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint)

या float-1 और +1 पाने के लिए , आप ऐसा कुछ कर सकते हैं:

select CAST(CRYPT_GEN_RANDOM(8) AS bigint) % 1000000000 / 1000000000.0

13

रैंड () फ़ंक्शन एक ही रैंडम नंबर उत्पन्न करेगा, यदि तालिका का चयन क्वेरी में किया जाता है। यदि आप रैंड फ़ंक्शन के लिए एक बीज का उपयोग करते हैं तो समान लागू होता है। इसे करने का एक वैकल्पिक तरीका, इसका उपयोग कर रहा है:

SELECT ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) AS [RandomNumber]

यहां से जानकारी मिली , जो समस्या को बहुत अच्छी तरह से समझाती है।


5

क्या आपके पास प्रत्येक पंक्ति में पूर्णांक मान है जिसे आप RAND फ़ंक्शन के बीज के रूप में पास कर सकते हैं?

1 और 14 के बीच पूर्णांक प्राप्त करने के लिए मेरा मानना ​​है कि यह काम करेगा:

FLOOR( RAND(<yourseed>) * 14) + 1

यह सिद्धांत रूप में काम करता है, लेकिन व्यवहार में मैंने पाया है कि RAND(<seed>)इसमें मामूली बदलाव के लिए बहुत यादृच्छिक नहीं है <seed>। उदाहरण के लिए एक त्वरित परीक्षण जो मैंने किया: मैंने <seed>184380, 184383, 184386, और संबंधित RAND(<seed>)मान थे: 0.14912, 0.14917, 0.14923।
ImaginaryHuman072889

शायद कुछ अधिक "प्रतीत होता है" यादृच्छिक परिणाम प्राप्त करने के लिए, कुछ इस तरह की कोशिश करें:RAND(<seed>)*100000) - FLOOR(RAND(<seed>)*100000)
काल्पनिक

5

यदि आपको अपने बीज को संरक्षित करने की आवश्यकता है ताकि यह हर बार "समान" यादृच्छिक डेटा उत्पन्न करे, तो आप निम्न कार्य कर सकते हैं:

1. एक दृश्य बनाएं जो चुनिंदा रैंड () देता है

if object_id('cr_sample_randView') is not null
begin
    drop view cr_sample_randView
end
go

create view cr_sample_randView
as
select rand() as random_number
go

2. एक यूडीएफ बनाएं जो दृश्य से मूल्य का चयन करता है।

if object_id('cr_sample_fnPerRowRand') is not null
begin
    drop function cr_sample_fnPerRowRand
end
go

create function cr_sample_fnPerRowRand()
returns float
as
begin
    declare @returnValue float
    select @returnValue = random_number from cr_sample_randView
    return @returnValue
end
go

3. अपने डेटा का चयन करने से पहले, रैंड () फ़ंक्शन को बीज दें, और फिर अपने चयनित विवरण में यूडीएफ का उपयोग करें।

select rand(200);   -- see the rand() function
with cte(id) as
(select row_number() over(order by object_id) from sys.all_objects)
select 
    id,
    dbo.cr_sample_fnPerRowRand()
from cte
where id <= 1000    -- limit the results to 1000 random numbers

4

RAND (seedInt) में बीज मान का उपयोग करने का प्रयास करें। रैंड () केवल एक बार प्रति कथन पर अमल करेगा, इसीलिए आप हर बार एक ही नंबर देखते हैं।


सबसे आसान! हालाँकि मान बहुत अधिक बिखरे हुए हैं, उस के बीच से अंकों का उपयोग करते हुए, जैसे RIGHT(CONVERT(BIGINT, RAND(RecNo) * 1000000000000), 2) (ध्यान दें: मैं देख रहा हूं कि मैं RIGHTसंक्षेप में परिवर्तित कर रहा हूं , लेकिन कठोर होने के BIGINTलिए CHAR, आपके पास CONVERTवहां एक और होगा)।
डग_इज़न

4

यदि आपको पूर्णांक बनाने की आवश्यकता नहीं है, लेकिन कोई भी विशिष्ट विशिष्ट पहचानकर्ता, आप उपयोग कर सकते हैं newid()

SELECT table_name, newid() magic_number 
FROM information_schema.tables

4

आपको प्रत्येक पंक्ति के लिए RAND () को कॉल करना होगा। यहाँ एक अच्छा उदाहरण है

https://web.archive.org/web/20090216200320/http://dotnet.org.za/calmyourself/archive/2007/04/13/sql-rand-trap-same-value-per-row.aspx


मृत लिंक :( किसी भी प्रतियां है कि जवाब में शामिल किया जा सकता है?
jocull

वह RAND()एक दृश्य में डालता है SELECT, उस दृश्य को एक फ़ंक्शन में रखता है , और फिर फ़ंक्शन को कहीं से भी कॉल करता है। चतुर।
डग_इवीसन

मैंने एक समाधान पोस्ट किया है जो समस्या को उसी तरह से हल करता है जैसे कि लिंक किए गए लेख में, लेकिन यहां इस ब्लॉग में सीधे उत्तर के रूप में पांच पोस्ट पहले! कोई मुझे चालाक बुलाया ईर्ष्या चेहरा hehe
Mitselplik

4
select round(rand(checksum(newid()))*(10)+20,2)

यहां यादृच्छिक संख्या 20 और 30 के बीच आ roundजाएगी। अधिकतम दो दशमलव स्थान देगा।

यदि आप नकारात्मक संख्या चाहते हैं, तो आप इसे कर सकते हैं

select round(rand(checksum(newid()))*(10)-60,2)

तब न्यूनतम मान -60 और अधिकतम -50 होगा।


3

यह उतना आसान है:

DECLARE @rv FLOAT;
SELECT @rv = rand();

और यह एक तालिका में 0-99 के बीच एक यादृच्छिक संख्या डाल देगा:

CREATE TABLE R
(
    Number int
)

DECLARE @rv FLOAT;
SELECT @rv = rand();

INSERT INTO dbo.R
(Number)
    values((@rv * 100));

SELECT * FROM R

2

मेरे द्वारा कभी-कभी चयनित "उत्तर" के साथ समस्या यह है कि वितरण हमेशा नहीं होता है। यदि आपको बहुत सारी पंक्तियों के बीच यादृच्छिक 1 - 14 के बहुत अधिक वितरण की आवश्यकता है, तो आप कुछ ऐसा कर सकते हैं (मेरे डेटाबेस में 511 टेबल हैं, इसलिए यह काम करता है। यदि आपके पास यादृच्छिक संख्या अवधि की तुलना में कम पंक्तियाँ हैं, तो यह काम नहीं करता है। कुंआ):

SELECT table_name, ntile(14) over(order by newId()) randomNumber 
FROM information_schema.tables

इस तरह का सामान्य यादृच्छिक विलयनों के विपरीत है कि यह संख्याओं को क्रमबद्ध रखता है और दूसरे कॉलम को यादृच्छिक बनाता है।

याद रखें, मेरे डेटाबेस में 511 टेबल हैं (जो केवल b / c के लिए उपयुक्त है, जो हम info_schema से चुन रहे हैं)। यदि मैं पिछली क्वेरी लेता हूं और इसे एक अस्थायी तालिका #X में डालता हूं, और फिर परिणामी डेटा पर इस क्वेरी को चलाता हूं:

select randomNumber, count(*) ct from #X
group by randomNumber

मुझे यह परिणाम मिलता है, मुझे दिखा रहा है कि मेरा यादृच्छिक नंबर बहुत समान रूप से कई पंक्तियों के बीच वितरित किया गया है:

यहां छवि विवरण दर्ज करें


2
select ABS(CAST(CAST(NEWID() AS VARBINARY) AS INT)) as [Randomizer]

हमेशा मेरे लिए काम किया है



1
    DROP VIEW IF EXISTS vwGetNewNumber;
    GO
    Create View vwGetNewNumber
    as
    Select CAST(RAND(CHECKSUM(NEWID())) * 62 as INT) + 1 as NextID,
    'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'as alpha_num;

    ---------------CTDE_GENERATE_PUBLIC_KEY -----------------
    DROP FUNCTION IF EXISTS CTDE_GENERATE_PUBLIC_KEY;  
    GO
    create function CTDE_GENERATE_PUBLIC_KEY()
    RETURNS NVARCHAR(32)
    AS 
    BEGIN
        DECLARE @private_key NVARCHAR(32);
        set @private_key = dbo.CTDE_GENERATE_32_BIT_KEY();
        return @private_key;
    END;
    go

---------------CTDE_GENERATE_32_BIT_KEY -----------------
DROP FUNCTION IF EXISTS CTDE_GENERATE_32_BIT_KEY;  
GO
CREATE function CTDE_GENERATE_32_BIT_KEY()
RETURNS NVARCHAR(32)
AS 
BEGIN
    DECLARE @public_key NVARCHAR(32);
    DECLARE @alpha_num NVARCHAR(62);
    DECLARE @start_index INT = 0;
    DECLARE @i INT = 0;
    select top 1 @alpha_num = alpha_num from vwGetNewNumber;
        WHILE @i < 32
        BEGIN
          select top 1 @start_index = NextID from vwGetNewNumber;
          set @public_key = concat (substring(@alpha_num,@start_index,1),@public_key);
          set @i = @i + 1;
        END;
    return @public_key;
END;
    select dbo.CTDE_GENERATE_PUBLIC_KEY() public_key;

क्षमा करें @ अगर मैं अच्छी तरह से समझाया नहीं,
ichak khoury

क्षमा करें @arnt, हमारे यहाँ दो कार्य हैं CTDE_GENERATE_32_BIT_KEY जो एक 32 बिट अल्फ़ान्यूमेरिक कुंजी उत्पन्न करता है (इसे अधिक या कम बढ़ाया जा सकता है) और दूसरा जिसे CTDE_GENERATE_PUBLIC_KEY कहा जाता है जो पहले फ़ंक्शन को कॉल करता है और 32 बिट की सार्वजनिक कुंजी लौटाता है या आप वापस कर सकते हैं 16 बिट की एक निजी कुंजी ... आपको बस एक सार्वजनिक कुंजी के रूप में dbo.CTDE_GENERATE_PUBLIC_KEY () कॉल करने की आवश्यकता है ; इसके पीछे तर्क यह है कि हम अल्फ़ान्यूमेरिक वर्ण सूची से एक वर्ण को 32 बार चुनते हैं और यादृच्छिक अल्फ़ान्यूमेरिक कुंजी प्राप्त करने के लिए उन्हें एक साथ मिलाते हैं। अनुसंधान के बाद।
ichak khoury

अच्छा लगा। यह स्पष्टीकरण इसे बेहतर उत्तर देता है। (किसी व्यक्ति ने हटाने के लिए चिह्नित कर;। मैं इसे खुला छोड़ने के लिए मतदान किया और आप के लिए है कि टिप्पणी की है)
ARNT

0

इसे इस्तेमाल करे:

SELECT RAND(convert(varbinary, newid()))*(b-a)+a magic_number 

जहां aकम संख्या है और bऊपरी संख्या है


1
क्या आप किसी प्रश्न का उत्तर देते समय अधिक स्पष्ट होने का प्रयास कर सकते हैं?
यूनुस टेमुरलेनक

0
Update my_table set my_field = CEILING((RAND(CAST(NEWID() AS varbinary)) * 10))

1 और 10 के बीच की संख्या।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.