Update if tuple is in the set, else insert in MySQL - mysql

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;

Related

how to insert data into table based on conditions on the other table

i have to insert values in one of my columns in table based on restrictions on another table . these are the conditions. i have two tables A and B . A has a column a , and values in column a is dependent on values in table B. lets say there are b,c,d columns in B. now conditions are these if value of d='Y' , value in a is 1 , if value in b&c are same value of a is 2 and else value is 3 . so i wrote this code . A and B have same primary key values thus same number of rows
select b ,c,d from B case when d='Y' then insert into A(a) values(1);
else case when b=c then insert into A(a) values(2); else insert into
A(a) values(3); end case end case ;
now there seems to be a syntax error , but i feel my fundamentals are weak in this topic. i think this can easily be done using cursor or loops , but data sets are huge so i don't think this would be feasible
Try this way:
insert into A(a)
select case
when d = 'Y' then 1
when b = c then 2
else 3
end
from B

Insert multiple rows in single query and update existing

Is it possible to insert multiple rows in single query but in the same time check if record exist and update existing record?
I have to avoid REPLACE INTO because my table have primary and unique keys.
I'm not sure where to put ON DUPLICATE KEY in my query?
insert into mytable (A, B C) values
('a','b',1),
('c','d',2),
('e','f',3) ON DUPLICATE KEY UPDATE A = VALUES(A), B = VALUES(B), C = VALUES(C)
This is solution:
insert into mytable (A, B C) values
('a','b',1),
('c','d',2),
('e','f',3) ON DUPLICATE KEY UPDATE A = VALUES(A), B = VALUES(B), C = VALUES(C)
Thanks to all!

MySQL swap primary key values

The accepted answer to sql swap primary key values fails with the error Can't reopen table: 't' - presumably this has something to do with opening the same table for writing twice, causing a lock.
Is there any shortcut, or do I have to get both, set one of them to NULL, set the second one to the first one, then set the first one to the previously fetched value of the second?
Don't use temporary tables for this.
From the manual:
You cannot refer to a TEMPORARY table more than once in the same query.
For example, the following does not work:
mysql> SELECT * FROM temp_table, temp_table AS t2;
ERROR 1137: Can't reopen table: 'temp_table'
This error also occurs if you refer to a temporary table multiple
times in a stored function under different aliases, even if the
references occur in different statements within the function.
UPDATE:
Sorry if I don't get it right, but why does a simple three way exchange not work?
Like this:
create table yourTable(id int auto_increment, b int, primary key(id));
insert into yourTable(b) values(1), (2);
select * from yourTable;
DELIMITER $$
create procedure pkswap(IN a int, IN b int)
BEGIN
select #max_id:=max(id) + 1 from yourTable;
update yourTableset id=#max_id where id = a;
update yourTableset id=a where id = b;
update yourTableset id=b where id = #max_id;
END $$
DELIMITER ;
call pkswap(1, 2);
select * from yourTable;
To swap id values of 1 and 2, I would use a SQL statement like this:
EDIT : this does NOT work on an InnoDB table, only works on a MyISAM table, per my testing.
UPDATE mytable a
JOIN mytable b ON a.id = 1 AND b.id = 2
JOIN mytable c ON c.id = a.id
SET a.id = 0
, b.id = 1
, c.id = 2
For this statement to work, the id value of 0 must not exist in the table, any unused value would be suitable... but to get this to work in a single SQL statement, you need to (temporarily) use a third id value.
This solution works for regular MyISAM tables, not temporary tables. I missed that this was being performed on a temporary table, I was confused by the error message you reported Can't reopen table:.
To swap id values 1 and 2 in a temporary table, I'd run three separate statements, again, using a temporary placeholder value of 0:
UPDATE mytable a SET a.id = 0 WHERE a.id = 1;
UPDATE mytable b SET b.id = 1 WHERE b.id = 2;
UPDATE mytable c SET c.id = 2 WHERE c.id = 0;
Edit: Fixed errors

Is there such a thing as a reverse foreign key?

In MySQL, is there a way to specify that a.column cannot exist in b.column - a reverse foreign key?
In other words:
# Would not return any rows ever
SELECT * FROM a
INNER JOIN b ON a.column = b.column;
# Would fail
INSERT INTO a
SELECT * FROM b;
# Would not insert any rows
INSERT IGNORE INTO a
SELECT * FROM b;
No there is no such thing.
You would need to do that in a trigger:
DELIMITER $$
CREATE TRIGGER bi_a_each BEFORE INSERT ON a FOR EACH ROW
BEGIN
DECLARE forbidden_key INTEGER;
SELECT id INTO forbidden_key FROM b WHERE b.id = NEW.acolumn LIMIT 1;
IF forbidden_key IS NOT NULL THEN
SELECT * FROM error_insertion_of_this_value_is_not_allowed;
END IF;
END $$
DELIMITER ;
To a point, if you want "can be in A or B, but not both"
This is the "super key/sub type" pattern
Create a new table AB that has a 2 columns
SomeUniqueValue, PK
WhichChild char(1), limited to 'a' or 'b'
There is also a unique constraint on both columns
Then
Add a WhichChild column to tables A and B. In A, it is always 'a'. In B, always 'b'
Add foreign keys from A to AB and B to AB on both columns
Now, SomeUniqueValue can be in only A or B.
Note: in proper RDBMS you'd use check constraints or computed columns to restrict WhichChild to 'a' or 'b' as needed. But MySQL is limited so you need to use triggers in MySQL. However, this is simpler then testing table B for each insert in A etc
Try to create a trigger and throw an error from it.

finding value of column after ON DUPLICATE KEY UPDATE

Consider this statement:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE d=d+1;
I need the value of d.
Is it possible to obtain it without performing a further SELECT?
There is a unique index on a,b,c. Would this index be used for better performance? This table will have a large number of rows.
Assuming you will be running both queries using the same connection, You can use the LAST_INSERT_ID(expr) function to set the current value of d, and check the value of LAST_INSERT_ID() together with the ROW_COUNT() function to find out if the record was inserted or updated:
INSERT INTO table (a,b,c)
VALUES (1,2,3)
ON DUPLICATE KEY UPDATE d = LAST_INSERT_ID(d + 1);
SELECT IF(ROW_COUNT() = 2, LAST_INSERT_ID(), 0 /*default value*/) ;
You can also use session variables:
INSERT INTO table (a,b,c)
VALUES (1,2,3)
ON DUPLICATE KEY UPDATE d = #tmp := (d + 1);
SELECT IF(ROW_COUNT() = 2, #tmp, 0 /*default value*/) ;