Im looking for how to generate a unique id that will remain unique for one year. I use uniqid() function but I've heard that there is a chance for duplicates, so I do this:
$id = rand(0,1000) . uniqid();
Will this remain unique for a whole year?
The only way to be sure you have a unique Id in your data set is to test for it.
$id = uniqid(2012); //returns a 13 character string plus it will append 2012 for 17 characters.
$resultSet = //get dataSet from somewhere
foreach($resultSet as $row) {
if ($row['id'] = $id) {
//do some stuff
}
}
This is a simple example of how you might flow this in a simple application. I'm sure there is probably a way to do this SQL as well (but I don't know SQL that well).
Alternatively you could just let the database start at 1 and assign each record a unique value for it's ID.
You failed to mention your purpose so these suggestions are a best guess.
Good Luck.
Related
I'm trying to create an increment number licence with the current date of the year + an increment number but i really don't know how to do this i know MYSQl does not support sequences but i would like to know if there is a way to solve the problem
here my controller
public function create(){
$licence = new Licence ;
$licence ->num_licence = Carbon::now()->year -- i would like here to put the current year like 2017 with a random unique number to get the format like 20170001 for exemple !
...
how to acheice this? thanks in advance :)
you can use uniqid function with current year as prefix.
public function create(){
$licence = new Licence ;
$num_liscence_exist=true;
while($num_liscence_exist){
$num_liscence=uniqid(Carbon::now()->year);
if (!Liscence_Table::where('num_liscence', '=',"'".$num_liscence."'")->exists()) {
$liscence->num_liscence=$num_liscence;
$num_liscence_exist=false;
}
}
}
Generate the random id using uniqid() and concatenate with date:
public function create(){
$liscence=new Liscence();
$year = Carbon::now()->year;
$liscence->num_liscence= $year. uniqid();
$liscence->save();
}
using uniqid() get unique number or also you can use time stamp with it:
$liscence=new Liscence();
$year = Carbon::now()->year;
$liscence->num_liscence= $year. strtoupper(uniqid()) . Carbon::now()->timestamp;
$liscence->save();
Will look like : 2017ABC011486543961
A sequence needs to be stored somewhere so I doubt there's a sensible pure-PHP solution. But since you're already using MySQL there's no reason to not use it. I'd create a database table for that, something like:
CREATE TABLE licence_sequence (
sequence_year YEAR NOT NULL,
next_value INT UNSIGNED NOT NULL DEFAULT 1,
PRIMARY KEY (sequence_year, next_value)
)
ENGINE=InnoDB;
(Ugly sequence_year name was chosen to avoid having to quote it every time.)
You then have to manage this from code, including:
Ensuring you have rows for every year as you need them (this can be as simple as populating data for all years for next century).
Ensuring you don't assign the same value to different items.
A rough overview of stuff to consider:
You can (and should) make your licence number a unique index to avoid dupes.
You can use transactions to avoid unnecessary gaps. Transaction should wrap all the operations involved:
Get next sequence number
Save it into new licence
Increment next number
You need to ensure atomic operations in a multi-tasking environment. This is the hardest part. I've been lately being playing with MySQL named locks and they seem to work correctly.
im working on PHP + MySQL application, which will crawl HDD/shared drive and index all files and directories into database, to provide "fulltext" search on it. So far im doing well, but im stuck on question, if i chosed good way how to store data into database.
On picture below, you can see part schema of my database. Thought is, that i'm saving domain (which represents part of disk which i wana to index) then there are some link(s) (which represents files and folder (with content, filepath, etc) then i have table to store sole (uniq) keywords, which i find in file/folder name or content.
And finaly, i have 16 tables linkkeyword to store relations between links and keywords. I have 16 of them because i thought it might be good to make something like hashtable, because im expecting high number of relations between link <-> keyword. (so far for 15k links and 400k keywords i have about 2.5milion of linkkeyword records). So to avoid storing so much data into one table (and later search above them) i thought that this hastable can be faster. It works like i wana to search for word, i compute it md5 and look at first character of md5 and then i know to which linkkeyword table i should use. So there is only about 150~200k records in each linkkeyword table (against 2.5milions)
So there im curious, if this approach can be of any use, or if will be better to store all linkkeyword information to single table and mysql will take care of it (and to how much link<->keyword it can work?)
So far this was great solution to me, but i crushed hard when i tried to implement regular-expression search. So user can use e.g. "tem*" which can result in temp, temporary, temple etc... In normal way when searching for word, i will conpute in md5 hash and then i know to which linkkeyword table i need to look. But for regular expression i need to get all keywords from keywords table (which matches regular expression) and then process them one by one.
Im also attaching part of code for normal keyword search
private function searchKeywords($selectedDomains) {
$searchValues = $this->searchValue;
$this->resultData = array();
foreach (explode(" ", $searchValues) as $keywordName) {
$keywordName = strtolower($keywordName);
$keywordMd5 = md5($keywordName);
$selection = $this->database->table('link');
$results = $selection->where('domain.id', $selectedDomains)->where('domain.searchable = ?', '1')->where(':linkkeyword' . $keywordMd5[0] . '.keyword.keyword LIKE ?', $keywordName)
->select('link.*,:linkkeyword' . $keywordMd5[0] . '.weight,:linkkeyword' . $keywordMd5[0] . '.keyword.keyword');
foreach ($results as $result) {
$keyExists = array_key_exists($result->linkId, $this->resultData);
if ($keyExists) {
$this->resultData[$result->linkId]->updateWeight($result->weight);
$this->resultData[$result->linkId]->addKeyword($result->keyword);
} else {
$domain = $result->ref('domain');
$linkClass = new search\linkClass($result, $domain);
$linkClass->updateWeight($result->weight);
$linkClass->addKeyword($result->keyword);
$this->resultData[$result->linkId] = $linkClass;
}
}
}
}
and regular expression search function
private function searchRegexp($selectedDomains) {
//get stored search value
$searchValues = $this->searchValue;
//replace astering and exclamation mark (counted as characters for regular expression) and replace them by their mysql equivalent
$searchValues = str_replace("*", "%", $searchValues);
$searchValues = str_replace("!", "_", $searchValues);
// empty result array to prevent previous results to interfere
$this->resultData = array();
//searched phrase can be multiple keywords, so split it by space and get results for each keyword
foreach (explode(" ", $searchValues) as $keywordName) {
//set default link result weight to -1 (default value)
$weight = -1;
//select all keywords, which match searched keyword (or its regular expression)
$keywords = $this->database->table('keyword')->where('keyword LIKE ?', $keywordName);
foreach ($keywords as $keyword) {
//count keyword md5 sum to determine which table should be use to match it links
$md5 = md5($keyword->keyword);
//get all link ids from linkkeyword relation table
$keywordJoinLink = $keyword->related('linkkeyword' . $md5[0])->where('link.domain.searchable','1');
//loop found links
foreach ($keywordJoinLink as $link) {
//store link weight, for later result sort
$weight = $link->weight;
//get link ID
$linkId = $link->linkId;
//check if link already exists in results, to prevent duplicity
$keyExists = array_key_exists($linkId, $this->resultData);
//if link already exists in result set, just update its weight and insert matching keyword for later keyword tag specification
if ($keyExists) {
$this->resultData[$linkId]->updateWeight($weight);
$this->resultData[$linkId]->addKeyword($keyword->keyword);
//if link isnt in result yet, insert it
} else {
//get link reference
$linkData = $link->ref('link', 'linkId');
//get information about domain, to which link belongs (location, flagPath,...)
$domainData = $linkData->ref('domain', 'domainId');
//if is domain searchable and was selected before search, add link to result set. Otherwise ignore it
if ($domainData->searchable == 1 && in_array($domainData->id, $selectedDomains)) {
//create new link instance
$linkClass = new search\linkClass($linkData, $domainData);
//insert matching keyword to links keyword set
$linkClass->addKeyword($keyword->keyword);
//set links weight
$linkClass->updateWeight($weight);
//insert link into result set
$this->resultData[$linkId] = $linkClass;
}
}
}
}
}
}
Your question is mostly one of opinion, so you may want to include the criteria that allow us to answer "worth it' more objectively.
It appears you've re-invented the concept of database sharding (though without distributing your data across multiple servers).
I assume you are trying to optimize search time; if that's the case, I'd suggest that 2.5 million records on a modern hardware is not a particularly big performance challenge, as long as your queries can use an index. If you can't use an index (e.g. because you're doing a regular expression search), sharding will probably not help at all.
My general recommendation with database performance tuning is to start with the simplest possible relational solution, keep tuning that until it breaks your performance goals, then add more hardware, and only once you've done that should you go for "exotic" solutions like sharding.
This doesn't mean using prayer as a strategy. For performance-critical application, I typically build a test database, where I can experiment with solutions. In your case, I'd build a database with your schema without the "sharding" tables, and then populate it with test data (either write your own population routines, or use a tool like DBMonster). Typically, I'd go for at least double the size I expect in production. You can then run and tune queries to prove, one way or another, whether your schema is good enough. It sounds like a lot of work, but it's much less work than your sharding solution is likely to bring along.
There are (as #danFromGermany comments) solutions that are optimized for text serach, and you could use MySQL fulltext search features rather than regular expressions.
I'm trying to generate a unique "dosieid" number for my web site. My web site is a human resources program solution, in that program users create dosie of their workers in their firm ...random dosieid needs me so when user creating dosie in field dosieid automatically show the dosieid-s that are not used before...the dosieid that don't exist in database. In other case I would use auto increment but in this case dosie is not created yet. And in form dosieid must be option to change the number if random is not fine with a user. One more hint the numbers must bee from 1 to 9999. Can someone help me? I have try many codes but I have not find something like one with this spec.
This is what I have do so far. It gets the random number but I don't know how to compare that random number with database row "dosieid" ?
$id_num = mt_rand(1,9999);
$query = "SELECT dosjeid FROM albums";
$result = mysql_query($query) or die(mysql_error());
while($account = mysql_fetch_array($result)){
if ($id_num == $account['id']){
$id_num = mt_rand(1,9999);
}
}
echo"$id_num<br>";
This is extraordinarily convoluted... why is an auto-incrementing number not enough? This code would also never work properly. If for whatever reason you HAVE to use a random number, then you'd do it like this:
while(true) {
$id_rand = mt_rand(1,9999);
$result = mysql_query("SELECT count(*) FROM albums WHERE dosjeid=$id_rand") or die(mysql_error());
$row = mysql_fetch_row($result);
if ($row[0] == 0) {
break; // our random number isn't in the database, so exit the loop
}
}
However, here's some problems with this:
1) You'll get an infinite loop when you reach 9999 dosie records
2) The more records there are in the database, the longer this loop will take to find a "vacant" slot. As you get closer and closer to 9999 records, you'll be taking a LONG time to find that one empty slot
3) If you're trying to "cloak" the IDs of anyone member so that users can't simply increment an ID parameter somewhere to see other people's records, there's FAR FAR FAR better/easier ways of doing this, such as encrypting the ID value before sending it out to clients.
Use a auto-increment number as your primary key and an additional display id with the UNIQUE attribute as the ID shown to the user. This way you have a unique ID for your internal processing and a display ID that can be easily changed.
This is a terrible design. You should either:
not let users create the dosieid (create it yourself, give it to them after record created)
Try to create a stub record first with an assigned dosieid, and then update it with information
or use UUIDs, which requires a much bigger range than 1-9999
Even if you check that the number was unique, in between the time when you check it and the time you insert the record someone else may have taken it.
And under no circumstances should you find an empty id by picking numbers at random. This makes your program execution time non-deterministic, and if you eventually get 5000 employees you could be waiting a long time.
Also, This range is way too small for a randomness requirement.
You may also want to read about number only hashes (check upon the algorithm's collision rate) - php: number only hash?
function doesIdExists($id)
{
$query = "SELECT dosjeid FROM albums";
$result = mysql_query($query) or die(mysql_error());
while($account = mysql_fetch_array($result))
{
if ($id_num == $account['id'])
return true; /* The id is taken */
}
return false; /* Not taken */
}
$recNotAdded = true;
while($recNotAdded)
{
$rand = mt_rand(1,1000); //Whatever your numbers
$doesExist = doesIdExists($rand);
if(!$doesExist)
{
/* Add to DB */
$recNotAdded = false;
}
}
I am developing a mysql database.
I "need" a unique id for each user but it must not auto increment! It is vital it is not auto increment.
So I was thinking of inserting a random number something like mt_rand(5000, 1000000) into my mysql table when a user signs up for my web site to be. This is where I am stuck?!
The id is a unique key on my mysql table specific to each user, as I can not 100% guarantee that inserting mt_rand(5000, 1000000) for the user id will not incoherently clash with another user's id.
Is there a way in which I can use mt_rand(5000, 1000000) and scan the mysql database, and if it returns true that it is unique, then insert it as the user's new ID, upon returning false (somebody already has that id) generate a new id until it becomes unique and then insert it into the mysql database.
I know this is possible I have seen it many times, I have tried with while loops and all sorts, so this place is my last resort.
Thanks
You're better off using this: http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_uuid
Or using this: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
But if you actually want to do what you are saying, you can just do something like:
$x;
do {
$x = random_number();
"SELECT count(*) FROM table WHERE id = $x"
} while (count != 0);
// $x is now a value that's not in the db
You could use a guid. That's what I've seen done when you can't use an auto number.
http://php.net/manual/en/function.com-create-guid.php
Doesn't this function do what you want (without verification): http://www.php.net/manual/en/function.uniqid.php?
I think you need to approach the problem from a different direction, specifically why a sequence of incrementing numbers is not desired.
If it needs to be an 'opaque' identifier, you can do something like start with a simple incrementing number and then add something around it to make it look like it's not, such as three random numbers on the end. You could go further than that and put some generated letters in front (either random or based on some other algorithm, such as the day of the month they first registered, or which server they hit), then do a simple checksuming algorithm to make another letter for the end. Now someone can't easily guess an ID and you have a way of rejecting one sort of ID before it hits the database. You will need to store the additional data around the ID somewhere, too.
If it needs to be a number that is random and unique, then you need to check the database with the generated ID before you tell the new user. This is where you will run into problems of scale as too small a number space and you will get too many collisions before the check lucks upon an unallocated one. If that is likely, then you will need to divide your ID generation into two parts: the first part is going to be used to find all IDs with that prefix, then you can generate a new one that doesn't exist in the set you got from the DB.
Random string generation... letters, numbers, there are 218 340 105 584 896 combinations for 8 chars.
function randr($j = 8){
$string = "";
for($i=0;$i < $j;$i++){
srand((double)microtime()*1234567);
$x = mt_rand(0,2);
switch($x){
case 0:$string.= chr(mt_rand(97,122));break;
case 1:$string.= chr(mt_rand(65,90));break;
case 2:$string.= chr(mt_rand(48,57));break;
}
}
return $string;
}
Loop...
do{
$id = randr();
$sql = mysql_query("SELECT COUNT(0) FROM table WHERE id = '$id'");
$sql = mysql_fetch_array($sql);
$count = $sql[0];
}while($count != 0);
For starters I always prefer to do all the randomization in php.
function gencode(){
$tempid=mt_rand(5000, 1000000);
$check=mysql_fetch_assoc(mysql_query("SELECT FROM users WHERE id =$tempid",$link));
if($check)gencode();
$reg=mysql_query("INSERT INTO users id VALUES ('$tempid')",$link);
//of course u can check for if $reg then insert successfull
I'm using Zend_Cache_Core with Zend_Cache_Backend_File to cache results of queries executed for a model class that accesses the database.
Basically the queries themselves should form the id by which to cache the obtained results, only problem is, they are too long. Zend_Cache_Backend_File doesn't throw an exception, PHP doesn't complain but the cache file isn't created.
I've come up with a solution that is not efficient at all, storing any executed query along with an autoincrementing id in a separate file like so:
0->>SELECT * FROM table
1->>SELECT * FROM table1,table2
2->>SELECT * FROM table WHERE foo = bar
You get the idea; this way i have a unique id for every query. I clean out the cache whenever an insert, delete, or update is done.
Now i'm sure you see the potential bottleneck here, for any test, save or fetch from cache two (or three, where we need to add a new id) requests are made to the file system. This may even defeat the need to cache alltogether. So is there a way i can generate a unique id, ie a much shorter representation, of the queries in php without having to store them on the file system or in a database?
Strings are arbitrarily long, so obviously it's impossible to create a fixed-size identifier that can represent any arbitrary input string without duplication. However, for the purposes of caching, you can usually get away with a solution that's simple "good enough" and reduces collisions to an acceptable level.
For example, you can simply use MD5, which will only produce a collision in 1 in 2128 cases. If you're still worried about collisions (and you probably should be, just to be safe) you can store the query and the result in the "value" of the cache, and check when you get the value back that it's actually the query you were looking for.
As a quick example (my PHP is kind of rusty, but hopefully you get the idea):
$query = "SELECT * FROM ...";
$key = "hash-" + hash("md5", $query);
$result = $cache->load($key);
if ($result == null || $result[0] != $query) {
// object wasn't in cache, do the real fetch and store it
$result = $db->execute($query); // etc
$result = array($query, $result);
$cache->save($result, $key);
}
// the result is now in $result[1] (the original query is in $result[0])
MD5!!
Md5 generates a string of length 32 that seems to be working fine, the cache files are created (with filenames about of length 47) so it seems as though the operating system doesn't reject them.
//returns id for a given query
function getCacheId($query) {
return md5($query);
}
And that's it! But there's that issuse of collisions and i think salting the md5 hash (maybe with the name of the table) should make it more robust.
//returns id for a given query
function getCacheId($query, $table) {
return md5($table . $query);
}
If anyone wants the full code for how i've implemented the results caching, just leave a comment and i'll be happy to post it.