Checking data on primary key violation in mysql - mysql

If I try to insert data into a table which already contains that primary key, it will clearly fail.
Is there a simple way to check whether the data I've failed to insert matches what is already in the table? (ie, if the non-primary key fields are the same as are already there for that primary key)
Ideally rather than get a single error, I would like to get 2 different errors when I attempt to insert a primary key that is already used:
- Error1: primary key constraint broken - data being inserted is already in table
- Error2: primary key constraint broken - attempt to enter different data for existing primary key

To check you can do something like this
SELECT COUNT(*) FROM
(
SELECT * FROM tab1
UNION
SELECT * FROM tab2
);
UNION removes duplicates so if rows in both tables are identical then above query will return identical result as
SELECT COUNT(*) FROM tab1;
OR
SELECT COUNT(*) FROM tab2;
Your question is not very detailed (e.g. how you insert this data?) so my answer in also quite generic, but I belive it will be useful for you.

Try it with this:
INSERT INTO yourTable (field1, field2, field3...)
SELECT yourValue1, yourValue2, yourValue3...
FROM dual
WHERE NOT EXISTS (SELECT *
FROM yourTable
WHERE field1 = yourValue1
AND field2 = yourValue2
AND field3 = yourValue3...);
This query checks your fields and only inserts when the record is not already there.

Related

Inserting To Table With Auto Increment MYSQL

Let's say I have created the following dimension table:
create table schema1.DOMAIN (
ID INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
DOMAIN_NAME VARCHAR(10)
);
And I have a table of logs with records where DOMAIN_NAME is a column. My goal here is to write an insert statement that will populate this dimension table with values for DOMAIN_NAME, but only when they don't already exist. For example:
INSERT INTO schema1.DOMAIN (ID, DOMAIN_NAME)
select distinct DOMAIN_NAME from LOGS l where not exists (select 1 from schema1.DOMAIN d where d.domain_name = l.domain_name);
I haven't actually run this on a MySQL db yet, but I have the following questions:
Notice I didn't supply a value for the ID column in schema1.DOMAIN for the insert. Does this matter? If it's not supplied, will it simply auto-increment the primary key? Or will it throw an error? Is there a way to avoid supplying this ID and have it auto-increment automatically? This is the desired behavior for me. What is the best way to do this?
Is there a more performant way to do this?
I want this to work whether schema1.DOMAIN is empty or already has records and we are dumping parsing a log for a new value. Are these two objectives not compatible.
1.Notice I didn't supply a value for the ID column in schema1.DOMAIN for the insert. Does this matter? If it's not supplied, will it simply auto-increment the primary key? Or will it throw an error? Is there a way to avoid supplying this ID and have it auto-increment automatically? This is the desired behavior for me. What is the best way to do this?
Ans.
INSERT INTO schema1.DOMAIN (DOMAIN_NAME)
select distinct DOMAIN_NAME from LOGS l where not exists (select 1 from schema1.DOMAIN d where d.domain_name = l.domain_name);
2.Is there a more performant way to do this?
Ans. Left outer join would perform better
3.I want this to work whether schema1.DOMAIN is empty or already has records and we are dumping parsing a log for a new value. Are these two objectives not compatible.
Ans. Seems compatible
The query you wanted to write - I just removed id from the list of columns for insert: it will auto-increment automatically for every insert:
insert into schema1.domain (domain_name)
select distinct domain_name
from logs l
where not exists (select 1 from schema1.domain d where d.domain_name = l.domain_name);
You could also use the insert ... on duplicate key syntax. This requires defining a unique constraint on the domain column:
create table schema1.domain (
id int auto_increment primary key not null,
domain_name varchar(10) unique
);
Then you can do:
insert into schema1.domain (domain_name)
select distinct domain_name from logs l
on duplicate key update domain = values(domain)
When a domain that already exists in the table is met, the query goes to the on duplicate key clause, where a dummy operation is performed.

How to merge two identical tables that have a primary key?

