डेटाबेस तालिका से यादृच्छिक रिकॉर्ड (T-SQL)


85

वहाँ एक sql सर्वर तालिका से एक यादृच्छिक रिकॉर्ड प्राप्त करने के लिए एक सफल तरीका है?

मैं अपनी इकाई परीक्षण डेटा को यादृच्छिक बनाना चाहूंगा, इसलिए एक तालिका से एक यादृच्छिक आईडी का चयन करने का एक सरल तरीका खोज रहा हूं। अंग्रेजी में, चयन "तालिका से एक आईडी का चयन करें जहां आईडी तालिका में सबसे कम आईडी और तालिका में उच्चतम आईडी के बीच एक यादृच्छिक संख्या है।"

मैं क्वेरी चलाने के लिए, शून्य मान के लिए परीक्षण किए बिना इसे करने का एक तरीका समझ नहीं सकता, फिर यदि शून्य है तो फिर से चलाएं।

विचार?


यहाँ तरीकों की एक जोड़ी के रूप में brettb.com/SQL_Help_Random_Numbers.asp
मेष

2
क्या आप वाकई इस दृष्टिकोण को लेना चाहते हैं? यूनिट टेस्ट डेटा यादृच्छिक नहीं होना चाहिए - वास्तव में, आपको एक ही परिणाम प्राप्त करने की गारंटी दी जानी चाहिए चाहे आप कितनी बार यूनिट टेस्ट निष्पादित करें। यादृच्छिक डेटा होने से इकाई परीक्षण के इस मूल सिद्धांत का उल्लंघन हो सकता है।
लगाम

@Mesh से ऊपर का लिंक अब सक्रिय नहीं है।
रॉबर्ट सेवर्स

जवाबों:


145

वहाँ एक sql सर्वर तालिका से एक यादृच्छिक रिकॉर्ड प्राप्त करने के लिए एक सफल तरीका है?

हाँ

SELECT TOP 1 * FROM table ORDER BY NEWID()

व्याख्या

NEWID()प्रत्येक पंक्ति के लिए A उत्पन्न होता है और तालिका इसके द्वारा क्रमबद्ध होती है। पहला रिकॉर्ड वापस आ गया है (यानी "सबसे कम" GUID के साथ रिकॉर्ड)।

टिप्पणियाँ

  1. GUIDs चार संस्करण के बाद से छद्म यादृच्छिक संख्याओं के रूप में उत्पन्न होते हैं:

    संस्करण 4 यूयूआईडी यूयूआईडी को सही मायने में यादृच्छिक या छद्म यादृच्छिक संख्याओं से उत्पन्न करने के लिए है।

    एल्गोरिथ्म इस प्रकार है:

    • घड़ी के दो सबसे महत्वपूर्ण बिट्स (बिट्स 6 और 7) को क्रमशः शून्य और एक पर सेट करें।
    • धारा 4.1.3 से 4-बिट संस्करण संख्या में time_hi_and_version फ़ील्ड के चार सबसे महत्वपूर्ण बिट्स (15 के माध्यम से 12) सेट करें।
    • सभी अन्य बिट्स को बेतरतीब ढंग से (या छद्म-बेतरतीब ढंग से) चुने हुए मूल्यों के लिए सेट करें।

    - एक यूनिवर्सली यूनिक आइडेंटिफायर (UUID) URN Namespace - RFC 4122

  2. विकल्प SELECT TOP 1 * FROM table ORDER BY RAND()काम नहीं करेगा जैसा कि कोई सोचता है। RAND()प्रति क्वेरी में एक एकल मान लौटाता है, इस प्रकार सभी पंक्तियाँ समान मान साझा करेंगी।

  3. जबकि GUID मान छद्म यादृच्छिक होते हैं, आपको अधिक मांग वाले अनुप्रयोगों के लिए बेहतर PRNG की आवश्यकता होगी।

  4. लगभग 100,000 पंक्तियों के लिए विशिष्ट प्रदर्शन 10 सेकंड से कम है - बेशक सिस्टम पर निर्भर करता है। ध्यान दें कि सूचकांक को हिट करना असंभव है, इस प्रकार प्रदर्शन अपेक्षाकृत सीमित होगा।


ठीक वही जो मेरे द्वारा खोजा जा रहा था। मुझे ऐसा लग रहा था कि मैं इसे बना रही हूं।
जेरेमी

1
आप मान रहे हैं कि NEWID छद्म आयामी मूल्यों का उत्पादन करता है। एक अच्छा मौका है कि यह अनुक्रमिक मूल्यों का उत्पादन करेगा। NEWID केवल अनूठे मान पैदा करता है। हालांकि, रैंड छद्म यादृच्छिक मूल्यों का उत्पादन करता है।
स्किज़

मैं इसे 1,671,145 पंक्तियों के साथ एक भारी अनुक्रमित तालिका पर चला रहा हूं, और इसे वापस आने में 7 सेकंड लगते हैं। तालिका बहुत इष्टतम है - यह वस्तुतः हमारे डेटाबेस का दिल है इसलिए इसका ध्यान रखा जाता है।
टॉम रिटर

