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.
Related
In a relational database which is the best way to store a foriegn key, or relate a key, not sure how best to phrase it.
For example if you had tables:
User
ID
Name
Email
Email:
ID
Email
This is not a table I am actually creating just simple enough to get the idea across.
In the user table if I would create a key with the ID then when I select the user table the ID of the email is the value in the email field. I can reference the actual email field, this fixes that issue, but is that not wasteful?
I am using PHPMyAdmin to setup the databases and keys.
Any advice the best way to do this?
PhpMyAdmin provides a Graphical User Interface (GUI) to MySQL operations.
The best way to do this is databases, which I presume you will have already created, is to simply run a quick query!
MySQL looks pretty scary, but its actually really simple, once you grasp the concept of it!
By looking at your example, you'll most likely be looking to run a query like this one. (This is rough pseudo and may not run in itself)
ALTER TABLE User
ADD FOREIGN KEY (ID) REFERENCES Email(ID);
Easy peasy! :)
The best resource for finding out more about the syntax required is over on W3 Schools! This is the article you'll want to look at!
Edit
As a general database rule, I'd recommend making all your column names (fields) unique! This avoids confusion. For example, you could use UserID and EmailID.
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" .
I am creating a form that will capture all of the form data and store it in a database, what I would like to do is use some of the form data to create a custom md5 user id to prevent multiple entries, I know that this is most probably not the most ideal way of doing it, so if there is a better way of creating a unique md5 uid that I can use for each user, please enlighten me.
I have considered just using a random number and checking the database against the email and first name, but I am curious to see if there is a better way of doing it.
Thanx in advance!
Wait ... you are wanting to use a unique MD5 to create a user id? ... why not use an auto_increment integer field? Each time the INSERT is run, it will be increased by 1 therefore always being unique. And since it is an integer, if you are doing any searches against it it would be a lot faster.
You can let MySQL do the work for you using "UNIQUE". Assuming you have a table user_data(user_data_id, name, text, content, date) and want name and text to be UNIQUE as a tuple:
CREATE user_data (
user_data_id INTEGER,
name VARCHAR(50),
text TEXT,
date DATE,
PRIMARY_KEY(user_data_id),
UNIQUE(name,text)
);
I assume you mean you want to avoid having duplicate entries by the same person.
You should probably check the database for the input's email + firstname + lastname, after normalizing them with strtolower() and removing spaces etc.
Apart from that you can't know for sure if the person entering data in the form has done it before. You can't safely rely on the ip being the same due to proxies and gateways, or even the computer being the same (shared computers). If you are aggressive on those 2 fronts you'll probably get alot of frustrated legitimate users that can't use your system.
Your best bet is to assume your database has duplicate entries and then decide what to do with them. Either flag the ones not being used, if they're accounts on the system have some intelligence to check if they're duplicates based on their behavior.
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.
I am writing a sql editor (sqlite3).
I can display a table and allow users to edit any value in the table but I now need some way of identifying the value editted. The problem is that I don't know what the primary key is and I don't think it's that good an idea to say "update table set a=b where x=123 and y=123 and z=123 and..." for all the fields that aren't "a".
I'm using jquery (and ajax) and php.
Any ideas?
If you don't know what the primary key is (or you don't know if there is an UNIQUE index), you won't have much of a choice : even if using all fields in your where clause, you might update more than one line (the one the user wanted to edit).
You really need some way to identify one precise line -- and that way is the primary key.
Maybe, just out of curiosity, you my check how phpMyAdmin does that ?
(I know it's not SQLIte, my MySQL -- but maybe the general idea could be re-used ?)
You could force the user to specify a primary key (or at least a UNIQUE) and then retrieve it with SHOW INDEX FROM table (http://dev.mysql.com/doc/refman/5.0/en/show-index.html)
If you cannot determine PK or UK column then you have to use "where x=123 and y=123 and z=123", but remember to add LIMIT 1 - then you are sure you don't edit more than one record.
It is indeed not such a good idea to issue that update '... for all the fields that aren't a'. You should include a too, along with the old value of a in the row that was edited.