sqlite
নিম্নলিখিত স্কিমা সহ আমার একটি টেবিল রয়েছে:
CREATE TABLE foo (bar VARCHAR)
আমি স্ট্রিং হিসাবে স্ট্রিংয়ের তালিকার জন্য এই টেবিলটি ব্যবহার করছি।
আমি এই টেবিল থেকে এলোমেলো সারিটি কীভাবে নির্বাচন করব?
sqlite
নিম্নলিখিত স্কিমা সহ আমার একটি টেবিল রয়েছে:
CREATE TABLE foo (bar VARCHAR)
আমি স্ট্রিং হিসাবে স্ট্রিংয়ের তালিকার জন্য এই টেবিলটি ব্যবহার করছি।
আমি এই টেবিল থেকে এলোমেলো সারিটি কীভাবে নির্বাচন করব?
উত্তর:
একটি এসকিউএল টেবিল থেকে একটি এলোমেলো সারি নির্বাচন করার জন্য একবার দেখুন
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);
তারপরে, সাময়িকী, টেবিলটি এলোমেলো_ফুতে আবার পূরণ করুন
delete from random_foo;
insert into random_foo select id from foo;
এবং এলোমেলো সারিটি নির্বাচন করতে, আপনি আমার প্রথম পদ্ধতিটি ব্যবহার করতে পারেন (এখানে কোনও ছিদ্র নেই)। অবশ্যই, এই শেষ পদ্ধতিটিতে কিছুসংগত সমস্যা রয়েছে, তবে এলোমেলোভাবে পুনরায় বিল্ডিং একটি রক্ষণাবেক্ষণ অপারেশন যা সম্ভবত খুব সম্ভবত ঘটে না।
তবুও, অন্য একটি উপায়, যা আমি সম্প্রতি একটি মেলিং তালিকায় পেয়েছি তা হ'ল মুছে ফেলার জন্য একটি ট্রিগার স্থাপন করা যাতে সর্বাধিক রোউইডযুক্ত সারিটি বর্তমান মুছে ফেলা সারিটিতে সরিয়ে নেওয়া হয়, যাতে কোনও ছিদ্র না থাকে।
সবশেষে, নোট করুন যে রোউইড এবং একটি পূর্ণসংখ্যার প্রাথমিক কী স্বতঃসংশোধনের আচরণটি অভিন্ন নয় (সারিউডের সাথে, যখন একটি নতুন সারি সন্নিবেশ করা হয়, সর্বাধিক (রোউইড) +1 নির্বাচন করা হয়, তবে এটি হিজেস্ট-মান-সর্বদা-দেখা +1 হয় একটি প্রাথমিক কী), সুতরাং শেষ সমাধানটি এলোমেলো_ফুতে স্বতঃসংশোধনের সাথে কাজ করবে না, তবে অন্যান্য পদ্ধতিগুলি তা করবে।
SELECT max(rowid) + 1
একটি ধীর ক্যোয়ারী হবে - এটির জন্য একটি পূর্ণ টেবিল স্ক্যান প্রয়োজন। স্ক্লাইট শুধুমাত্র ক্যোরিটি অনুকূল করে 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, এন) এবং
SELECT * FROM foo LIMIT 1 OFFSET m;
এমনকি আপনি প্রথম সংখ্যাটি ( এন ) কোথাও সংরক্ষণ করতে পারেন এবং ডাটাবেস গণনা পরিবর্তিত হলেই এটি আপডেট করতে পারেন। এইভাবে আপনাকে প্রতিবার SELECT COUNT করতে হবে না।
OFFSET
অফসেটের আকারের উপর নির্ভর করে এটির সন্ধানের জন্য প্রয়োজনীয় সময়টি মনে হচ্ছে - সারি 2 দ্রুত, সারি 2 মিলিয়ন কিছু সময় নেয়, এমনকি যখন সমস্ত ডেটা স্থির-আকার হয় এবং এটি এটি সরাসরি অনুসন্ধান করতে সক্ষম হওয়া উচিত। কমপক্ষে, এটি এসকিউএলাইট 3.7.13 এর মতো দেখাচ্ছে।
SELECT bar
FROM foo
ORDER BY Random()
LIMIT 1
এখানে @ অঙ্কুর সমাধানের একটি পরিবর্তন রয়েছে:
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
আমি বড় স্ক্যালিটি 3 ডাটাবেসের জন্য নিম্নলিখিত সমাধানটি নিয়ে এসেছি :
SELECT * FROM foo WHERE rowid = abs(random()) % (SELECT max(rowid) FROM foo) + 1;
অ্যাবস (এক্স) ফাংশনটি X টির সাথে সংখ্যার আর্গুমেন্টের পরম মান প্রদান করে
এলোমেলো () ফাংশনটি -9223372036854775808 এবং +9223372036854775807 এর মধ্যে একটি সিউডো-এলোমেলো পূর্ণসংখ্যা প্রদান করে।
অপারেটর% এর বাম অপারেন্ডের পূর্ণসংখ্যার মানটি তার ডান অপারেণ্ডের পরিবর্তিত করে।
অবশেষে, আপনি 0 এর সমান রোয়িড প্রতিরোধ করতে +1 যুক্ত করুন।