add duplicate value for primary key - mysql

I have a table with fields (id , brand, model , os)
id as primary key
tables have ~ 6000 rows
Now i want to add new field with id=4012 (already exist) & increment id++ for id>4012
silliest way :
make table backup
remove entries with id >= 4012
insert new entry with id = 4012
restore table from backup
stupid, but works ))
Looking for more beautiful solution
Thx
table structure :
CREATE TABLE IF NOT EXISTS `mobileslist` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`brand` text NOT NULL,
`model` text NOT NULL,
`os` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=14823 ;
i try :
UPDATE mobileslist SET id = id + 1 WHERE id IN (SELECT id FROM
mobileslist WHERE id >= 4822 ORDER BY id);
but got answer :
1093 - You can't specify target table 'mobileslist' for update in FROM clause

1) Create a temporary table, with descending order by ID.
2) Perform an UPDATE query on the temporary table which sets ID = ID + 1 WHERE ID >= 4012
3) Drop the temporary table
4) Perform your insert operation on the original table.

Hope i understood it right, you want to insert a new entry at position 4012 moving & reassigning all the entries present at Id = 4012 or more with a new id incremented by 1.
Hope this helps.
Try this:
UPDATE <TableName>
SET
id = id + 1
WHERE id IN (SELECT id FROM <TableName> WHERE id >= 4012 ORDER BY id)
INSERT INTO <TableName>
(id , brand, model , os)
VALUE
(4012, "<BrandName>", "<Model>", "<OS>")
Updated Answer:
DECLARE #MaxId INT, #Difference INT
SELECT
#MaxId = MAX(id)
FROM mobileslist
SET #Difference = #MaxId - 4012
UPDATE mobileslist
SET
id = id + #Difference
where id >= 4012
INSERT INTO mobileslist
(id , brand, model , os)
VALUE
(4012, "TestBrand", "TestModel", "TestOS")
UPDATE mobileslist
SET
id = id - #Difference
where id > 4012

Related

Add a line in between a SQL table and change following id

I would like to insert a row in the middle of my SQL table. Similar to Excel, the existing rows should then be automatically increased by ID+1. Is there such a function?
Example:
Current state:
After insert inbetween:
Please never do it in production.
Setup
create table tbl(
id int NOT NULL AUTO_INCREMENT primary key,
val varchar(20)
);
insert into tbl (val)
values
('a'),('b'),('c'),('d');
The script to add 'x' between 'b' and 'c' when ordered by id
update tbl
set id=id+1
where id > 2
order by id desc;
insert tbl(id, val)
values (3,'x');

How to insert if not exists with selecting from same table?

I have my table schema in H2 db as follows:
create table if not exists Test ( id bigint not null,name varchar(255), primary key (id) );
alter table Test add constraint if not exists Test_NAME UNIQUE (name);
I want to insert a value for the name attribute as 'Default' if it does not exist in the table by selecting the latest id value from the table and increment it by one.
Example:
Do not insert if an entry for name = Default already exists.
ID | Name
1 | Default
Insert if an entry for name = Default does not exists.
ID | Name
1 | ABC
2 | XYZ
For the id column, find the max id and increment it by one. In this case, insert id=3 and name=Default.
My query is as follows:
INSERT INTO Test (id , name)
SELECT max(id) + 1, 'Default' from Test
WHERE NOT EXISTS (SELECT * FROM Test where name='Default');
However, it gives me an error saying:
NULL not allowed for column "ID"; SQL statement
as it applies the where condition on the inner select statement.
I also tried:
MERGE INTO Test KEY(name) VALUES (SELECT MAX(id) + 1 from Test, 'Default');
It gives an error because, merge tries to update with the new values.
If it finds 'Default', it will update the row with new id causing primary key violation.
Is there a better way to do this? How can I make the query work?
You are massively overcomplicating this. Define the id field as auto increment and place a unique index on the name field. The unique index prevents duplicate names to be inserted, while the auto increment increases the value of the id field by 1 (by default) if the insert is successful.
I updated id to auto increment and the following query work flawlessly
INSERT INTO Test (name) select * from (select 'Default') as tmp WHERE NOT EXISTS (SELECT name from Test where name='Default');
when you run your query first time, no record found in table so, it give error 'null' there, so if you add IFNULL() function there as below
INSERT INTO Test (id , name)
SELECT **IFNULL**(max(id),0) + 1, 'Default'
FROM Test
WHERE NOT EXISTS (SELECT * FROM Test where name='Default');

Rename columns in SQL

