When a username is inserted into my database, such as:
John_Smith
I need to check if there is already a John_Smith present. If so, increment it by 1 to become John_Smith_1
So if the following usernames already exist:
John_Smith
John_Smith_1
John_Smith_2
John_Smith_3
....up to John_Smith_10
I need the next John_Smith inserted to be incremented to John_Smith_11.
So far, I have searched and come up with this:
$preferredname= "John_Smith"
//check for duplicate user names
$duplicate= check_for_duplicate_username($preferredname);
//if duplicate, increment the preferredname
if ($duplicate)
{
$parts = explode("_",$preferredname);
if (isset($parts[1]))
$preferredname = $parts[0]."_".$parts[1]."_".($parts[2]+1);
else $preferredname = $parts[0]."_".$parts[1]."_1";
}
This, I believe would work for only the first matching usernames. My problem is checking the database for the version of the name with the highest number.. This is my sql:
function check_for_duplicate_username($name)
{
// check if username already exists
$sql = "SELECT * FROM users WHERE user_username=$name";
//then return duplicates
You can use this query:
$sql = 'SELECT * FROM users WHERE user_username LIKE ' . $name . '_%';
the above will query for rows in which user_username have value similar to John_Smith_* ( where * is any valid character including number, which you have to check later )
you can use this php statement for getting user's suffix number:
preg_match( '/([0-9]+)$/', 'John_smith_10', $matches );
$user_number = $matches[0];
While this may not be the best solution in the grand scheme of things, here is an answer that addresses what you were specifically trying to do. The following query returns the number of users with either $name or $name_123 SELECT COUNT(*) FROM users WHERE user_username REGEXP '$name[_0-9]*$'; So if the value is 0 you can simply use $name by itself, otherwise you can use $name."_". + the number returned by the query.
But as many people have mentioned, prly not the best idea to autoassign usernames (very web 1.0 :P ). I'd recommend email addresses. Another option is to use whatever userid the social app uses along with another field identifying the social app (if you have multiple), and then using an autoincremented id field as the unique primary key..
I had a similar problem I was trying to solve today and did it like this. In my case I needed to store/create a unique directory name based on the users first initial/last name:
$username = "bjones";
$usersql = "SELECT * FROM users WHERE username LIKE '$username%'";
$usercnt = mysqli_num_rows(mysqli_query($con,$usersql));
// If bjones, bjones1, bjones2, etc already exists
if ($usercnt >= 1) {
$num = ++$usercnt; // Increment $usercnt by 1
$username = $username . $num; // Add number to username
}
Assuming bjones, bjones1, bjones2 already exists, I would end up with bjones3.
Related
Hello so first of all please consider this question as a newbie one because I can just set an ID field and add zerofill so it would look like 000001, 000002 and so fort. But what I did is wrong, and the system is already big so please consider my question. I have a table named accounts which has an id field and sponsorID field. Now what I did looks like this (btw I am using slim framework):
$db = new db();
$sponsorIDrandom = mt_rand(100000, 999999);
$bindCheck = array(
":sponsorID" => $sponsorIDrandom
);
$sponsorIDChecker = $db->select("accounts", "sponsorID = :sponsorID", $bindCheck);
$generate_SID = null;
do {
$generate_SID = mt_rand(100000, 999999);
} while (in_array($generate_SID, array_column($sponsorIDChecker, 'sponsorID')));
$db->insert("accounts", array(
"sponsorID" => $generate_SID
));
The code above will check if a number already exist in the accounts table and if there is an existing, it will generate a random number again until it becomes unique or non-existing in the accounts table. I made the sponsorID field unique so that it won't accept duplicate values.
Now the problem is the code I posted. I thought it would let the $generate_SID be unique because I used the in_array function so it would check if a value already exist in the array and do generate a number again until it is unique but I did receive luckily an error that it tried to insert a random number that already exists and it didn't generate a new one.
Can anyone tell me if there's a solution for this? Or should I re-modify the code above so it would not enter already existing sponsorID? Thank you in advance.
From what i understood, you try to insert a unique id into a table but the generator only runs once and or it tells you that the number already exists.
I've never used slim but it seems in your code you try to do a SELECT of a single record, because you generate a random number and then ask for this number to the database:
$sponsorIDrandom = mt_rand(100000, 999999);
$bindCheck = array(
":sponsorID" => $sponsorIDrandom
);
$sponsorIDChecker = $db->select("accounts", "sponsorID = :sponsorID", $bindCheck);
This only returns one or none rows if as you say the sponsorID is UNIQUE.
And then you try to generate another random number and check if is not repeated based on this single (or null) record.
$generate_SID = null;
do {
$generate_SID = mt_rand(100000, 999999);
} while (in_array($generate_SID, array_column($sponsorIDChecker, 'sponsorID')));
this loop only executes once because the probability of this second random number to be inside this record (if there is a record at all) are almost none and if the database are as big as you says, then the probability for collisions are too high.
for this code to work you need to load every record or ask for the newly generated number if it exists in the database every time it is generated, both alternatives are not recommended but since the databse is already (almost) full.
$sponsorIDChecker = $db->select(...); //use the equivalent of "SELECT sponsorID from accounts" without the WHERE clause, is better to ask for a single column.
$generate_SID = null;
do {
$generate_SID = mt_rand(100000, 999999);
} while (in_array($generate_SID, ...)); //here you put the result of the query above.
$db->insert("accounts", array(
"sponsorID" => $generate_SID
));
Now, something that may be of help: if you set the sponsorID as a zerofill in the databse as you said
I can just set an ID field and add zerofill so it would look like 000001, 000002 and so fort.
then you can lower the min value of mt_rand to 0 and you gain 100000 more IDs to try.
I'm creating a simple lottery script.
The idea is that in one lottery there could be a few winners and I'm having troubles with checking if a new winner is a person who already won in this lottery.
I store this kind of data in DB.
list [longtext] - column with a list of contestants (separated with spaces or comas)
winner [longtext] - column with a list of winners in this lottery (separated with spaces)
My loop:
//$won_this is person who won in this round
$old_winners = $draw[winner];
$czy = strpos($old_winners, "$won_this");
while($czy == FALSE)
{
$add_winner = $won_this;
}
$sql = "update `draws` set `winner`= concat(winner, ' $add_winner') where code='$draw['number']'";
mysql_query($sql) or die(mysql_error());
My loop doesn't work. It will loop forever or not at all. I have no idea how to write this.
How can I create a loop that runs when a winner is duplicated and works until the new winner is found?
The first thing I would do is convert the old winners into an array:
$winners = explode(' ', $draw['winner']);
Then I would add the new winner to the array:
$winners[] = $won_this;
And finally I would call array_unique on the array to ensure uniqueness and then convert the array back into a string to be inserted into the database:
$winners_string = implode(' ', array_unique($winners));
$stmt = $connection->prepare("update `draws` set `winner`= ? where code = ?");
// Use bing_param('si'...) if $draw['number'] is an integer, not a string
$stmt->bind_param('ss', $winners_string, $draw['number']);
$stmt->execute();
Although ideally, and as mentioned in the comments to your question, there are better ways to store the data, e.g. have a new table with a draw_number column and a winner column and simply add a new row for each winner.
$czy is always false so nothing will happen in this script. It is always false because you are using the wrong syntax to search the array. Change your solution for checking your array Michael example is correct. Try it
I wrote a function which makes a random id makeid(); Just to ensure the id is unique I have a SQL statement which checks if the id already exists.
$does_id_exist = mysql_query("SELECT COUNT(*) AS count FROM signups WHERE affid='$affid'");
if(mysql_num_rows($does_id_exist) == 1)
{
#loop function and perform query again
}
else
{
#insert record
}
So I'm having trouble with looping the function. How do I loop my function makeid() and perform the $does_id_exist check to ensure that each ID is unique.
--UPDATE-- Just to clarify- My code makes an id like YES#281E But before I INSERT this id into the users record. I just need to verify IF any other user already has this id. IF another user has this id that event must trigger my function to create a new id e.g. WOW!29E3 and again check the sql/query to ensure no other user has that id. Continue to loop if fails or end and INSERT if the id is available.
You can either just use a primary key on your database table, or something like this:
<?php
// the id to insert
$newId = null;
// populate with results from a SELECT `aff_id` FROM `table`
$currentIds = array();
// prepopulate
for( $i=0; $i<100000; $i++ )
{
$currentIds[] = "STRING_" + rand();
}
// generate at least one id
do
{
$newId = "STRING_" + rand();
}
// while the id is taken (cached in $currentIds)
while( in_array($newId, $currentIds) );
// when we get here, we have an id that's not taken.
echo $newId;
?>
Output:
STRING_905649971 (run time 95ms);
I'd definitely not recommend running the query repeatedly. Perhaps a final check before you insert, if your traffic volume is high enough.
Do not do COUNT(*), because you do not need to know how many rows is there (it should be 0 or 1 as you need Id unique), so even DB finds your row it will still be checking for the whole table to count. You really care if you got 1 row, so just select for row with that ID and this sufficient. You should also avoid using rand() - this does not help as you see and you cannot predict how many loops you can do before you find "free slot". use something predictable, like date prefix, or prefix incremented each day. anything that would help you narrow the data set. But for now (pseudocode!):
$id = null;
while( $id == null ) {
$newId = 'prefix' . rand();
mysql_query("SELECT `affid` FROM `signups` WHERE `affid`='${newId}'");
if( mysql_num_rows() == 0) {
$id = newId;
break;
}
}
Ensure you got DB indexed, to speed things up.
EDIT: I do agree that any cache would be useful to speed things up (you can add it easily yourself based on #Josh example), still, I think this is fixing at wrong place. If possible rethink the way you generate your ID. It does not really need to be auto increment, but something more predictable than rand() would help you. If your ID does not need to be easily memorable and it is not any security concern to have them sequential, maybe use numbers with other base than 10 (i.e. using 26 would use all digits + letters so you'd end with PREFIX-AX3TK, so string as you want, and at the same time you would easily be able to quickly generate next Id
There's a mysql database that stores ids and names, when users are creating names with a form they can create existent names since unique ids are the ids such as:
d49f2c32f9107c87c7bb7b44f1c8f297 name
2fa9c810fbe082900975f827e8ed9408 name
what i want to do is saving the second "name" -> "name(1)" when inserting into database.
So far what I've got is this as the idea
lets say the name entered is 'name'
$input = 'name';
select the name we want to check from mysql database
mysql_query(SELECT * FROM `table` WHERE `name` = '$input');
if the result exists, then insert as $input.'(1)'
my question is what if name exists, and name(1) also exists, then how can i add the name(2) there...
You could return the number of people with that name in the database, then add 1 to that number.
SELECT COUNT(id) FROM table WHERE name LIKE '$input(%)');
$i = 1;
$sourceName = $name;
while( sql "SELECT COUNT(*) FROM table WHERE name = '$name'" ) {
$name = $sourceName.' ('.$i.')';
$i++;
}
At this point you have the final $name (with $i counting the iteration)
Something like this should do the trick:
SELECT * FROM table WHERE name = '$input' OR name LIKE '$input(%)'
Note that for this to work, you'd need to escape any percent signs in $input in the LIKE clause, otherwise they'll be treated as wildcards.
Use a regex that checks for integers between two parentheses at the end of the string. If there exists an integer, add 1 to it.
You could also attempt to do it the other way around, make name field unique and try to input it in a while loop, if it fails add ($i) and do $i++ every iteration.
//edit:
The problem with using solutions that do a like comparison is that you will get false positives, for instance $hi% will also count hippie. Which gives you unnecessary (1) additions!
My application requires the user to enter their business name, which the application will automatically create into a unique identifier to be used in URLs, ie
"Bob's Cafe" will become "bobs-cafe"
But if there are duplicate names I would like the application to add a number so if there is already a "bobs-cafe" we will use "bobs-cafe-1" and likewise if there is already a "bobs-cafe-1" we will use "bobs-cafe-2"
Ive used explode and also looked at a regular expressions but I dont know the best way to approach this.
Im stuck in being able to grab the number and incrementing it and returning the string
Adding to Sarfraz's answer, you might want to find it using a LIKE statement
SELECT `urlIdentifier` FROM `businesses` WHERE `urlIdentifier` LIKE `bobs-cafe%`
which will get all the bobs-cafe items - that way, if you get 5 rows you know you have
bobs-cafe
bobs-cafe-1
bobs-cafe-2
bobs-cafe-3
bobs-cafe-4
and that you'll need to add bobs-cafe-5
EDIT - Or this:
SELECT count(*) as `howMany` FROM `businesses` WHERE `urlIdentifier` LIKE `bobs-cafe%`
Now your result object ( or array ) will have the total number:
echo $resultObject->howMany; // number of bobs-cafe sql found
Why not to add an autoincrement number to every identifier in the URL?
Just like SO does:
stackoverflow.com/questions/2895334/php-application-check-name-is-unique-if-not-append
so, you have both unique identifier and a business name.
This is even better because they are free to change their business name, without changing an identifier.
As for your question it's very simple. Just for the PHP practice:
if (/* you've found the name is already non unique and have the max one in the $id */) {
$parts = explode("-",$id);
if (isset($parts[1])) $newid = $parts[0]."-".($parts[1]+1);
else $newid = $parts[0]."-1";
}
Assuming $user is already in the form bobs-cafe
function username_exists ( $user ) {
$result = mysql_query("SELECT name FROM table WHERE $name LIKE '$user%' ");
$count = mysql_num_rows($result);
if ( $result ) {
$num = $count+1;
return username_exists ( $user.'-'.$num ) ;
} else {
return $user;
}
}