How to hash auto increments in mysql - php

Is there a way to make mysql hash the auto increment values for its tables?
For example with md5?
id - name
1 - New York
2 - Chicago
3 - Sydney
4 - Berlin
what I'm trying to get
id - name
c4ca4238a0b923820dcc509a6f75849b - New York
c81e728d9d4c2f636f067f89cc14862c - Chicago
eccbc87e4b5ce2fe28308fd9f2a7baf3 - Sydney
a87ff679a2f3e71d9181a67b7542122c - Berlin
Thanks in advance
EDIT:
I think I need to clarify the question a little more, what im trying to do is not Call the ID's but Insert them. In the moment the ID column is an int field which I will change to varchar.
I want to save the identifiers as Hashed in the DB not call them with mysql SELECT. Thanks

If you really need this, for some reason, you can achieve it with a help of a separate table for sequencing and a BEFORE trigger
Table schemas:
CREATE TABLE table1_seq
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
CREATE TABLE table1
(id VARCHAR(32) NOT NULL DEFAULT 0, name VARCHAR(32));
The trigger
DELIMITER $$
CREATE TRIGGER tg_bi_table1
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq () VALUES ();
SET NEW.id = MD5(LAST_INSERT_ID());
END$$
DELIMITER ;
Now you can insert rows into your table1 table
INSERT INTO table1 (`name`) VALUES ('New York'),('Chicago'),('Sydney'),('Berlin');
or select
SELECT * FROM table1 WHERE id = MD5(2);
Here is SQLFiddle demo

All the answers above lack a good understanding of the need to use hashed id's.
Hashing the auto increment id violates the whole concept.
The concept you want to reach is that the next id will be unpredictable from the previous.
In the idea of hashing the id the next id of the md5( 1 ) is the md5( 2 ).
If you use the names that helps.
It would be best to create the hash from several fields.
The fields together should be unique to create a unique hash.

Maybe i did not understand the question, but this is my opinion:
I think you try to create a hash table. So insert id field as hash of your data (md5(name)).
But if not, use a table trigger to generate field hash after insert.

MySQL Docs say..
Functions cannot be added as COLUMN DEFAULTS - except for now() that
is internally represented as a synonym of CURRENT_TIMESTAMP.
A best bet would be to do this...
UPDATE yourtablename SET id=MD5(id) WHERE 1=1;
or to run a TRIGGER
Something like ... (Not 100% correct... just giving you an idea)
CREATE TRIGGER generateMD5forID BEFORE INSERT ON `yourtablename` FOR EACH ROW SET id = MD5(id);

The Answers here brought up an Idea in me.. I think that will work as the best solution for now.. but if there is someone who knows an easier way I'm glad to hear it.
Solution:
Create a new table with an auto increment field like id or count, which you will always increment first and use the last ID out of that table to hash it for the primary field of your other table.

Related

How to Use Auto Increment in Varchar data Type in PHP an MYSQL?

can anyone tell us how to use auto increment in varchar data type?
i have look for other question and people always ask to use interger or use trigger. but however this is my college's project that has a rule for us to use varchar.
Automatically generated based on last Product ID existing in the database
Ex. If the latest Product ID is ‘PR004’, then the new id will be ‘PR005’
so, we must set auto increment in php right?can someone tell me how to use this?
thank you
MYSQL 5.7.5:
You can accomplish the goal using Generated Columns and this.
Not tested
CREATE TABLE TEST (
ProdID VARCHAR(20) AS CONCAT('PR','',PID) STORED,
PID INT auto_increment)
For your convenience,
MSSQL:
The easiest method is to simply make a calculated column. It uses what is known as a "calculated" column in conjunction with an IDENTITY column.
CREATE TABLE Test
(
ProdID AS CAST('PR'+RIGHT('000'+CAST(RowNum AS VARCHAR(3)),3) AS VARCHAR(30)) PERSISTED
,ProdName VARCHAR(30)
,RowNum INT IDENTITY(1,1)
);
INSERT INTO Test (ProdName)
SELECT 'Thread' UNION ALL
SELECT 'Button Thread' UNION ALL
SELECT 'Coat Thread';
SELECT ProdID, ProdName FROM Test;
That returns the following (notice that the auto-increment worked):
ProdID ProdName
------------------------------ ------------------------------
PR001 Thread
PR002 Button Thread
PR003 Coat Thread

