INSERT or UPDATE from another table in mysql - mysql

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.

Related

Update if tuple is in the set, else insert in 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;

MYSQL How to create a UNIQUE constraint on two columns any combinations (in both directions)

If I have mySQL table with two row, how can I make make a constraint that same value can't be on both cols to the same time and prevent creating doubles of any combinations of both columns?
For example, if I insert the following :
col1 col2
a b ok
c a ok
c b ok
c a not ok sure it's already in the table
a c not ok because it's already in the table in other combination (c a)
f f not ok because same value in both columns
Long time ago, I found this on net.
Lets say, you have table, named tableName then you have to create a primary key which includes both column.
create table tableName
(
col1 int not null,
col2 int not null,
primary key (col1,col2)
);
But creating primary key does not solve your problem for checking vice versa combination. For that, you have to create a trigger which check uniqueness for both side.
DELIMITER $$
CREATE TRIGGER tableName_bi BEFORE INSERT ON tableName FOR EACH ROW
BEGIN
DECLARE found_count,newcol1,newcol2,dummy INT;
SET newcol1 = NEW.col1;
SET newcol2 = NEW.col2;
SELECT COUNT(1) INTO found_count FROM tableName
WHERE col1 = newcol2 AND col2 = newcol1;
IF found_count = 1 THEN
SELECT 1 INTO dummy FROM information_schema.tables;
END IF;
END; $$
DELIMITER ;
Note : Change your table and column name according to yours.

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!

Unique constraint on 2 columns, but in normal and reverse order

Couldn't find any answer, so I'm writing this open question. I'm curious if is there any possibility to create such UNIQUE constraint on 2 columns in SQL Server 2008 table, that "normal" and "reverse" duplicates wouldn't be allowed.
Example:
ID1 = 10, ID2 = 20 -- existing row
Trying to add a pair of values:
ID1 = 10, ID2 = 20 -- not allowed because of the UNIQUE key
ID1 = 20, ID2 = 10 -- allowed
The second row will be inserted (of course it's not a duplicate). And that's the issue. Can any key/constraint/whatever be set on a table to disallow above insertion? I.e. something using an expression instead of list of columns? For now I use a trigger which checks for such "duplicates", but I just wonder if is there any simpler solution.
Thanks,
Peter P.
CREATE TABLE dbo.test
(ID1 int , ID2 int ,
CONSTRAINT ID_UK UNIQUE(ID1,ID2),
)
GO
IF EXISTS (SELECT name FROM sysobjects
WHERE name = 'check_val' AND type = 'TR')
DROP TRIGGER check_val
GO
CREATE TRIGGER check_val
ON dbo.test
FOR INSERT, UPDATE
AS
if exists ( select i.ID1 ,i.ID2 from inserted i inner join dbo.test t
on t.ID2=i.ID1 and t.ID1=i.ID2 )
RAISERROR ('duplicate values',
16, 1)
ROLLBACK TRANSACTION
GO
insert dbo.test
select 10,20
union
select 20,10
I just needed the exact same thing (just a couple years later)
I decided to go with a check constraint that requires ID1 to be less than ID2
i know that's kinda of hacky, which is why i'm not convinced it's better than the trigger.
now when i insert data, ID1 has to be the smaller else the check constraint fails, that coupled with the unique constraint ensures only one instance of the combination exists.
I'm not anti-trigger, just prefer to not use them unless i really need to
--create your table
create table dbo.test
(
ID1 int not null,
ID2 int not null
)
go
--create a unique constraint the prevents duplicate of id1 and id2
create unique index test_ID1_ID2_uindex
on test (ID1, ID2)
go
--create a check that ensures id1 is less than id2, disallowing something like Id1=20, id2=10
ALTER TABLE dbo.Test
ADD CONSTRAINT CHK_Test_ID1_Less_ID2 CHECK (ID1<ID2);
GO
--this will fail
insert dbo.test
select 10,20
union
select 20,10

MySQL reference to field in another row

I want a MySQL field to be able to reference the same field in another row and return that field's value when loaded into PHP.
For instance, if row with id = 1 has value "bar" in column foo, the row with id = 3 should have value "[1]" (or something similar; the 1 is pointing to the row with id = 1) in column foo and MySQL should replace that value with "bar" when returning the array.
I'm not talking about an UPDATE query. I am trying to build a SELECT query that will make the appropriate replacement. I want [1] to be the permanent value of that row, and reflect whatever foo in the referenced row should happen to be.
You could try something like this but without knowing more, your mileage may vary.
Also, simply use 1, not [1] as the reference value
SELECT a.id, b.foo
FROM `foo_table` a
INNER JOIN `foo_table` b
ON CAST(a.foo AS UNSIGNED) = b.id
WHERE a.id = 3 -- or whatever
Update
I'd be more inclined to make your table design more specific. For example, try this structure
CREATE TABLE `foo_table` (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
foo VARCHAR(255),
parent_id INT NULL,
FOREIGN KEY (parent_id) REFERENCES `foo_table` (id)
ON DELETE CASCADE
) ENGINE=INNODB;
Then your query can be
SELECT a.id, COALESCE(b.foo, a.foo) AS foo
FROM foo_table a
LEFT JOIN foo_table b
ON a.parent_id IS NOT NULL
AND a.parent_id = b.id;