I would like to implement paging for a random set
Select * from Animals ORDER BY random(SEED) LIMIT 100 OFFSET 50
I tried to set int to some integer and to some fracture. Doesn't work.
How do I seed random in sqlite?
I known that a similar question already exists, Seeding SQLite RANDOM(), but I don't understand the PHP solution.
Short answer:
You can't. SQLite's random() function does not support a seed value.
Not so short answer:
Checking SQLite's func.c shows that random() is defined without any parameters..
VFUNCTION(random, 0, 0, 0, randomFunc ),
..and this randomFunc() just calls sqlite3_randomness() (again without any explicit seed value) to obtain a random value of sizeof(sqlite_int64) bytes.
Internally, the implementation of sqlite3_randomness() (see random.c) will set up the RC4 pseudo-random number generator the first time it is used with random seed values obtained from the OS:
/* Initialize the state of the random number generator once,
** the first time this routine is called. The seed value does
** not need to contain a lot of randomness since we are not
** trying to do secure encryption or anything like that...
**
** [..]
*/
if( !wsdPrng.isInit ){
[..]
sqlite3OsRandomness(sqlite3_vfs_find(0), 256, k);
[..]
wsdPrng.isInit = 1;
}
Actually, SQLite's unit test functions themselves just use memcpy() on the global sqlite3Prng struct to save or restore the state of the PRNG during test runs.
So, unless you're willing to do something weird (like create a temporary table of consecutive numbers (1..max(Animals)), shuffle those around and use them to select 'random-seeded' RowIds from your Animals table) I suppose you're out of luck.
I would not usually copy an existing answer, but I can see that you have left a comment asking the author of this answer to explain how it works already a few weeks ago and no explanation has been given. I will therefore copy the relevant part and try to explain whats going on. If this explanation is good, do go and vote on the original answer.
$seed = md5(mt_rand());
$prng = ('0.' . str_replace(array('0', 'a', 'b', 'c', 'd', 'e', 'f'), array('7', '3', '1', '5', '9', '8', '4'), $seed )) * 1;
$query = 'SELECT id, name FROM table ORDER BY (substr(id * ' . $prng . ', length(id) + 2)';
The first two rows are just about creating a seed of a sort. The result is a decimal number with lots of decimals like:
0.54534238371923827955579364758491
Then the sql select uses this number to multiply with the numeric row id of every row in the SQLite table. And then the rows are sorted according to the decimal part of the resulting product. Using fewer decimals, the sort order would look something like this:
row id row id * seed sort order
1 0.545342384 545342384
2 1.090684767 090684767
3 1.636027151 636027151
4 2.181369535 181369535
5 2.726711919 726711919
6 3.272054302 272054302
7 3.817396686 817396686
8 4.362739070 362739070
After sorting this would be the result:
row id row id * seed sort order
2 1.090684767 090684767
4 2.181369535 181369535
6 3.272054302 272054302
8 4.362739070 362739070
1 0.545342384 545342384
3 1.636027151 636027151
5 2.726711919 726711919
7 3.817396686 817396686
In this sample I used only eight rows so the result is not very random looking. With more rows the result will appear more random.
This solution will give you the same order repeatedly as long as:
You use the same seed
No new rows have appeared in the table and no rows have been deleted from the table
I don't know if you're wanting a PHP and iOS solution, but if you are only interested in iOS and dont care much about using the built-in sqlite random() function, you could declare a custom function to use in your queries, one that does take a seed parameter.
sqlite3_create_function(database, "CUSTOM_RANDOM", 1, SQLITE_UTF8, NULL, &CustomRandomSQLite, NULL, NULL);
.
void CustomRandomSQLite(sqlite3_context* context, int argc, sqlite3_value** argv)
{
if(argc == 1 && sqlite3_value_type(argv[0]) == SQLITE_INTEGER)
{
const int seed = sqlite3_value_int(argv[0]);
const int result = ...;
sqlite3_result_int(context, result);
}
else
{
sqlite3_result_error(context, "Invalid", 0);
}
}
.
Select * from Animals ORDER BY CUSTOM_RANDOM(SEED) LIMIT 100 OFFSET 50
I use this for random from seed in my javascript game i am sure you can quite easily convert it to sql
seed: function(max) {
if(typeof this._random === 'undefined') this._random = max; // init on first run
this._random = (this._random * 9301 + 49297) % 233280;
return Math.floor(this._random / (233280.0) * max);
}
Related
I want to generate a unique id in Laravel.
EX: PO-12010001
PO = product,
12 = the month,
01 = the year,
0001 = ID of product.
I have tried googling and the answer is using UUID but could not understand.
Your ID will always be 4 digits at the end, so we can pluck those last four characters using substr(). When you increment that by one, it will lose its padding. So 0001+1=2. We therefor pad it back using str_pad() with a length of four.
$string = 'PO-12010001';
$id = substr($string, -4, 4);
$newID = $id+1;
$newID = str_pad($newID, 4, '0', STR_PAD_LEFT);
echo "PO-1201".$newID;
Live demo at https://3v4l.org/55RTL
Since it is not clear where the last 4 characters (ID of product) come from, there are 2 different outcomes based on their origin, I am assuming that "PO" is a constant in all your products:
1.If you're auto-generating the Product ID:
$id = "PO-".date('my') . substr(uniqid(), 9, 12);
date('my') will return a two-digits form of the current month and a two-digits form of the current year.
uniqid() returns a unique identifier based on the current time in microseconds, the identifier is usually a mix of letters and digits, and it is usually 13 characters long, so we use substr() to only return the last 4 characters of the string.
NOTE: we are using the last characters of uniqid() because they change every millisecond.
2.If you already have a Product ID:
$id = "PO-".date('my') . $product_id;
When like this situation first how you want to make your ID
Item Type
Month
Year
Product ID
Get product type in your controller
if Product = PO /
Service = SE
Create a New Date using PHP
$date2 = date('Y-m-d');
and get date substring with your requirement and get the last id of the product table and concat all the variable and use as Unique ID.
First, I dopn't know. So maybe it has a similar concept. But anyway, user defined+designed unique are most likely not unique.
My recommendation is to let the database create an unique id with the autoincrement feature. This is usually the only way to guarantee unique ideas in a multi tasking environment.
The, in an second step, you can create an human readable id and use it for displaying it at the suer interface. Such query can be something like:
update table set nice_id = concat("prefix-",main_id)
where main_id = $last_inserted_id
... or any other calculation based on counting the the number of same entries since beginning of month.
There are other solutions based on try to create an nice_id, insert it into the database, and if this fails, create the next one .. and loop until successful. But simple integers created by autoincrement are more performant on queries and for keys.
it's called Human code which can be unique identify beside an Id column in db table.
$idColumn = 1;
$dateCode = date('ym');
$newHumanCode = 'PO-'.$dateCode.substr('0000'.$idColumn, -4);
return $newHumanCode;
also you can use randome number instead of use $idColumn,
for example:
$idColumn = mt_rand();
You can use the Laravel ID generator.
First Install it:
composer require haruncpi/laravel-id-generator
Import the class in your controller.
use Haruncpi\LaravelIdGenerator\IdGenerator;
Now simply use it
$prefix = "PO-".date("my");
$id = IdGenerator::generate(['table' => 'your_table_name', 'length' => 11, 'prefix' =>$prefix]);
Output
PO-12010001
PO-12010002
PO-12010003
...
A question struck in my mind for 2 days and wondering whether it is possible to implement this type of tree structure in laravel and MySQL.
(First, take a look at the image attached. Thanks)
Suppose our platform uses refer system, and initially, a user 'A' join. Now, this user 'A' further refers 3 persons 'B','C','D'. Now, the total refer on A is 3 (because it refers 3 persons).
Now, let B further refers 'E','F' and 'C' further refers 'G','H', 'I' and 'D' refers 0. So, now refer of each person is "D = 0", "C = 3", "B = 2". and these refers will also add up on "A". So, it has "A = 8".
Now, 'G' refers 'J', so 'G' gets +1 and 'C' also gets +1 and 'C' is referred by 'A', so 'A' also gets +1. Now, total refer to each person is :
"j = 0","G=1","H=0","I=0", "D=0","E=0","f=0","B=2","C=4 (beacuse G refers J also)","A=9(beacuase 9 childers are refered by him)"
The chain continues until A gets total refer of 40.
In simple, if a person refers another person then it will get +1 and it's parent whom he gets refer also get +1 and so on until parent reaches 40, the chain continues.
I know, this is One-Many relationship between a user and refer and we can use a pivot table, but, How can we implement this type of logic. Give me some hints. Thanks.
I have written out something that should hopefully help you with this, using a while loop.
public function totalReferredBy(User $user)
{
// Initialise the queue to contain only the provided user
$queue = collect([$user]);
// This collection will eventually contain all of the "child"/referred users
$results = collect();
while ($queue->isNotEmpty() > 0) {
// Run a where in query to select all the referred users of the users in the queue.
$referredUsers = User::whereIn('referred_by', $queue->pluck('id'))->get();
// Merge the referredUsers we have found in the database with the results collection, so we can later count.
$results = $results->merge($referredUsers);
// Make the referredUsers we have just found in the database, the new queue. If the query did not return any
// referred users, the queue count would be 0 and the loop will exit.
$queue = $referredUsers;
}
// Now we should have all of the given user's "children" and "children of children" in the $results collection.
// We just need to return the count of that collection to get the total number of users that have been referred.
return $results->count();
}
You can use it like this:
$user = User::find(1);
$totalReferred = $this->totalReferredBy($user);
Then if your application does something when the user reaches 40 or more referred, you can just do:
if ($this->totalReferredBy($user) > 40) {
// Do something
}
This assumes that you have a referred_by column on the users table.
Im currently working on assigning groups to a special url, with their groupId as score.
create group-url:
$this->cache->redis->zadd("group_route",$groupId,$groupUrl);
search if it is a group-url, and get the group:
function isCostumUrl($groupUrl) {
$group = $this->cache->redis->zrank("group_route",$groupUrl);
if ($group) {
return $group;
} else {
return false;
}
}
Problem My problem is that somehow the result-groupid is wrong.
I am searching for katt, that has id 4, but it reply with 3 wich acually belongs to group-url fisk.
how can i acually make it return the right result?
The rank is not the same with the score. The rank is zero -0- based, so in the case above rank 3 is correct for group_route katt. For example you can have different scores of your items 2, 3, 4 and 5, but the rank (or index) will always be the same. Take a look at the Redis rank command
But zscore would work correct for you (you actually put zscore in title, but use zrank in example)
Hi I want to show random 6 rows from a collection. each row as a timestamp so I could use that but my question is how do I return only 6 rows from the collection and make it random
here is a sample of my collection - I use PHP
{
"age": "2",
"breed": "Bengal",
"dislikes": "Dislikes being patted by people",
"likes": "Like to purr and get headbutts. Sleeps on our bed, with Woody our dog, and also comes in for food at 6pm, loves Tin fish and is known to meow quite lo [...]",
"lost": true,
"pet_lost_date": NumberInt(1361366445),
"type": "cat"
}
I saw this
db.items.find().skip(randonNumberHere).limit(1); - MongoDB: Pulling multiple random documents from a collection
but I did not understand it, all i understand from that is the find() which finds everything skip() which skips a number of rows and limit() which is how many get returned.
However My question is more about getting all the lost pets and random them and only showing 6
public function lost_pets($no){
$collection = static::db()->ipet_mypet;
$pet = $collection->find(array('lost': true, '$where'=> function(){var randomNumber=Math.random(); return this.random>=randomNumber || this.random>randomNumber })).sort(array('pet_lost_date'=> 1)).limit(6);
}
You could use this:
db.collection.find({'lost': true, $where: function(){var randomNumber=Math.random(); return this.pet_lost_date>=randomNumber || this.pet_lost_date>randomNumber }}).next();
Find({'lost':true}) fetches the documents with field 'lost': true.
The $where clause returns a DBCursor, which points to a particular document. By calling "next()", we obtain the next document pointed by the cursor. So we fetch one random document at a time.
According to the way I see it logically, the easy way is to save records with a random number, then sort by that number when reading from the db.
Let say you have 20 records
you want to randomly fetch 5 records
We will generate a random skip value between 0 to 20 - limit value (5) = 15.
With this we are sure to return 5 records even if the random skip value starts from 15. We can also force the skip value to be zero if its becomes negative after we substract the random value from the total records
Example code:
$total_records = $collection->count(); <br>
$limit = 5; <br>
$skip = mt_rand(0, $total_records);<br>
$collection->find()->skip($skip < 0 ? 0 : $skip)->limit($limit);
I export from MYSQL db different info that I put inside an array:
$info=array(
(ID,CALORIES,PROTEIN,CARBOS,FIBER),
...
);
ex: (1,270,24,12,5),(2,280,2,42,10),...
Then, further down the script, I need to get the IDs of the 3 products with the highest calories, of the 6 products with the highest result of 2xPROTEIN+3xCARBOS, etc for 5 charts.
How can I do such a sorting of the array to fill my different tables?
The function sort() only seems to work for a single-dimensioned array (if it works for my case, I don't know what would be the syntax). It also doesn't seem to work for my more advanced sortings (2*x+3*y)...
Even tho it is not exactly what you are asking, I would highly suggest you preparing your tables in mysql (using all formulas to sort, etc.). Mysql's main job is do various selections and sorting, I would leave the work for it. Moreover, advanced sorting in mysql is way easier than thinking of algorithms or functions in php :)
SELECT * FROM `products`
ORDER BY (2*PROTEIN+3*CARBOS) DESC
Easy as that and no headaches. Apply LIMIT 3 at the end to get the top 3. Update
SELECT * FROM `products`
to your more advanced query. If having difficulties in code you may try to wrap it up as a subquery as this:
SELECT * FROM (SELECT * FROM `products` WHERE `type`='fruit' LIMIT 6) a
ORDER BY (2*PROTEIN+3*CARBOS) DESC LIMIT 3
You can use array_multisort() to sort multidimensional arrays. The syntax allows for quite some flexibilty, see the reference.
You can use usort function:
function cmp( $a, $b )
{
if( $a["calories"] *3+ $a["protein"]*2 == $b["calories"] *3+ $b["protein"]*2){ //do another comparison etc.. ; }
return ($a["calories"] *3+ $a["protein"]*2< $b["calories"] *3+ $b["protein"]*2)) ? -1 : 1;
}
usort($myarray,'cmp');
usort is your friend here.
function sort2Protein3Carbo($a, $b)
{
// Assuming protein is the 2nd value in your array and carbo the 3rd.
$resA = 2 * $a[2] + 3 * $a[3];
$resB = 2 * $b[2] + 3 * $b[3];
if ($resA == $resB)
return 0;
return ($resA < $resB) ? -1 : 1;
}
usort($info, "sort2Protein3Carbo");