How to update the id column starting from 1 again

I am having problem to update the list of id number again starting from 1,2,3,4,5. Since I have deleted few records as I was testing the sql commands. Can you please help on how to make this id column again starting from 1.
I could just the name of the id number however if I do that then when I input new record, it will again start from the previous number which was 66.
ID Name
1 A
32 B
34 C
35 D
55 E
66 F
Truncate your table first and then execute this
ALTER TABLE tablename AUTO_INCREMENT = 1
You should truncate the table to reseed it properly and not just use alter table
(tldr; it's usually better not to worry about the density or sequential order an auto-increment column.)
It is not possible1 to use an AUTO_INCREMENT to automatically fill in values less than MAX(ID).
However, the auto increment ID can be reset if existing IDs are updated. The compacting phase is required because MySQL does not allow "filling in gaps" via an auto-increment column.
Compact the existing IDs, like so:
SET #i := 0;
UPDATE t id = #i := (#i+1)
Important: Make sure that all relational usage is identified in the form of Foreign Key relations with CASCADE ON UPDATE before this is done or the data may become irreversibly corrupted.
Assign the auto-ID see to the maximum1 ID value after compacting:
ALTER TABLE t AUTO_INCREMENT = (SELECT MAX(id) FROM t)
1 Per the AUTO_INCREMENT documentation in ALTER TABLE:
You cannot reset the counter to a value less than or equal to the value that is currently in use .. if the value is less than or equal to the maximum value currently in the AUTO_INCREMENT column, the value is reset to the current maximum AUTO_INCREMENT column value plus one.
The rule means that it is not possible to set the increment ID lower than an already used ID; in addition, manually assigning a value higher will automatically raise the AUTO_INCREMENT value.
The easiest (and sometimest fastest) way is to remove column and add it back. Updating column may screw up indexes or make a mess with values. Droping whole table got no sense. But remember that if other columns refer to that ids you can damage your app.

How to get the ID (auto increment) of a record about to be uploaded?

I am using Laravel 3. I have a form, and 2 tables. One table has an AUTO INCREMENT ID and I want to give this ID to the second table. eg.
table1
ID: Auto increment
title:
text:
date:
table2
ID: Auto increment
t1_ID: table1->ID
text:
Is it possible somehow?
I think I can get the ID of the last record in table1 and add 1 to it in the controller, but maybe there is an easier way.
SOLUTION #1
This sounds like you need to use a trigger. To be safe you should use an AFTER INSERT trigger because you cannot predict if the autoincrement will increment more than once in the event of some unforeseen error during an INSERT.
Perhaps the trigger should look something like this:
DELIMITER $$
CREATE TRIGGER table1_ai AFTER INSERT ON table1 FOR EACH ROW
BEGIN
INSERT INTO table2 (t1_ID) VALUES (NEW.ID);
END; $$
DELIMITER ;
That way, the ID is safely placed in table2, knowing that the ID is in actual use in table1.
SOLUTION #2
You could retrieve the ID using the information_schema. How?
Suppose the table is mydb.table1. You can quickly get the next auto_increment value like this:
SELECT auto_increment FROM information_schema.tables
WHERE table_schema='mydb' and table_name='table1';
This could be risky to retrieve if mydb.table1 experiences high-volume writes
EPILOGUE
You should go with SOLUTION #1, since implementing the trigger would handle the ID's placement in two tables without you having to code it.

Avoid entering duplicate entries based on date, without using select statement

I am running a insert statement to insert data, but I want to check for any duplicate entries based on date and then do an entry.
All I want is if today a user enters product_name='x', 'x' is unique so that no one can enter product name x again today. But of course the next day they can.
I do not want to run a select before the insert to do the checking. Is there an alternative?
You can either use
1. Insert into... on duplicate update
2. insert.. ignore
This post will answer your question
"INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
You can use the mysql insert into... on duplicate update syntax which will basically enter in a new row if one isn't there, or if the new row would have caused a key constraint to kick in, then it can be used to update instead.
Lets say you have the following table:
MyTable
ID | Name
1 | Fluffeh
2 | Bobby
3 | Tables
And ID is set as the primary key in the database (meaning it CANNOT have two rows with the same value in it) you would normally try to insert like this:
insert into myTable
values (1, 'Fluffster');
But this would generate an error as there is already a row with ID of 1 in it.
By using the insert on duplicate update the query now looks like this:
insert into myTable
values (1, 'Fluffster')
on duplicate key update Name='Fluffster';
Now, rather than returning an error, it updates the row with the new name instead.
Edit: You can add a unique index across two columns with the following syntax:
ALTER TABLE myTable
ADD UNIQUE INDEX (ID, `name`);
This will now let you use the syntax above to insert rows while having the same ID as other rows, but only if the name is different - or in your case, add the constraint on the varchar and date fields.
Lastly, please do add this sort of information into your question to start with, would have saved everyone a bit of time :)