This seems like a simple task, but I am struggling to find a way to do this. I have two tables (A and B) with the same structure. Both have an auto-increment primary key. I want the data from table B to go in to table A. I tried:
insert into A select * from B
However I get an error that a primary key already exists. I would like the new rows from table B to get a new primary key when I insert them in to table A - so basically discard the primary key from B but insert all the other columns. Seems like it should be a simple query but I can't figure it out. Thank you.
You're also selecting (and inserting) the auto_increment id, which fails if such id already exists. To let mysql automatically assign id just select and insert all values besides the id:
INSERT INTO A (foo, bar, baz)
SELECT foo, bar, baz FROM B
You must specify the columns you are want to insert from table B to table A, since you want to create a new id you can use a query as follow assuming column1 is they key that we don't want to insert.
insert into A (column2, column3) select column2, column3 from B
You can also lookup at this link that has some good query examples.

Mysql, Insert new record into table B if foreign key exists in table A

There are a few similar questions on here. None provide a solution. I would like to INSERT a NEW record into table B, but only if a foreign key exists in table A. To be clear, I do not wish to insert the result of a select. I just need to know that the foreign key exists.
INSERT INTO tableB (tableA_ID,code,notes,created) VALUES ('24','1','test',NOW())
SELECT tableA_ID FROM tableA WHERE tableA_ID='24' AND owner_ID='9'
Clearly, the above does not work. But is this even possible? I want to insert the NEW data into tableB, only if the record for the row in tableA exists and belongs to owner_ID.
The queries I have seen so far relate to INSERTING the results from the SELECT query - I do not wish to do that.
Try this:
INSERT INTO tableB (tableA_ID,code,notes,created)
SELECT id, code, notes, created
FROM ( SELECT '24' as id, '1' as code, 'test' as notes, NOW() as created) t
WHERE EXISTS
(
SELECT tableA_ID
FROM tableA
WHERE tableA_ID='24' AND owner_ID='9'
)
I know it's a pretty much old answered question but it's highly ranked now in google search results and I think some addition may help someone in the future.
In some DB configuration, you may want to insert a row in a table that have two or more foreign keys. Let's say we have four tables in a chat application :
Users, Threads, Thread_Users and Messages
If we want a User to join a Thread we'll want to insert a row in Thread_Users in wich have two foreign keys : user_id, thread_id.
Then, we can use a query like this, to insert if both foreign keys exists, and silently fail otherwise :
INSERT INTO `thread_users` (thread_id,user_id,status,creation_date)
SELECT 2,3,'pending',1601465161690 FROM (SELECT 1 as nb_threads, 1 as nb_users) as tmp
WHERE tmp.nb_threads = (SELECT count(*) FROM `threads` WHERE threads.id = 2)
AND tmp.nb_users = (SELECT count(*) FROM `users` WHERE users.id = 3)
It's a little verbose but it does the job pretty well.
Application-side, we just have to raise an error if affectedRows = 0 and maybe trying to see which of the keys doesn'nt exists. IMHO, it's a better way to do the job than to execute two SELECT queries and THEN execute the INSERT especially when an inexistent foreign key probability is very low.

INSERT INTO...SELECT - Primary key conflict - error #1062

