मैं SQL में यादृच्छिक संख्या के साथ एक कॉलम कैसे भर सकता हूं? मुझे हर पंक्ति में समान मूल्य मिलता है


84
UPDATE CattleProds
SET SheepTherapy=(ROUND((RAND()* 10000),0))
WHERE SheepTherapy IS NULL

अगर मैं एक चयन करता हूं तो मैं देखता हूं कि मेरी यादृच्छिक संख्या हर पंक्ति में समान है । किसी भी विचार कैसे अद्वितीय यादृच्छिक संख्या उत्पन्न करने के लिए?

जवाबों:


167

इसके बजाय rand(), उपयोग करें newid(), जो परिणाम में प्रत्येक पंक्ति के लिए पुनर्गणना है। सामान्य तरीका चेकसम के मोडुलो का उपयोग करना है। ध्यान दें कि checksum(newid())-2,147,483,648 का उत्पादन कर सकते हैं और पूर्णांक अतिप्रवाह का कारण बन सकते हैं abs(), इसलिए हमें इसे पूर्ण मान में परिवर्तित करने से पहले चेकसम रिटर्न मान पर मॉडुलो का उपयोग करने की आवश्यकता है।

UPDATE CattleProds
SET    SheepTherapy = abs(checksum(NewId()) % 10000)
WHERE  SheepTherapy IS NULL

यह 0 और 9999 के बीच एक यादृच्छिक संख्या उत्पन्न करता है।


1
यह प्रश्न / उत्तर सहायक भी हो सकता है: stackoverflow.com/a/9039661/47226
हारून हॉफमैन

यह मेरे लिए बिल्कुल भी काम नहीं कर रहा है। क्या कॉलम को INT होना चाहिए? हर बार त्रुटि # 1064। पागल गोलियों के लिए पहुँच रहा है ...
फ्रीवेल्ड जुड

1
यह सुंदरता की बात है! बहुत बढ़िया। इसे प्यार करना। एक छोटा सा धीमा प्रदर्शन, लेकिन अभी भी महान।
अरविन आमिर

25

यदि आप SQL Server 2008 पर हैं, तो आप भी उपयोग कर सकते हैं

 CRYPT_GEN_RANDOM(2) % 10000

जो कुछ हद तक सरल लगता है (यह प्रति पंक्ति के अनुसार एक बार मूल्यांकन किया जाता newidहै - नीचे दिखाया गया है)

DECLARE @foo TABLE (col1 FLOAT)

INSERT INTO @foo SELECT 1 UNION SELECT 2

UPDATE @foo
SET col1 =  CRYPT_GEN_RANDOM(2) % 10000

SELECT *  FROM @foo

रिटर्न (2 यादृच्छिक शायद अलग-अलग संख्या)

col1
----------------------
9693
8573

अस्पष्टीकृत को कम करने का एकमात्र वैध कारण है जिसके बारे में मैं सोच सकता हूं, वह यह है कि उत्पन्न यादृच्छिक संख्या 0-65535 के बीच है जो 10,000 से समान रूप से विभाज्य नहीं है, कुछ संख्याओं का प्रतिनिधित्व थोड़ा अधिक होगा। इसका एक तरीका यह होगा कि इसे एक स्केलर यूडीएफ में लपेटा जाए जो किसी भी संख्या को 60,000 से अधिक दूर फेंक देता है और एक प्रतिस्थापन संख्या प्राप्त करने के लिए खुद को पुनरावर्ती कहता है।

CREATE FUNCTION dbo.RandomNumber()
RETURNS INT
AS
  BEGIN
      DECLARE @Result INT

      SET @Result = CRYPT_GEN_RANDOM(2)

      RETURN CASE
               WHEN @Result < 60000
                     OR @@NESTLEVEL = 32 THEN @Result % 10000
               ELSE dbo.RandomNumber()
             END
  END  

1
@downvoter - कोई विशेष कारण? हो सकता है कि आप ऊपर तीर मारने का मतलब है कि यह उत्तर ठीक काम करता है!
मार्टिन स्मिथ

सभी को यह याद आ रहा है कि यह विधि प्रदर्शन के लिए बेहतर है। मैं NEWID () के लिए एक विकल्प की तलाश कर रहा हूं और यह स्पॉट पर है, धन्यवाद!
डिग्स

किसी भी वांछित रेंज से आसानी से निपटा जा सकता है। उदाहरण के लिए ABS (CASTPT_GEN_RANDOM (8) AS BIGINT)% 10001) 0-10000 से एक नंबर प्राप्त करता है, जो कि ओपी का कोड उत्पन्न होता है यदि यह उसी तरह से काम करता है जैसे कि वे उम्मीद करते थे।
bielawski