I want to (directly) generate a table with the content from 2 columns of another table. How ca I change the names of the columns (rename them in the new table)?
Here´s an example:
CREATE TABLE X AS
SELECT
Table1.name,
Table1.act
FROM Y
->I don´t want to name the columns "name" and "act" as in the original table - I want to have "name" replaced by "customer" and "act" replaced by "status"
Do it like this:
CREATE TABLE X AS
SELECT
Table1.name as customer,
Table1.act as status
FROM Y
You could just specify name aliases in the query:
CREATE TABLE X AS
SELECT
Table1.name AS customer,
Table1.act AS status
FROM Y
Alternatively, you could specify the column definitions in brackets after the table name:
CREATE TABLE X (customer VARCHAR(10), status VARCHAR(10)) AS
SELECT
Table1.name,
Table1.act
FROM Y
You will need to use a While Loop to do that:
$my_query = "SELECT * FROM tj_ethnicity FROM Table_X";
while($row = mysql_fetch_assoc($my_query))
{
$new_query = "CREATE TABLE `."$row['customer']".` (
`customerid` int(11) NOT NULL AUTO_INCREMENT,
`status` varchar(50) DEFAULT ."$row['status']".,
`created` datetime NOT NULL,
PRIMARY KEY (`customerid`)
)";
}

MySQL loop for every row and update

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;

How to add and populate a sequence column to a link table

Assuming I have a table like the one below:
create table filetype_filestatus (
id integer(11) not null auto_increment,
file_type_id integer(11) not null,
file_status_id integer(11) not null,
)
I want to add a sequence column like so:
alter table filetype_filestatus add column sequence integer(11) not null;
alter table filetype_filestatus add unique key idx1 (file_type_id, file_status_id, sequence);
Now I want to add the column, which is straightforward, and populate it with some default values that satisfy the unique key.
The sequence column is to allow the user to arbitrarily order the display of file_status for a particular file_type. I'm not too concerned by the initial order since that can be revised in the application.
Ideally I would end up with something like:
FileType FileStatus Sequence
1 1 1
1 2 2
1 3 3
2 2 1
2 2 2
The best I can think of is something like:
update filetype_filestatus set sequence = file_type_id * 1000 + file_status_id;
Are there better approaches?
Hmm, I believe this should work:
UPDATE filetype_filestatus as a
SET sequence = (SELECT COALESCE(MAX(b.sequence), 0)
FROM filetype_filestatus as b
WHERE b.file_type_id = a.file_type_id) + 1
WHERE sequence = 0
I'd recommend adding the new column to the table, running the alter table statement (and getting the default of 0), run the update statement, then add the constraint (well, you have to anyways). Anything that gets touched updates to a sequence greater than 0, so this can be safely run multiple times, too.
EDIT:
As #Dems has pointed out, the subquery is being run before the update, and so the above doesn't actually work for this purpose. It does work on single-line inserts (which doesn't help at all here).
EDIT:
Gah, you have an id column, this works just fine (and yes, I tested this one first).
UPDATE filetype_filestatus as a
SET sequence = (SELECT COALESCE(COUNT(*), 0)
FROM filetype_filestatus as b
WHERE b.file_type_id = a.file_type_id
AND b.id < a.id) + 1
WHERE sequence = 0
Don't know about the performance implications, though.
If all you need are "some values that conform to idx1", why not just copy the id field? It is, after all, unique...
UPDATE
filetype_filestatus
SET
sequence = id;
EDIT
How to get sequential values based on the OPs changes to the question being asked.
ROW_NUMBER() is not available in MySQL, and it is also my understanding that you can't use the table being updated in the source query as well.
create temporary table temp_filetype_filestatus (
id integer(11) not null auto_increment,
file_type_id integer(11) not null,
file_status_id integer(11) not null,
PRIMARY KEY (file_type_id, file_status_id)
)
INSERT INTO temp_filetype_filestatus (
file_type_id,
file_status_id
)
SELECT
file_type_id,
file_status_id
FROM
filetype_filestatus
ORDER BY
file_type_id,
file_status_id
-- Update Option 1
------------------
UPDATE
filetype_filestatus
SET
sequence
=
(SELECT id FROM temp_filetype_filestatus
WHERE file_type_id = filetype_filestatus.file_type_id
AND file_status_id = filetype_filestatus.file_status_id)
-
(SELECT id FROM temp_filetype_filestatus
WHERE file_type_id = filetype_filestatus.file_type_id
ORDER BY file_status_id ASC LIMIT 1)
+
1
-- Update Option 2
------------------
UPDATE
filetype_filestatus
SET
sequence
=
(SELECT COUNT(*) FROM temp_filetype_filestatus
WHERE file_type_id = filetype_filestatus.file_type_id
AND file_status_id <= filetype_filestatus.file_status_id)