Check duplicates SQL or php? - php

I have a field in my users database, a 6 digit number that is generated upon registration. I use mt_rand(100000, 999999) to generate the numbers.
Now to the question, to make sure no one gets the same number I need to either make the field UNIQUE (which i think seems the best) instead of some PHP code. Maybe theres some other way I don't know. The question is, whats the best way to do this?

You can do this way using PHP.
First give a unique constraint to the field.
if (mysqli_errno() == 2027)
mysqli_query("INSERT INTO ... {mt_rand()}");
So, once you insert a duplicate value, it gives out an error code 2027, saying duplicate. You can resubmit the query.

Why don't you
use a nested select to get the max(user_id), increase it and use that value for the new user?
create a table that holds just the current user-id and fetch, increase and use that value to create the new user?
use an AUTO_INCREMENT column?

Use an AUTO_INCREMENT column.
Performing a query to check if a generated number already exists is a bad solution and become worse with more and more users registered because more number are used, so you need to keep trace of all generated numbers to always generate a valid number.
With an AUTO_INCREMENT column, this occurs "automatically" .

Related

Create Unique MYSQL Primary Key Where Only Part Of is Incremntal

In one of my mysql table, I need to generate the primary key field which is 15 digit in length.
Structure is 2+2+2+2+2+5 as ex: 010101010100001.
First 10 Digit values comes from five 2 digit form/input fields and last 5 character is unique and incremental. So, whenever a form/data is submitted that value will be increased.
now how can I achieve that?
I think of following method but thinking of 2 issue:
First use select query to get the last used id/number. Then add +1 to it.**
Issue-1:
For this I have to make 2 query 1 for select and 1 for update, but I think there is much better way than this?
Issue-2:
What if multiple like hundreds/thousands of users submit the form at the very same time? how can I make sure it will be unique and wont cause a db error?
any suggestion/idea would be highly appreciated.
Having a UNIQUE/PRIMARY KEY ensures that you cannot have any duplicate entries in the database. You will get an error message from MySQL if you try to create a duplicate entry. So you don't need to check for duplicates, MySQL will do so for you. However you have to check for error messages and react accordingly by changing the value like adding +1 on it, depending on your requirements.

MySQL insert unique technique

I have a php application that inserts a data into MySQL, which contains a randomly-generated unique value. The string will have about 1 billion possibilities, with probably no more than 1 or 2 million entries at any one time. Essentially, most combinations will not exist in the database.
I'm trying to find the least expensive approach to ensuring a unique value on insert. Specifically, my two options are:
Have a function that generates this unique ID. On each generation, test if the value exists in the database, if yes then re-generate, if no, return value.
Generate random string and attempt insert. If insert fails, test error is 1062 (MySQL duplicate entry X for key Y), re-generate key and insert with new value.
Is it a bad idea to rely upon the MySQL error for re-trying the insert? As I see it, the value will probably be unique, and it seems the initial (using technique 1) would be unnecessary.
EDIT #1
I should have also mentioned, the value must be a 6 character length string, composed of either uppercase letters and/or numbers. They can't be incremental either - they should be random.
EDIT #2
As a side note, I'm trying to create a redemption code for a gift certificate that is difficult to guess. Using numbers and letters creates 36 possibilities for each character, instead of 10 for just numbers or 26 for just letters.
Here's a stripped-down version of the solution I created. The first value entered in the table is the primary key, which is auto incremented. affected_rows() will equal 1 if the insert is successful:
$code = $build_code();
while ((INSERT INTO certificates VALUES ('', $code) ON DUPLICATE KEY UPDATE pk = pk) && affected_rows() == 0)
$code = $build_code();
Is it a bad idea to rely upon the MySQL error for re-trying the insert?
Nope. Go ahead an use it if you want. In fact many people think if you check and if it doesn't exist then it's safe to insert. But unless you lock the table it's always possible that another process might slip in and grab the id.
So go ahead generate a random id if it suits your purpose. Just make sure you test your code so it does properly handle dups. Might also be useful to log dups just to ensure your assumptions about how unlikey dups are to occur are correct.
Define your table with unique constraint:
http://dev.mysql.com/doc/refman/5.0/en/constraint-primary-key.html
Why not just use: "YourColName BIGINT AUTO_INCREMENT PRIMARY KEY" to ensure uniqueness?

Apply UUID function to database field from PHP

I have this CodeIgniter and MySQL application.
I have a database table where one field must be unique. When I "delete" a record from the table I don't want to really remove it from the table, I just want to set free the value of the unique field so it can be used for a future new record without conflicts and leave it there.
At first I tought applying some sort of UUID function to the field would be a good solution.
Can somebody please point me how can I apply the UUID function to the field from the PHP code?
I googled about it and couldn't come up with nothing, CodeIgniter's docs neither.
Some other toughts are also welcome and appreciated.
Thanks in advanced!
If I understand correctly your aim here, you can do this with a single line of sql statement.
update users set username = CONCAT(UUID(), username) where username = "username_to_be_deleted"
This is quite a good attempt to keep the unique constraint, unless some wicked handed user of yours picked a username that is in the format of a unique id + some string, and it will accidentaly match. Not likely, though.
Added benefit: as UUID has a fixed format, you can always extract the original username from the encoded value.
And of course, a much better aproach, if you do not add a unique constraint on a field like this, but rather enforce uniqueness programmatically.

MySQL Unique hash insertion