कौन सा 'वही' मुद्दा? सूत्र प्रति पंक्ति (op की समस्या हल) में नए मान उत्पन्न करता है और परिणाम सीमा के भीतर होता है, लेकिन उन्हें तिरछा नहीं किया जाएगा क्योंकि 64 बिट्स बीज होते हैं और परिणाम के केवल 14 बिट्स होते हैं इसलिए कोई भी संभावित तिरछा undetectable होगा। यहां तक ​​कि अगर आप 10 ^ 15 परिणाम उत्पन्न करते हैं तो कोई भी तिरछा हो सकता है जो आपको लगता है कि आप पता लगा रहे हैं कि अभी भी त्रुटि के दायरे में होगा। मतलब आपको यह साबित करने के लिए 2 ^ 19 परिणाम उत्पन्न करने होंगे कि वास्तव में तिरछा अस्तित्व में था।
bielawski

9

जबकि मुझे CHECKSUM का उपयोग करना पसंद है, मुझे लगता है कि जाने के लिए एक बेहतर तरीका उपयोग कर रहा है NEWID(), सिर्फ इसलिए कि आपको सरल संख्या उत्पन्न करने के लिए जटिल गणित से गुजरना नहीं पड़ता है।

ROUND( 1000 *RAND(convert(varbinary, newid())), 0)

आप 1000जिस भी सीमा के साथ सेट करना चाहते हैं, उसकी जगह ले सकते हैं, और आप हमेशा एक सीमा बनाने के लिए एक प्लस चिह्न का उपयोग कर सकते हैं, मान लें कि आप के बीच एक यादृच्छिक संख्या चाहते हैं 100और 200, आप कुछ ऐसा कर सकते हैं:

100 + ROUND( 100 *RAND(convert(varbinary, newid())), 0)

इसे अपनी क्वेरी में एक साथ रखना:

UPDATE CattleProds 
SET SheepTherapy= ROUND( 1000 *RAND(convert(varbinary, newid())), 0)
WHERE SheepTherapy IS NULL

1

मैंने प्रत्येक के साथ 100,000,000 पंक्तियों को उत्पन्न करके RAND () के खिलाफ 2 सेट आधारित यादृच्छिककरण विधियों का परीक्षण किया। फ़ील्ड को समतल करने के लिए आउटपुट रैंड (नकल) से 0-1 के बीच एक फ्लोट है। अधिकांश कोड बुनियादी सुविधाओं का परीक्षण कर रहे हैं, इसलिए मैं यहां एल्गोरिदम को संक्षेप में प्रस्तुत करता हूं:

-- Try #1 used
(CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val
-- Try #2 used
RAND(Checksum(NewId()))
-- and to have a baseline to compare output with I used
RAND() -- this required executing 100000000 separate insert statements

CRYPT_GEN_RANDOM का उपयोग करना स्पष्ट रूप से सबसे यादृच्छिक था क्योंकि 10 ^ 18 नंबर के सेट से 10 ^ 8 नंबर को फेकने पर केवल 1 डुप्लिकेट देखने का केवल .000000001% मौका है। IOW हमें कोई डुप्लिकेट नहीं देखना चाहिए था और यह कोई भी नहीं था! इस सेट को मेरे लैपटॉप पर बनाने में 44 सेकंड का समय लगा।

Cnt     Pct
-----   ----
 1      100.000000  --No duplicates

SQL सर्वर निष्पादन समय: CPU समय = 134795 ms, बीता समय = 39274 ms।

IF OBJECT_ID('tempdb..#T0') IS NOT NULL DROP TABLE #T0;
GO
WITH L0   AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c))  -- 2^4  
    ,L1   AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B)    -- 2^8  
    ,L2   AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B)    -- 2^16  
    ,L3   AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B)    -- 2^32  
