मेरे पास sqlite
निम्नलिखित स्कीमा के साथ एक तालिका है:
CREATE TABLE foo (bar VARCHAR)
मैं इस तालिका को स्ट्रिंग की सूची के लिए भंडारण के रूप में उपयोग कर रहा हूं।
मैं इस तालिका से एक यादृच्छिक पंक्ति का चयन कैसे करूं?
मेरे पास sqlite
निम्नलिखित स्कीमा के साथ एक तालिका है:
CREATE TABLE foo (bar VARCHAR)
मैं इस तालिका को स्ट्रिंग की सूची के लिए भंडारण के रूप में उपयोग कर रहा हूं।
मैं इस तालिका से एक यादृच्छिक पंक्ति का चयन कैसे करूं?
जवाबों:
SQLite तालिका से रैंडम पंक्ति का चयन करने पर एक नज़र है
SELECT * FROM table ORDER BY RANDOM() LIMIT 1;
SELECT a.foo FROM a JOIN b ON a.id = b.id WHERE b.bar = 2 ORDER BY RANDOM() LIMIT 1;
मुझे हमेशा एक ही पंक्ति मिलती है।
निम्नलिखित समाधान एक्टास्टिक की तुलना में बहुत तेज हैं (गिनती (*) में बहुत खर्च होता है, लेकिन यदि आप इसे कैश कर सकते हैं, तो अंतर इतना बड़ा नहीं होना चाहिए), जो खुद "यादृच्छिक द्वारा क्रम" () से बहुत तेज है। जब आपके पास बड़ी संख्या में पंक्तियाँ हों, हालाँकि उनके पास कुछ असुविधाएँ हैं।
यदि आपकी राइडिड्स भरी हुई हैं (यानी कुछ डिलीट), तो आप निम्नलिखित कर सकते हैं ( बेहतर प्रदर्शन देने के (select max(rowid) from foo)+1
बजाय max(rowid)+1
, जैसा कि टिप्पणियों में बताया गया है):
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
यदि आपके पास छेद हैं, तो आप कभी-कभी एक गैर-विद्यमान उपद्रवी का चयन करने का प्रयास करेंगे, और चयन एक खाली परिणाम सेट लौटाएगा। यदि यह स्वीकार्य नहीं है, तो आप इस तरह एक डिफ़ॉल्ट मान प्रदान कर सकते हैं:
select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1)) or rowid = (select max(rowid) from node) order by rowid limit 1;
यह दूसरा समाधान सही नहीं है: संभाव्यता का वितरण अंतिम पंक्ति (उच्चतम पंक्ति के साथ एक) पर अधिक है, लेकिन यदि आप अक्सर तालिका में सामान जोड़ते हैं, तो यह एक चलती लक्ष्य बन जाएगा और संभावनाओं का वितरण होना चाहिए काफी बेहतर।
फिर भी एक और समाधान, यदि आप अक्सर बहुत सारे छेद वाली मेज से यादृच्छिक सामान का चयन करते हैं, तो आप एक ऐसी तालिका बनाना चाहते हैं जिसमें मूल तालिका की पंक्तियों को यादृच्छिक क्रम में क्रमबद्ध किया गया हो:
create table random_foo(foo_id);
फिर, आवधिक, तालिका random_foo फिर से भरें
delete from random_foo;
insert into random_foo select id from foo;
और एक यादृच्छिक पंक्ति का चयन करने के लिए, आप मेरी पहली विधि का उपयोग कर सकते हैं (यहां कोई छेद नहीं हैं)। बेशक, इस अंतिम विधि में कुछ समसामयिक समस्याएं हैं, लेकिन random_foo का पुन: निर्माण एक अनुरक्षण ऑपरेशन है जो बहुत बार होने की संभावना नहीं है।
फिर भी, अभी तक एक और तरीका है, जो मुझे हाल ही में एक मेलिंग सूची में मिला है , सबसे बड़ी उपद्रवी के साथ पंक्ति को वर्तमान हटाए गए पंक्ति में स्थानांतरित करने के लिए एक ट्रिगर डालना है, ताकि कोई छेद न बचा हो।
अंतिम रूप से, ध्यान दें कि उपद्रवी और पूर्णांक प्राथमिक कुंजी अभिवाही का व्यवहार समरूप नहीं है (पंक्ति के साथ, जब एक नई पंक्ति सम्मिलित की जाती है, तो अधिकतम (पंक्तिबद्ध) +1 चुना जाता है, जबकि यह हाइगेस्ट-मूल्य-कभी-देखा + 1 है एक प्राथमिक कुंजी), इसलिए अंतिम समाधान random_foo में एक संकेत के साथ काम नहीं करेगा, लेकिन अन्य तरीके होंगे।
SELECT max(rowid) + 1
धीमी क्वेरी होगी - इसके लिए एक पूर्ण तालिका स्कैन की आवश्यकता होती है। sqlite केवल क्वेरी का अनुकूलन करता है SELECT max(rowid)
। इस प्रकार, यह उत्तर इससे बेहतर होगा: select * from foo where rowid = (abs(random()) % (select (select max(rowid) from foo)+1));
इसे अधिक जानकारी के लिए देखें: sqlite.1065341.n5.nabble.com/…
आपको अपनी क्वेरी पर "ऑर्डर द्वारा रैंडम ()" डालने की आवश्यकता है ।
उदाहरण:
select * from quest order by RANDOM();
आइए एक पूर्ण उदाहरण देखें
CREATE TABLE quest (
id INTEGER PRIMARY KEY AUTOINCREMENT,
quest TEXT NOT NULL,
resp_id INTEGER NOT NULL
);
कुछ मूल्यों को सम्मिलित करना:
insert into quest(quest, resp_id) values ('1024/4',6), ('256/2',12), ('128/1',24);
एक डिफ़ॉल्ट चयन:
select * from quest;
| id | quest | resp_id |
1 1024/4 6
2 256/2 12
3 128/1 24
--
एक यादृच्छिक का चयन करें:
select * from quest order by RANDOM();
| id | quest | resp_id |
3 128/1 24
1 1024/4 6
2 256/2 12
--
* हर बार जब आप चुनते हैं, तो ऑर्डर अलग होगा।
यदि आप केवल एक पंक्ति वापस करना चाहते हैं
select * from quest order by RANDOM() LIMIT 1;
| id | quest | resp_id |
2 256/2 12
--
* हर बार जब आप चयन करते हैं, तो रिटर्न अलग होगा।
व्हाट अबाउट:
SELECT COUNT(*) AS n FROM foo;
फिर [0, n) और में एक यादृच्छिक संख्या m चुनें
SELECT * FROM foo LIMIT 1 OFFSET m;
आप पहले नंबर ( n ) को भी कहीं सेव कर सकते हैं और डेटाबेस में बदलाव होने पर ही इसे अपडेट कर सकते हैं। इस तरह आपको हर बार SELECT COUNT नहीं करना है।
OFFSET
ऑफसेट के आकार के आधार पर लगता है कि खोजने के लिए आवश्यक समय है - पंक्ति 2 तेज है, पंक्ति 2 मिलियन थोड़ी देर लगती है, तब भी जब डेटा का सभी डेटा निश्चित आकार का होता है और यह इसे सीधे लेने में सक्षम होना चाहिए। कम से कम, यह वही है जो SQLite 3.7.13 में दिखता है।
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
यहाँ @ ak के समाधान का एक संशोधन है:
SELECT *
FROM table
LIMIT 1
OFFSET ABS(RANDOM()) % MAX((SELECT COUNT(*) FROM table), 1)
यह समाधान अंतराल के साथ सूचकांकों के लिए भी काम करता है, क्योंकि हम एक सीमा में ऑफसेट को यादृच्छिक करते हैं [0, गिनती)। MAX
खाली तालिका के साथ एक मामले को संभालने के लिए उपयोग किया जाता है।
यहां 16k पंक्तियों के साथ एक तालिका पर सरल परीक्षा परिणाम दिए गए हैं:
sqlite> .timer on
sqlite> select count(*) from payment;
16049
Run Time: real 0.000 user 0.000140 sys 0.000117
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
14746
Run Time: real 0.002 user 0.000899 sys 0.000132
sqlite> select payment_id from payment limit 1 offset abs(random()) % (select count(*) from payment);
12486
Run Time: real 0.001 user 0.000952 sys 0.000103
sqlite> select payment_id from payment order by random() limit 1;
3134
Run Time: real 0.015 user 0.014022 sys 0.000309
sqlite> select payment_id from payment order by random() limit 1;
9407
Run Time: real 0.018 user 0.013757 sys 0.000208
मैं बड़े sqlite3 डेटाबेस के लिए निम्नलिखित समाधान के साथ आया :
SELECT * FROM foo WHERE rowid = abs(random()) % (SELECT max(rowid) FROM foo) + 1;
एब्स (X) फ़ंक्शन, संख्यात्मक तर्क X का पूर्ण मान लौटाता है।
यादृच्छिक () फ़ंक्शन -9223372036854775808 और +9223372036854775807 के बीच एक छद्म यादृच्छिक पूर्णांक देता है।
ऑपरेटर% अपने बाएं ऑपरेंड modulo के दाहिने ऑपरेंड के पूर्णांक मान को आउटपुट करता है।
अंत में, आप पंक्ति को 0 के बराबर पंक्ति को रोकने के लिए जोड़ते हैं।