@ ÂviewAnew। 1.6 मिलियन पंक्तियों और 7 सेकेंड्स एक ऐसे चयन पर जो एक इंडेक्स को हिट नहीं कर सकता (और नहीं कर सकता) खराब नहीं है।
स्किलेव्ज़

7
@Skizz, रैंड उस तरह से काम नहीं करता है। चयन से पहले एक एकल यादृच्छिक मान उत्पन्न होता है। इसलिए यदि आप "SELECT TOP 10 RAND () ..." को
आजमाते

27

बड़ी तालिकाओं पर आप TABLESAMPLEपूरे तालिका को स्कैन करने से बचने के लिए इसका उपयोग कर सकते हैं ।

SELECT  TOP 1 *
FROM YourTable
TABLESAMPLE (1000 ROWS)
ORDER BY NEWID()

ORDER BY NEWIDअभी भी सिर्फ लौटने पंक्तियों डेटा पृष्ठ पर पहले दिखाई देते हैं से बचने के लिए आवश्यक है।

तालिका के आकार और परिभाषा के लिए उपयोग की जाने वाली संख्या को सावधानीपूर्वक चुना जाना चाहिए और यदि कोई पंक्ति वापस नहीं की जाती है, तो आप पुन: प्रयास कर सकते हैं। इसके पीछे के गणित और तकनीक छोटे तालिकाओं के अनुकूल क्यों नहीं है पर यहां चर्चा की गई है


मुझे यह Microsoft की वेबसाइट पर मिला: आप TABLESAMPLE का उपयोग तब कर सकते हैं जब किसी नमूने को बड़ी तालिका से जल्दी से लौटाया जा सके, जब निम्न में से कोई भी स्थिति सत्य हो: नमूना को अलग-अलग पंक्तियों के स्तर पर वास्तव में यादृच्छिक नमूना होने की आवश्यकता नहीं है। तालिका के अलग-अलग पृष्ठों पर पंक्तियों को एक ही पृष्ठ पर अन्य पंक्तियों के साथ संबद्ध नहीं किया जाता है।
मार्क एनिंगह

1
@MarkEntingh - इसके मामले में TOP 1कोई फर्क नहीं पड़ता कि एक ही पृष्ठ पर पंक्तियाँ सहसंबद्ध हैं या नहीं। आप केवल उनमें से एक उठा रहे हैं।
मार्टिन स्मिथ

9

इसके अलावा MIN (Id) और MAX (Id) के बीच एक यादृच्छिक आईडी प्राप्त करने के लिए अपनी विधि का प्रयास करें और फिर

SELECT TOP 1 * FROM table WHERE Id >= @yourrandomid

यह आपको हमेशा एक पंक्ति में मिलेगा।


2
-1, यह केवल तभी काम करेगा जब मिन और मैक्स के बीच कोई गुम आईडी न हो। यदि कोई हटा दिया जाता है, तो उसी आईडी को यादृच्छिक फ़ंक्शन द्वारा उत्पन्न किया जाता है, तो आपको शून्य रिकॉर्ड वापस मिल जाएगा।
नील एन

6
@ नील, वास्तव में नहीं - यह आपको आईडी के साथ पहली पंक्ति मिलेगी यदि यादृच्छिक संख्या से अधिक है यदि लापता आइडी हैं। यहां समस्या यह है कि प्रत्येक पंक्ति के बाहर आने की संभावना स्थिर नहीं है। लेकिन फिर यह ज्यादातर मामलों में ग्रस्त है।
स्किलिविज़

1
+1। यूनिट टेस्टिंग के लिए, अलग-अलग वैल्यूज़ को हिट करना चाहिए जो काफी अच्छा है - अगर आपको असली रैंडम की आवश्यकता है, तो यह कुछ और है। लेकिन ओपी संदर्भ में यह काफी अच्छा होना चाहिए।
टॉमटॉम

7

यदि आप बड़े डेटा का चयन करना चाहते हैं तो मुझे पता है कि:

SELECT * FROM Table1
WHERE (ABS(CAST(
    (BINARY_CHECKSUM
    (keycol1, NEWID())) as int))
    % 100) < 10

स्रोत: MSDN


मुझे यकीन नहीं है, लेकिन मुझे लगता है कि चुनिंदा प्रक्रिया में NEWID () का उपयोग करने के नुकसान के कारण रैंड () के बजाय NEWID () का उपयोग सही मायने में यादृच्छिक संख्या उत्पन्न करने के लिए बेहतर हो सकता है।
QMaster

मैं इस पद्धति का उपयोग प्रतिशत रिकॉर्ड की सटीक संख्या के बजाय प्रतिशत आधार के साथ करने की कोशिश करता हूं, मैंने इसे चयन सीमा का विस्तार करने और TOP n के साथ सीमित करने के साथ किया है, क्या कोई सुझाव है?
QMaster