incremental counter mysql

My question is pretty simple but answer might be tricky.
I'm in PHP and I want to manage manually a unique ID for my objects.
What is tricky is to manage atomicity. I dont want that 2 elements get the same ID.
"Elements" are grouped in "Groups". In each group I want elements ID starting from 1 and grow incrementally for each insert in that group.
My first solution is to have a "lastID" column in the table "Groups" :
CREATE TABLE groups ( id INT AUTO_INCREMENT, lastId INT )
CREATE TABLE elements ( myId INT, multiple values ...)
In order to avoid many elements with the same ID, I have to update lastId and select it in an atomic SQL Query.
After that, one retrieved, I have a unique ID that can't be picked again and I can insert my element.
My question is how to solve the bold part ? My database is MySQL with MyISAM engine so there is no transaction support.
UPDATE groups
SET lastId = lastId + 1
WHERE id = 42
SELECT lastId
FROM groups
WHERE id = 42
Is there something more atomic than these 2 requests ?
Thanks
UPDATE groups SET lastId = last_insert_id(lastId + 1)
and then you can get your new id with
SELECT last_insert_id()
Using last_insert_id with a parameter will store the value and return it when you call it later.
This method of generating autonumbers works best with MyISAM tables having only a few rows (MyISAM always locks the entire table). It also has the benefit of not locking the table for the duration of the transaction (which will happen if it is an InnoDB table).
This is from the MySQL manual:
If expr is given as an argument to LAST_INSERT_ID(), the value of the
argument is returned by the function and is remembered as the next
value to be returned by LAST_INSERT_ID(). This can be used to simulate
sequences:
Create a table to hold the sequence counter and initialize it:
CREATE TABLE sequence (id INT NOT NULL);
INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
UPDATE sequence SET id=LAST_INSERT_ID(id+1);
SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter
and causes the next call to LAST_INSERT_ID() to return the updated
value. The SELECT statement retrieves that value. The
mysql_insert_id() C API function can also be used to get the value.
See Section 21.8.3.37, “mysql_insert_id()”.
You can generate sequences without calling LAST_INSERT_ID(), but the
utility of using the function this way is that the ID value is
maintained in the server as the last automatically generated value. It
is multi-user safe because multiple clients can issue the UPDATE
statement and get their own sequence value with the SELECT statement
(or mysql_insert_id()), without affecting or being affected by other
clients that generate their own sequence values.
One option is for you to use the nifty MyISAM feature that let's auto_increment values be incremented for each group.
CREATE UNIQUE INDEX elements_ix1 ON elements (groupId, myID)
myID INT NOT NULL AUTO_INCREMENT
That's more "atomic" than anything that involves updating a separate table. Note that this only works for MyISAM, not InnoDB.
excerpt from http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
MyISAM Notes
For MyISAM tables, you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.
I would assume your MySQL installation also has InnoDB engine which does support transactions. You just need to change the engine type of you tables.

Categories