So, imagine a mysql table with a few simple columns, an auto increment, and a hash (varchar, UNIQUE).
Is it possible to give mysql a query that will add a column, and generate a unique hash without multiple queries?
Currently, the only way I can think of to achieve this is with a while, which I worry would become more and more processor intensive the more entries were in the db.
Here's some pseudo-php, obviously untested, but gets the general idea across:
while(!query("INSERT INTO table (hash) VALUES (".generate_hash().");")){
//found conflict, try again.
}
In the above example, the hash column would be UNIQUE, and so the query would fail. The problem is, say there's 500,000 entries in the db and I'm working off of a base36 hash generator, with 4 characters. The likelyhood of a conflict would be almost 1 in 3, and I definitely can't be running 160,000 queries. In fact, any more than 5 I would consider unacceptable.
So, can I do this with pure SQL? I would need to generate a base62, 6 char string (like: "j8Du7X", chars a-z, A-Z, and 0-9), and either update the last_insert_id with it, or even better, generate it during the insert.
I can handle basic CRUD with MySQL, but even JOINs are a little outside of my MySQL comfort zone, so excuse my ignorance if this is cake.
Any ideas? I'd prefer to use either pure MySQL or PHP & MySQL, but hell, if another language can get this done cleanly, I'd build a script and AJAX it too.
Thanks!
This is our approach for a similar project, where we wanted to generate unique coupon codes.
First, we used an AUTO_INCREMENT primary key. This ensures uniqueness and query speed.
Then, we created a base24 numbering system, using A,B,C, etc, without using O and I, because someone might have thought that they were 0 or 1.
Then we converted the auto-increment integer to our base24 number. For example, 0=A, 1=B, 28=BE, 1458965=EKNYF. We used base24, because long numbers in base10 have fewer letters in base24.
Then we created a separate column in our table, coupon_code. This was not indexed.
We took the base24 and added 3 random numbers, or I and O (which were not used in our base24), and inserted them into our number. For example, EKNYF could turn into 1EKON6F or EK2NY3F9. This was our coupon code and we inserted it into our coupon_code column. It's unique and random.
So, when the user uses code EK2NY3F9, all we have to do it remove all non-used characters (2,3 and 9) and we get EKNYF, which we convert to 1458965. We just select the primary key 1458965 and then compare coupon_code column with EK2NY3F9.
I hope this helps.
If your heart is set on using base-36 4 character hashes (hashspace is only 1679616), you could probably pre-generate a table of hashes that aren't already in the other table. Then finding a unique hash would be as simple as moving it from the "unused table" to the "used table" which is O(1).
If your table is conceivably 1/3 full you might want to consider expanding your hashspace since it will probably fill up in your lifetime. Once the space is full you will no longer be able to find unique hashes no matter what algorithm you use.
What is this hash a hash of? It seems like you just want a randomly generated unique VARCHAR column? What's wrong with the auto increment?
Anyway, you should just use a bigger hash - find an MD5 function - (if you're actually hashing something), or a UUID generator with more than 4 characters, and yes, you could use a while loop, but just generate a big enough one so that conflicts are incredibly unlikely
As others have suggested whats wrong with an autoinc field? If you want an alpha numeric value then you could simply do a simple conversion from int to a alphanumeric string in base 36. This could be implemented in almost any language.
Going with zneaks comment, why don't you use an autoincrement column? save the hash in another (non unique) field, and concatenate the id to it (dynamically). So you give a user [hash][id]. You can parse it out in pure sql using the substring functions.
Since you have to have the hash, the user can't look at other records by incrementing the id.
So, just in case someone runs across a similar issue, I'm using a UNIQUE field, I'll be using a php hash function to insert the hashes, if it comes back with an error, I'll try again.
Hopefully because of the low likelyhood of conflict, it won't get slow.
You could also check the MySQL functions UUID() and UUID_SHORT(). Those functions generate UUIDs that are globally unique by definition. You won't have to double-check if your PHP-generated hash string already exists.
I think in several cases these functions can also fit your project's requirements. :-)
If you already have the table filled by some content, you can alter it with the following :
ALTER TABLE `page` ADD COLUMN `hash` char(64) AS (SHA2(`content`, 256)) AFTER `content`
This solution will add hash column right after the content one, generates hash for existing and new records too without need to change your INSERT statement.
If you add UNIQUE index to the column (after have removed duplicates), your inserts will only be done if content is not already in the table. This will prevent duplicates.

Maintain unique id across multiple tables

I want to build a database-wide unique id. That unique id should be one field of every row in every table of that database.
There are a few approaches I have considered:
Create one master-table with an auto-increment-field and a trigger in every other table, like:
"before insert here, insert in master-table -> get the auto-increment value -> and use this value as primary-key here"
I have seen this before, but instead of making one INSERT, it does 2 INSERTS, which I expect would not be that performant.
Add a field uniqueId to every table, and fill this field with a PHP-generated integer... something like unix-timestamp plus a random number.
But I had to use BIGINT as the datatype, which means big index_length and big data_length.
Similar to the "uniqueId" idea, but instad of BIGINT I use VARCHAR and use uniqid() to populate this value.
Since you are looking for opinions... Of the three ideas you give, I would "vote" for the uniqid() solution. It seems pretty low cost in terms of execution (but possibly not implementation).
A simpler solution (I think) would be to just add a field to each table to store a guid and set the default value of the field to be MySQL's function that generates a guid (I think it is UUID). This lets the database do the work for you.
And in the spirit of coming up with random ideas... It would be possible to have some kind of offline process fill in the IDs asynchronously. Make sure every table has the appropriate field and make the default value be 0/empty. Then the offline process could simply run a query on each table to find the rows that do not yet have a unique id and it could fill them in. That would let you control the ID and even use some kind of incrementing integer. This, of course, requires that you do not need the unique ID instantly each time a record is inserted.

Categories