मुझे इस परिदृश्य के साथ एक और समस्या मिली, यदि आप समूह का उपयोग करते हैं, तो आपको यादृच्छिक रूप से चयनित पंक्तियों का क्रम हमेशा मिलेगा, इसलिए ऐसा लगता है कि छोटे तालिकाओं में @skilvvz दृष्टिकोण सबसे उचित है।
QMaster

0

मैं उन तरीकों पर सुधार करना चाह रहा था जो मैंने कोशिश की थीं और इस पद पर आए थे। मुझे लगता है कि यह पुराना है लेकिन यह तरीका सूचीबद्ध नहीं है। मैं परीक्षण डेटा बना रहा हूं और लागू कर रहा हूं; यह @st (दो चार राज्य) के साथ कहे गए SP में "पता" के लिए विधि दिखाता है

Create Table ##TmpAddress (id Int Identity(1,1), street VarChar(50), city VarChar(50), st VarChar(2), zip VarChar(5))
Insert Into ##TmpAddress(street, city, st, zip)
Select street, city, st, zip 
From tbl_Address (NOLOCK)
Where st = @st


-- unseeded RAND() will return the same number when called in rapid succession so
-- here, I seed it with a guaranteed different number each time. @@ROWCOUNT is the count from the most recent table operation.

Set @csr = Ceiling(RAND(convert(varbinary, newid())) * @@ROWCOUNT)

Select street, city, st, Right(('00000' + ltrim(zip)),5) As zip
From ##tmpAddress (NOLOCK)
Where id = @csr

0

यदि आप वास्तव में व्यक्तिगत पंक्तियों का एक यादृच्छिक नमूना चाहते हैं, तो TABLESAMPLE का उपयोग करने के बजाय, पंक्तियों को यादृच्छिक रूप से फ़िल्टर करने के लिए अपनी क्वेरी को संशोधित करें। उदाहरण के लिए, निम्न क्वेरी बिक्री के लगभग एक प्रतिशत पंक्तियों को वापस करने के लिए NEWID फ़ंक्शन का उपयोग करती है। SalesOrderDetail Table:

SELECT * FROM Sales.SalesOrderDetail
WHERE 0.01 >= CAST(CHECKSUM(NEWID(), SalesOrderID) & 0x7fffffff AS float)
/ CAST (0x7fffffff AS int)

SalesOrderID कॉलम CHECKSUM अभिव्यक्ति में शामिल है ताकि NEWID () प्रति पंक्ति के आधार पर नमूना प्राप्त करने के लिए प्रति पंक्ति एक बार मूल्यांकन करे। अभिव्यक्ति CAST (CHECKSUM (NEWID), SalesOrderID) और 0x7fffffff AS फ्लोट / CAST (0x7fffffff AS int) 0 और 1. के बीच एक यादृच्छिक फ्लोट मान का मूल्यांकन करता है।

स्रोत: http://technet.microsoft.com/en-us/library/ms189108(v=sql.105s.nx

इसे और नीचे समझाया गया है:

यह कैसे काम करता है? आइए WHERE क्लॉज को विभाजित करें और इसे समझाएं।

चेक फ़ंक्शन सूची में आइटम पर एक चेकसम की गणना कर रहा है। यह तर्कपूर्ण है कि क्या SalesOrderID की भी आवश्यकता है, क्योंकि NEWID () एक ऐसा फ़ंक्शन है जो एक नया यादृच्छिक GUID लौटाता है, इसलिए किसी यादृच्छिक रैंडम को एक स्थिर से गुणा करने पर किसी भी मामले में यादृच्छिक परिणाम प्राप्त होना चाहिए। वास्तव में, SalesOrderID को छोड़कर कोई फर्क नहीं पड़ता है। यदि आप एक उत्सुक सांख्यिकीविद् हैं और इसे शामिल करने का औचित्य साबित कर सकते हैं, तो कृपया नीचे टिप्पणी अनुभाग का उपयोग करें और मुझे बताएं कि मैं गलत क्यों हूं!

चेक फ़ंक्शन एक वार्बिनरी देता है। द्विआधारी और 0x7fffffff के साथ संचालन करना, जो कि बाइनरी में (111111111 ...) के बराबर है, एक दशमलव मान प्राप्त करता है जो प्रभावी रूप से 0 और 1s के यादृच्छिक स्ट्रिंग का प्रतिनिधित्व करता है। सह-कुशल 0x7fffffff द्वारा विभाजित करना प्रभावी रूप से इस दशमलव आकृति को 0 और 1. के बीच के आंकड़े तक सामान्य कर देता है, फिर यह तय करने के लिए कि क्या प्रत्येक पंक्ति अंतिम परिणाम सेट में शामिल करने का गुण है, 1 / x की सीमा का उपयोग किया जाता है (इस मामले में, 0.01) जहां x नमूने के रूप में पुनर्प्राप्त करने के लिए डेटा का प्रतिशत है।

स्रोत: https://www.mssqltips.com/sqlservertip/3157/different-ways-to-get-random-data-for-sql-server-data-sampling

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