SELECT TOP 100000000 (CAST(CRYPT_GEN_RANDOM(8) AS BIGINT)%500000000000000000+500000000000000000.0)/1000000000000000000 AS Val
  INTO #T0
  FROM L3;

 WITH x AS (
     SELECT Val,COUNT(*) Cnt
      FROM #T0
     GROUP BY Val
)
SELECT x.Cnt,COUNT(*)/(SELECT COUNT(*)/100 FROM #T0) Pct
  FROM X
 GROUP BY x.Cnt;

परिमाण के लगभग 15 ऑर्डर कम यादृच्छिक रूप से यह विधि दो बार तेजी से नहीं थी, 100M संख्या उत्पन्न करने में केवल 23 सेकंड लगते हैं।

Cnt  Pct
---- ----
1    95.450254    -- only 95% unique is absolutely horrible
2    02.222167    -- If this line were the only problem I'd say DON'T USE THIS!
3    00.034582
4    00.000409    -- 409 numbers appeared 4 times
5    00.000006    -- 6 numbers actually appeared 5 times 

SQL सर्वर निष्पादन समय: CPU समय = 77156 ms, बीता समय = 24613 ms।

IF OBJECT_ID('tempdb..#T1') IS NOT NULL DROP TABLE #T1;
GO
WITH L0   AS (SELECT c FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c))  -- 2^4  
    ,L1   AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B)    -- 2^8  
    ,L2   AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B)    -- 2^16  
    ,L3   AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B)    -- 2^32  
SELECT TOP 100000000 RAND(Checksum(NewId())) AS Val
  INTO #T1
  FROM L3;

WITH x AS (
    SELECT Val,COUNT(*) Cnt
     FROM #T1
    GROUP BY Val
)
SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T1) Pct
  FROM X
 GROUP BY x.Cnt;

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

Cnt  Pct
---- ----
1    99.768020
2    00.115840
3    00.000100  -- at least there were comparitively few values returned 3 times

पुनरारंभ के कारण, निष्पादन समय पर कब्जा नहीं किया जा सका।

IF OBJECT_ID('tempdb..#T2') IS NOT NULL DROP TABLE #T2;
GO
CREATE TABLE #T2 (Val FLOAT);
GO
SET NOCOUNT ON;
GO
INSERT INTO #T2(Val) VALUES(RAND());
GO 100000000

WITH x AS (
    SELECT Val,COUNT(*) Cnt
     FROM #T2
    GROUP BY Val
)
SELECT x.Cnt,COUNT(*)*1.0/(SELECT COUNT(*)/100 FROM #T2) Pct
  FROM X
 GROUP BY x.Cnt;

पुनश्च सोच रहा था कि पुनरारंभ कुछ डुप्लिकेट के लिए जिम्मेदार हो सकता है मैंने जल्दी से सिर्फ 3M पंक्तियों का परीक्षण किया जो लगभग 6-1 / 2 मिनट लगा। मुझे 2101 डुप्लिकेट मिले और 2 मान 3 बार (.07% और .000067% क्रमशः) दिखाई दिए, जिसमें संकेत मिलता है कि शायद एक हिस्सा खेला गया था, लेकिन यादृच्छिकता अभी भी तारकीय से दूर है।
बिलावस्की

एक दूसरे के जवाब पर गौर करने के बाद सिर्फ न्यूड के साथ बीजगणित में परिवर्तन किया गया, इसलिए मैंने भी यही कोशिश की। न केवल यह चेकसम का उपयोग करने की तुलना में तेज़ है, बल्कि उस परीक्षण में एक मान 8 बार दिखाई देता है। निष्पक्ष होने के लिए, यह अभी भी 95.447319% अद्वितीय था जो केवल मेरे परीक्षण में रैंड (चेकसम (न्यूआईड ())) के 95.450254% से मुश्किल से भी बदतर है। एक दूसरे निष्पादन ने 5 बार और 95.452929% अलग दिखने वाले 3 नंबरों की सबसे खराब स्थिति पैदा की, इसलिए 100M पंक्तियों का परीक्षण करते समय भी YMMV।
bielawski

-2
require_once('db/connect.php');

//rand(1000000 , 9999999);

$products_query = "SELECT id FROM products";
$products_result = mysqli_query($conn, $products_query);
$products_row = mysqli_fetch_array($products_result);
$ids_array = [];

do
{
    array_push($ids_array, $products_row['id']);
}
while($products_row = mysqli_fetch_array($products_result));

/*
echo '<pre>';
print_r($ids_array);
echo '</pre>';
*/
$row_counter = count($ids_array);

for ($i=0; $i < $row_counter; $i++)
{ 
    $current_row = $ids_array[$i];
    $rand = rand(1000000 , 9999999);
    mysqli_query($conn , "UPDATE products SET code='$rand' WHERE id='$current_row'");
}

शायद यह सही नहीं है और easylest तरीका है, लेकिन यह काम करता है)))
Vaso Nadiradze

1
उत्तर देने से पहले कृपया प्रश्न को ध्यान से पढ़ें। वैसे, प्रत्येक पंक्ति के लिए एक अलग क्वेरी भेजने के लिए एक बहुत, बहुत बुरा विचार है जब एक पंक्ति को भी सीमित करने के लिए है।
दुलोवे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.