If I have the following column in database:
Email
aaa#gmail.com
ccc#gmail.com
ddd#gmail.com
ccc#gmail.com
bbb#gmail.com
aaa#gmail.com
I would like to ALTER THE TABLE and create a unique ID column based on the 'Email' column. Like the following:
Email Email_ID
aaa#gmail.com 001
ccc#gmail.com 002
ddd#gmail.com 003
ccc#gmail.com 002
bbb#gmail.com 004
aaa#gmail.com 001
I would suggest that you use an integer for the value -- rather than a string. Then, you can use variables as for the assignment:
alter table t add email_id int;
update t join
(select email, (#rn := #rn + 1) as rn
from (select distinct email from t order by email) t cross join
(select #rn := 0) params
) tt
on t.email = tt.email
set t.email_id = tt.rn;
If you run the subquery, you will see that this assigns to each email a distinct number.
The outer query then assigned this number into the email_id column. In MySQL 8+, you could also write:
alter table t add email_id int;
update t join
(select email, row_number() over (order by email) as rn
from (select distinct email from t order by email) t
) tt
on t.email = tt.email
set t.email_id = tt.rn;
If you are using MySQL version 8 or later, then DENSE_RANK provides a nice option here:
SELECT
Email,
LPAD(CAST(DENSE_RANK() OVER (ORDER BY Email) AS CHAR(3)), 3, '0') AS Email_ID
FROM yourTable
ORDER BY
Email;
I would have suggested maybe just adding an auto increment column to your table, but that wouldn't quite meet your requirements, because an auto increment column would always be unique.
Here's what I'd do...
Create a new table with a unique email column
CREATE TABLE `emails` (
id INT(3) PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) UNIQUE
);
Seed it with your current data
INSERT INTO `emails` (`email`)
SELECT DISTINCT `email` FROM `some_mystery_table`
ORDER BY `email`;
Alter your existing tables to reference emails(id) as a foreign key. This could be a little tricky as you'd need to (probably)
Add a new int column email_id where required
Update your data with the id value corresponding to the email address
UPDATE some_mystery_table, emails
INNER JOIN emails ON some_mystery_table.email = emails.email
SET some_mystery_table.email_id = emails.id;
Remove the email column
Add a foreign key where email_id references emails(id)
When displaying your data and you need a zero-padded email id, join the emails table, eg
SELECT a.whatever, e.email, LPAD(e.id, 3, '0') AS email_id
FROM some_mystery_table a
INNER JOIN emails e ON a.email_id = e.id;
When adding new email records, you add them to emails first, then use the generated id in any other related tables.
ALTER TABLE emails add column `email_id` int(5) ZEROFILL PRIMARY KEY AUTO_INCREMENT;
SET #x:=0;
UPDATE emails SET email_id = LPAD(#x:= (#x+1),4, '0') WHERE 1=1;
We first added the column email_id to the table emails and set it as primary key, using this query:
ALTER TABLE emails add column `email_id` int(5) ZEROFILL PRIMARY KEY AUTO_INCREMENT;
Then we declared a global variable called x with a default value of 0:
SET #x:=0;
And finally, we filled the column with the incremental zero filled id:
UPDATE emails SET email_id = LPAD(#x:= (#x+1),4, '0') WHERE 1=1;
We used LPAD to zero fill.
Related
I am trying to to split a table into two table and want to add the reference (foreign key) of one table to another
For Example lets say there are is a table called customer table and an Column in it called Group Name has repetitive data which goes against data normalization, so I want to split the table on that column, which would be to replace that Group name Column with GroupID column
NOW form a new table with 2 column GroupID and Group Name and insert distinct Group values into GroupName column, with an auto-incrementing GroupID which will be the Primary key in the group table, and be refrenced in Customer table to act as a foreign key
Now the main question is how to Insert those Autoincremented GroupID of 'GROUP TABLE' into groupID of the customer Table or how do You Insert Foreign Keys into Customer Table According to the Main table
The customerTable With GroupID and customerTable With Customer_Group are two diffrent table
UPDATE ch03.customerd
JOIN ch03.group gr ON customer.Customer_Group = gr.Group_Name
SET customerd.Group_ID = gr.Group_id
WHERE customerd.Customer_id = customer.Customer_id;
update ch03.customerd set Group_ID =
(select gr.Group_id
from ch03.customer as co
join ch03.group as gr on co.Customer_Group = gr.Group_Name)
where customerd.Customer_id = customer.Customer_id;
this is what i have tried and isn't working
If all data except group_id is already transferred then
UPDATE new_customer_table nc
JOIN old_customer_table oc ON nc.customer_id = oc.customer_id
JOIN new_group_table ng ON oc.customer_group = ng.group_name
SET nc.group_id = ng.group_id
If new tables are empty yet then
INSERT INTO new_group_table (group_name)
SELECT DISTINCT customer_group
FROM old_customer_table;
INSERT INTO new_customer_table (customer_id, .. , customer_age, group_id)
SELECT oc.customer_id, .. , oc.customer_age, ng.group_id
FROM old_customer_table oc
JOIN new_group_table ng ON oc.customer_group = ng.group_name;
PS. If customer_group in old table is not defined as ENUM / have no CHECK constraint which checks entered values for validity then I recommend to execute INSERT INTO new_group_table .. firstly and check the values inserted carefully. If some misprintings will be found then you need to edit source data before, then truncate new_group_table and repeat - until all group names are correct.
I have a database with a list of API key. I need to associate an email and a name with these. I want my query to update the name and email on the first row that has null as the email.
id key name email
'1', '3046GUGYi7ab', NULL, NULL
'2', 'TXQzL33HVp1W', NULL, NULL
'3', 'YIK6DAnTVU4n', NULL, NULL
My attempt is this, But apparently, you cant use the same table in a subquery.
UPDATE key_table
set email="test#x.com", `name`="test"
where id = (Select min(id) from key_table
where email=null);
I'm sure there is a simpel soultion for this? Any ideas?
My attempt is this, But apparently, you cant use the same table in a
subquery.
UPDATE key_table
set email="test#x.com", `name`="test"
where id = (Select min(id) from key_table
where email=null);
You need to wrap the inner query within a extra subquery if you use the same table name.
The query below should work.
Query
UPDATE
key_table
SET
email = "test#x.com"
, name = "test"
WHERE
id = (
SELECT
min_id
FROM (
SELECT
MIN(id) AS min_id
FROM
key_table
WHERE
email IS NULL
)
AS key_table
)
Try this
UPDATE key_table
SET email="test#x.com", `name`="test"
WHERE ID=1;
This will only affect the first row and change the value
Hope this helps
I have table called users and for example it looks like:
Name ID
Tom 1
Al 55
Kate 22
...
The problem is: the IDs are not in sequence.
I would like to give them new IDs from 1 to length of users. I would like to declare some var=1 and make UPDATE in loop and give them new ID = var, and later do var=var+1 until var <= users length
How can I do this?
Thank you very much!
Here is how you would do that in MySQL. Just run this:
set #newid=0;
update users set ID = (#newid:=#newid+1) order by ID;
If the ID in the Users table is not referenced by other tables by FK, the following query can update the ID in the table to have new consecutive values:
CREATE TABLE IF NOT EXISTS tmpUsers (
ID int not null,
newID int not null auto_increment primary key
) engine = mysisam;
INSERT INTO tmpUsers (ID,newID)
SELECT ID,NULL
FROM users
ORDER BY ID;
UPDATE users u INNER JOIN tmpUsers t
ON u.ID=t.ID
SET u.ID=t.NewID;
DROP TABLE IF EXISTS tmpUsers;
Test script:
CREATE TABLE users (ID int not null, name nvarchar(128) not null);
INSERT users(ID,name)
VALUES (1,'aaa'),(4,'bbb'),(7,'ggg'),(17,'ddd');
SELECT * FROM users;
I have got an older database for which (at some really questionable and obscure reason I do not like to put too much on topic here) I want to randomize or shuffle the primary keys.
I right now have auto-increment fields in the Mysql database tables.
I have not many relations, those that exist are not defined as foreign keys. The relationships do not need to be preserved.
All I'm looking for is to take the current values of the primary keys and replace it with a random value out of those like:
ID := new(ID)
Where the new function returns a value from the set of all OLD ids with a 1:1 match. E.g.
2 := 3
3 := 2
But not
2 := 3
3 := 3
Is there a way to change the data in the database with (ideally) a single SQL query per table?
Edit: I do not have really strict requirements. Consider to have exclusive access to the database if it helps, including changing constraints on the primary key back and forth, e.g. alter the table, do the operation, alter the table to previous schema. It is also possible to add another column for the new (or old) PK value.
Just a scetch of the procedure. Create two temporary tables
CREATE TABLE temp_old
( ai INT NOT NULL AUTO_INCREMENT
, id INT NOT NULL
, PRIMARY KEY (ai)
, INDEX old_idx (id, ai)
) ENGINE = InnoDB ;
CREATE TABLE temp_new
( ai INT NOT NULL AUTO_INCREMENT
, id INT NOT NULL
, PRIMARY KEY (ai)
, INDEX new_idx (id, ai)
) ENGINE = InnoDB ;
Copy the id values in different orders to the two tables (randomly in the 2nd table):
INSERT INTO temp_old
(id)
SELECT id
FROM tableX
ORDER BY id ;
INSERT INTO temp_new
(id)
SELECT id
FROM tableX
ORDER BY RAND() ;
Then we drop the primary key:
ALTER TABLE tableX
DROP PRIMARY KEY ;
to run the actual UPDATE statement:
UPDATE tableX AS t
JOIN temp_old AS o
ON o.id = t.id
JOIN temp_new AS n
ON n.ai = o.ai
SET t.id = n.id ;
Then recreate the primary key and drop the temp tables:
ALTER TABLE tableX
ADD PRIMARY KEY (id) ;
DROP TABLE temp_old ;
DROP TABLE temp_new ;
Tested in SQL-Fiddle
Here's a technique that creates a list of your ids in table order, along with a sequential number from 1, it also creates a list of your ids in a random order, along with a sequential number from 1. It then updates the ids based on matching the sequential number.
There are issues with the performance of order by rand(), (and it's randomness).
If your keys are already sequential starting from 1, you can simplify this.
Update
Test as t
Inner Join (
Select
#rownum2 := #rownum2 + 1 as rank,
t2.id
From
Test t2,
(Select #rownum2:= 0) a1
) as o on t.id = o.id
Inner Join (
Select
#rownum := #rownum + 1 as rank,
t3.id
From
(Select id from Test order by Rand()) t3,
(Select #rownum:= 0) a2
) as n on o.rank = n.rank
Set
t.id = n.id
http://sqlfiddle.com/#!2/3f354/1
You could create a stored procedure that would create a temporary table containing all of the ids, then you can loop over each record, replacing the id with an id from the temp table then removing that id from the temp table. I don't believe there is a way to do what you are talking about in a single query though.
I want to create a table employee with id,name,dept,username attributes.
The id column values are auto_increment. I want to concatenate the values of id with dept to generate the username.
Following is the query that I wrote:
create table employee emp_id MEDIUMINT NOT NULL AUTO_INCREMENT, name char(30) NOT NULL, dept char(6)NOT NULL, username varchar NOT NULL PRIMARY KEY(emp_id);
How to insert values into this table properly? Please help.
If your usernames will always be the concatenation of id and dept, you don't need to create a separate column for it, you can just select it using the MySQL CONCAT function, like this:
SELECT id, name, dept, CONCAT(id, '-', dept) AS username FROM employee
This will return results for username like 13-sales.
If you want to actually store the username (maybe because you want the ability to customize it later), you'll have to first insert the row to get the id, and then update the row setting the username to the concatenated id and dept.
You can use null on MySQL for auto traslate as the last id:
INSER INTO employee (name, dept) VALUES (?,?);
UPDATE employee SET username = concant(emp_id,dept) WHERE emp_id = NULL;