I have two tables. One is permission_index and the other is permission_index_bkp.
My script is supposed to transfer some rows and data from permission_index to permission_index_bkp. However, I don't want to create new rows if the data in all 4 columns is the same.
This is what I am trying to use:
INSERT INTO permission_index_bkp
(b_app, b_perm_type, b_perm_type_id, b_perm_3)
SELECT app, perm_type, perm_type_id, perm_3
FROM permission_index
WHERE app = 'module'
AND perm_type = '1'
AND perm_type_id = '2'
AND perm_3 IS NOT NULL
ON DUPLICATE KEY UPDATE app = app,
perm_type = perm_type,
perm_type_id = perm_type_id,
perm_3 = perm_3;
I've been getting errors like:
1052: Column 'app' in field list is ambiguous (I think I fixed this by changing columns' name in permission_index_bkp).
or
1054: Unknown column 'app' in 'field list'
Could you guys tell me how to fix my query?
Thanks!!
EDIT 1:
This has made the errors disappear, however, rows keep being added in permission_index_bkp, even though they have the same values:
INSERT INTO permission_index_bkp
(b_app, b_perm_type, b_perm_type_id, b_perm_3)
SELECT app, perm_type, perm_type_id, perm_3
FROM permission_index AS pi
WHERE app = 'module'
AND perm_type = '1'
AND perm_type_id = '2'
AND perm_3 IS NOT NULL
ON DUPLICATE KEY UPDATE b_app = b_app,
b_perm_type = b_perm_type,
b_perm_type_id = b_perm_type_id,
b_perm_3 = b_perm_3;
Use VALUES() in the ON DUPLICATE KEY clause to specify that you want to update a column to the value that would have been inserted.
And you need to be assigning to the column names in the destination table, not the names in the table you're selecting from, so they should all be b_XXX.
INSERT INTO permission_index_bkp
(b_app, b_perm_type, b_perm_type_id, b_perm_3)
SELECT app, perm_type, perm_type_id, perm_3
FROM permission_index
WHERE app = 'module'
AND perm_type = '1'
AND perm_type_id = '2'
AND perm_3 IS NOT NULL
ON DUPLICATE KEY UPDATE
b_app = VALUES(b_app),
b_perm_type = VALUES(b_perm_type),
b_perm_type_id = VALUES(b_perm_type_id),
b_perm_3 = VALUES(b_perm_3);
Also, you don't need to include the unique key column(s) in the ON DUPLICATE KEY UPDATE clause.
Though I never used this syntax but after doing some search in google I found that you need to declare an unique key on all four columns of your permission_index table to remove duplicate entries.
Please check below example:
create table test (a int, b int);
insert into test values(1,1);
insert into test values(1,2);
create table test2 (a int, b int,
UNIQUE KEY uktest2 (a,b));
INSERT INTO test2
(a,b)
SELECT a,b
FROM test b
WHERE a=1
ON DUPLICATE KEY UPDATE a = b.a,
b=b.b;
select * from test;
select * from test2;
Output:
table test:
a
b
1
1
1
2
table test2:
a
b
1
1
1
2
insert into test values(1,3);
insert into test values(1,1);
INSERT INTO test2
(a,b)
SELECT a,b
FROM test b
WHERE a=1
ON DUPLICATE KEY UPDATE a = b.a,
b=b.b;
select * from test;
select * from test2;
Output:
table test:
a
b
1
1
1
2
1
3
1
1
table test2:
a
b
1
1
1
2
1
3
db<fiddle here
Related
I want to ignore duplicates (or update key on duplicates), but only on consecutive duplicates.
Say my initial table looks like this (uk and a are column names):
uk a
----
x 1
Iteration 1 inserts 1 so I want this to be ignored in order to avoid duplicates.
Iteration 2 inserts 2 and my table now looks like this:
uk a
----
x 1
x 2
Iteration 3 inserts 1 and because the last row where my unique key = x was different to 1 then I want 1 to be inserted again:
uk a
----
x 1
x 2
x 1
How can this be achieved in MySQL?
My current solution is to query in data from the table first and remove these duplicates, but I would prefer that it was handled by MySQL.
You need a column that will be an auto-increment primary key
CREATE TABLE your_table(
id INT NOT NULL AUTO_INCREMENT,
uk CHAR(30) NOT NULL,
a INT,
PRIMARY KEY (id)
);
INSERT INTO your_table(uk, a) VALUES ('x', 1)
now you can use the following insert command to avoid duplicates as you describe it
INSERT INTO your_table(uk, a)
SELECT 'x', 1 FROM your_table t1
JOIN (
SELECT max(id) maxid, uk
FROM your_table
GROUP BY uk
) t ON t.maxid = t1.id and
t1.a != 1 and
t.uk = 'x'
The second insert can be the following
INSERT INTO your_table(uk, a)
SELECT 'x', 2 FROM your_table t1
JOIN (
SELECT max(id) maxid, uk
FROM your_table
GROUP BY uk
) t ON t.maxid = t1.id and
t1.a != 2 and
t.uk = 'x'
The third insert will be the same as the first one and the result table will be as expected.
See the demo
From your table it is not visible, which values got inserted last. Data in a table is considered unordered. So for your last example we know there are the three records x|1, x|1, x|2 in the table, but not whether x|1 or x|2 was inserted last. You'd need an additional column to indicate this. This could be a datetime or an ascending ID.
If you don't want to change your table, you need a helper table containing the last record instead. Anyway, you'd write a before-insert trigger to look up the last inserted value and throw an error when the new record matches the last inserted record for th uk.
create table mytable(uk char(1), a int);
create table mytable_helper(uk char(1), a int, primary key (uk));
create trigger mytable_ins BEFORE INSERT ON mytable FOR EACH ROW
begin
DECLARE msg VARCHAR(128);
if exists (select * from mytable_helper h where new.uk = h.uk and new.a = h.a) then
set msg = concat('Consecutive duplicate for a = ', new.a, ' and uk = ''', new.uk, '''.');
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = msg;
else
replace into mytable_helper (uk, a) values (new.uk, new.a);
end if;
end;
insert into mytable (uk, a) values ('x', 1);
insert into mytable (uk, a) values ('x', 2);
insert into mytable (uk, a) values ('x', 1);
insert into mytable (uk, a) values ('y', 3);
insert into mytable (uk, a) values ('x', 1);
Error(s), warning(s):
Consecutive duplicate for a = 1 and uk = 'x'.
REXTESTER http://rextester.com/XOG65602
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');
I ran some query and got a set of tuples like ((A1,B1), (A2,B2), (A3,B3)....).
I need to check if a tuple from above set exists in a table XYZ(A,B,C). If it exists, then update C else insert (Ax,Bx,C) into the table.
I tried using the below query but it doesn't work. Is there any other way?
CASE WHEN EXISTS (SELECT * from XYZ as t where (t.A, t.B) in (select u.A, u.B from diff_table as u)) THEN
THEN UPDATE XYZ as v SET C = 1 WHERE (v.A, v.B) = (t.A, t.B) ELSE
INSERT INTO XYZ (A,B,C) values (u.A, u.B, 1) END;
I'd do it the other way round:
Update the ones that exist
Insert the ones that don't
Or if you have primary keys
Insert all with default value for C (existing will get rejected)
Update all
The functionality you want is insert . . . on duplicate key insert.
First, you need an appropriate index (if you don't have one):
create index idx_xyz_a_b on xyz(a, b)
Then:
insert into xyz(a, b, c)
select dt.a, dt.b, 1
from diff_table dt
on duplicate key update set c = 1;
By the way, if the value already exists, are you sure you want to set it to 1 instead of incrementing it?
insert into xyz(a, b, c)
select dt.a, dt.b, 1
from diff_table dt
on duplicate key update set c = c + 1;
I have two tables, with same schema -
create table test1 (
a INT NOT NULL ,
b INT NOT NULL ,
c INT,
PRIMARY KEY (a,b)
);
create table test2 (
a INT NOT NULL ,
b INT NOT NULL ,
c INT,
PRIMARY KEY (a,b)
);
I want to insert values from test2 table into test1, but if the row with same primary key already exist, update it. I know in mysql you can do similar thing with ON DUPLICATE KEY UPDATE like -
INSERT INTO test1 VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=3;
But I dont know how to do the above query with a SELECT from another table. What I am looking for is a query of form -
INSERT INTO test2
SELECT a, b, c FROM test1
ON DUPLICATE KEY UPDATE c = c + t.c
(Select a, b, c from tests1)t;
This query is obviously invalid. I would appreciate if somebody can make a valid query out of it.
This should work for you:
INSERT INTO test2
SELECT a, b, c as c1 FROM test1
ON DUPLICATE KEY UPDATE c = c + c1
You could do it with this SQL:
INSERT INTO test1 (a, b, c)
SELECT t.a as a, t.b as b, t.c AS c FROM test2 AS t
ON DUPLICATE KEY UPDATE c=t.c;
It depends, I use the PK autoincrement feature, for Row Unique identifier, I split a big table, so the small one have changes I can't miss, I read several opinions, even merge and remake PK that's do not work for me. The result set in Memory looks like if you don't mention the full columns name you will have errors. I did this and work, I hope some body have a better and smaller solutions:
>INSERT
>INTO t_traffic_all
>SELECT
>t_traffic.file_id,
>t_traffic.cust,
>t_traffic.supp,
>.
>. (a lot...)
>.
>t_traffic.i_traffic_type,
>t_traffic.date_posted,
>t_traffic.date_update
>FROM t_traffic
>ON DUPLICATE KEY UPDATE
>t_traffic_all.file_id = t_traffic.file_id,
>t_traffic_all.cust = t_traffic.cust,
>t_traffic_all.supp = t_traffic.supp,
>t_traffic_all.imprt = t_traffic.imprt,
>.
>.
>.
>t_traffic_all.i_traffic_type= t_traffic.i_traffic_type,
>t_traffic_all.date_posted= t_traffic.date_posted,
>t_traffic_all.date_update= t_traffic.date_update
> Affected rows: 11128
> Time: 29.085s
the total rows processed where 18608, so it insert 11128 and update 7480 (7554 should be) this numbers do not are very precise but the result was.
I'm trying to insert an ingredient to an ingredients table if it doesn't exist.
I'm using the following syntax:
INSERT INTO ingredient(Name)
(
SELECT 'ingName' FROM dummytable WHERE
(SELECT count(*) FROM ingredient WHERE Name = 'ingName')=0)
This does not seem to work (0 rows affected), even though the SELECT query seem to return the desired result (an entry which contains "ingName").
The "ingredient" table has 2 columns: Name, id (id is auto incremented)
Thanks,
Li
Its better to add unique index on the name column:
ALTER TABLE `ingredient` ADD UNIQUE(`Name`)
After doing that you can use INSERT IGNORE:
INSERT IGNORE INTO `ingredient` ... /* anything */
That's because your inner query SELECT count(*) FROM ingredient WHERE Name = 'ingName' is returning a value > 0 and hence the upper query SELECT 'ingName' FROM dummytable WHERE is not selecting any rows and so no insert is happening.
I tried the same with a test table having 2 column name|value and it did worked fine
INSERT INTO test1(name) (
SELECT 'name' FROM test2 WHERE
(
SELECT count(*) FROM test2 WHERE name = 'bilboa'
)
=0
)
Inserted 2 rows with value name cause that's what I am selecting in select query and my test table 2 rows.