I have a database: groupofficecom has two tables:
cal_events: id(Primary key), name, start_time, description,....
cf_cal_events: model_id (Primary key), col_1, col_2, col_3,....
I'm trying to execute the following code:
INSERT INTO groupofficecom.cf_cal_events (model_id,col_1,col_2,....)
SELECT groupofficecom.cal_events.ID, '0' AS col_1, '' AS col_2,....
FROM groupofficecom.cal_events
But it keeps giving me error #1062 - Duplicate entry '155' ('155' is the 'id' from cal_events) for key 'PRIMARY'
I want the primary key model_id to be the same value as id in cal_events because the table cf_cal_events is just complementary fields for cal_events (this is a program, so I can't change its database, it'll be gone on the first update)
Thank you guys!
This means there already is an entry with that id in the target table.
First, check how this can be.
Then, use one of the solutions described here as is appropriate:
"INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE"
i.e. UPDATE or IGNORE.
You should use an ORDER BY with the select you have and the solution above to choose which entries get ignored (all but the first entry with IGNORE).
It is also possible that you want something different entirely, i.e. to use an UPDATE statement instead of an INSERT statement.
In fact I found a very good function, it's very similar to the INSERT but smarter:
REPLACE INTO database (column_1, column_2)
SELECT source_column1, 'value' AS column2
FROM table;
Or:
REPLACE INTO database (column_1, column_2)
VALUES ('value1', 'value2')
FROM table;
Works like magic!
It inserts new items to the destination table, and if it finds a row with the same primary key value, it erases it and re-inserts the new value (it works great for updating a table from another one)
I hope this solves your problem like it solved mine ;)

Removing duplicate rows from a MySql table

Similar questions were indeed asked, but I didn't find an answer.
I have a MySql table with 3 non-unique fields. I don't want duplicate rows. Meaning ("a", "b", "c") and ("a", "dasd", "dfsd") are okay (I don't mind having "a" twice in the first fields), but having ("a", "b", "c") twice is wrong.
I need a query which will remove duplicates, leaving only one row for each row group.
Edit This has already been covered on SO before.
One approach would be to create a new table based on the existing table. You could do this through something like:
create table myNewTable SELECT distinct * FROM myOldTable;
Then you could clear the old table's data, and create a unique constraint on the fields you don't want duplicated:
TRUNCATE TABLE myOldTable;
ALTER TABLE myOldTable
ADD UNIQUE (field1, field2);
Then insert your data back into the original table. Because you created myNewTable using DISTINCT, you should not have any duplicates.
INSERT INTO myOldTable SELECT * FROM myNewTable;
Note: It assumes we have primary key apart from column1 and column2 and column3. Also it assumes that last row should be preserved. Helpful when we have some other information also apart from column1,column2 and column3.
It saves the last primary key and delete the rest for unique values of Column1,Column2,Column3
Insert result of below query into a temp table
SELECT MAX(PrimaryKey)
FROM TABLENAME
GROUP BY Column1,Column2,Column3
Delete from TABLENAME where PrimaryKey NOT IN (SELECT PrimaryKey FROM TEMPTABLE)
If we have only these 3 columns, then
Save distinct in temp table
truncate original table
insert back into original from temp table.
You can retrieve a list of the duplicates like this:
SELECT field1, field2, field3, count(*) AS cnt
FROM yourtable
GROUP by field1, field2, field3
HAVING (cnt > 1)
You'll then have to delete the duplicate rows in subsequent seperate queries.
I will solve the problem by using a temporary table and subqueries to find the elements to erase. That will only work if your table 'yourTable' with the fields f1,f2,f3 has also an ID field that is unique.
Create the temporary table to store the IDs of the elements to erase.
CREATE TEMPORARY TABLE ids (ID int);
Find the IDs of the elements to erase:
INSERT INTO ids(ID) SELECT ID FROM yourTable AS t
WHERE 1 != (SELECT COUNT(*) FROM yourTable
WHERE yourTable.ID <= t.ID
AND yourTable.f1 = t.f1
AND yourTable.f2 = t.f2
AND yourTable.f3 = t.f3);
Delete the elements of the table with the previously selected indexes
DELETE yourTable FROM yourTable,ids WHERE yourTable.ID = ids.ID;
Remove the temporary table
DROP TABLE ids;
If SQL supported to to subqueries using the same table for a SELECT and a DELETE we could do all that in the same query, but this is not the case, so we need to go through a temporary table.
To avoir duplicates to happen I will set the three fields as primary keys of the table, in this way:
ALTER TABLE yourTable ADD PRIMARY KEY (f1, f2, f3);
You will be able to alter your table this way, only when you removed all the duplicates and once the table altered subsequent inserts with duplicated values will fail.