MySQL INSERT if a identical entire row doesn't exist - mysql

I have a table with 10 columns and I have to add many, many rows from a CSV file. Of course, I must not add two identical rows, so I need a SQL statement that ignore the command if the entire row does exists. The INSERT must be ignored only if all fields are identical. Two rows may have identical field1 or field2, but not all fields identical.
I tried INSERT IGNORE but it doesn't work. No column is set as UNIQUE, as the INSERT must be ignored onyl only if the entire row is identical.
What solution do you have for this? Thanks!

Create a combined index on all columns, then INSERT IGNORE or REPLACE INTO according to your needs.
From the docs:
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.

Related

MySQL: Insert multiple values if they don't exist, but need a multiple column check

I have a simpe query like so:
INSERT INTO myTable (col1, col2) VALUES
(1,2),
(1,3),
(2,2)
I need to do a check that no duplicate values have been added BUT the check needs to happen across both column: if a value exists in col1 AND col2 then I don't want to insert. If the value exists only in one of those columns but not both then then insert should go through..
In other words let's say we have the following table:
+-------------------------+
|____col1____|___col2_____|
| 1 | 2 |
| 1 | 3 |
|______2_____|_____2______|
Inserting values like (2,3) and (1,1) would be allowed, but (1,3) would not be allowed.
Is it possible to do a WHERE NOT EXISTS check a single time? I may need to insert 1000 values at one time and I'm not sure whether doing a WHERE check on every single insert row would be efficient.
EDIT:
To add to the question - if there's a duplicate value across both columns, I'd like the query to ignore this specific row and continue onto inserting other values rather than throwing an error.
What you might want to use is either a primary key or a unique index across those columns. Afterwards, you can use either replace into or just insert ignore:
create table myTable
(
a int,
b int,
primary key (a,b)
);
-- Variant 1
replace into myTable(a,b) values (1, 2);
-- Variant 2
insert ignore into myTable(a,b) values (1,2);
See Insert Ignore and Replace Into
Using the latter variant has the advantage that you don't change any record if it already exists (thus no need to rebuild any index) and would best match your needs regarding your question.
If, however, there are other columns that need to be updated when inserting a record violating a unique constraint, you can either use replace into or insert into ... on duplicate key update.
Replace into will perform a real deletion prior to inserting a new record, whereas insert into ... on duplicate key update will perform an update instead. Although one might think that the result will be same, so why is there a statement for both operations, the answer can be found in the side-effects:
Replace into will delete the old record before inserting the new one. This causes the index to be updated twice, delete and insert triggers get executed (if defined) and, most important, if you have a foreign key constraint (with on delete restrict or on delete cascade) defined, your constraint will behave exactly the same way as if you deleted the record manually and inserted the new version later on. This means: Either your operation fails because the restriction is in place or the delete operation gets cascaded to the target table (i.e. deleting related records there, although you just changed some column data).
On the other hand, when using on duplicate key update, update triggers will get fired, the indexes on changed columns will be rewritten once and, if a foreign key is defined on update cascade for one of the columns being changed, this operation is performed as well.
To answer your question in the comments, as stated in the manual:
If you use the IGNORE modifier, errors that occur while executing the INSERT statement are ignored. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row is discarded and no error occurs. Ignored errors may generate warnings instead, although duplicate-key errors do not.
So, all violations are treated as warnings rather than errors, causing the insert to complete. Otherwise, the insert would be applied partially (except when using transactions). Violations of duplicate key, however, do not even produce such a warning. Nonetheless, all records violating any constraint won't get inserted at all, but ignore will ensure all valid records get inserted (given that there is no system failure or out-of-memory condition).

MySQL: Making 2 values unique

I'm trying to make 2 values unique, like if I have the values (5, 10) the same values can't be added again.
I'm currently selecting from the table the values x and y, checking if they both together exists on the table if they don't exists insert them, in other words
"Select * from location where x=? and y=?"
if no result is returned it will continue to insert the values.
This is typically accomplished by creating a unique index on both columns combined (a multi-column index).
Then, MySQL will prevent you from inserting duplicates. You can go ahead and try to insert the record, and if you get a duplicate key error, you know it already exists.
Alternatively, another way to handle it is to use INSERT IGNORE, so that no error occurs if you try to insert a duplicate row. Still, it won't insert, so you simply check the affected ROW_COUNT() to see if the insert was successful.
Using a unique index and catching the failure on the insert is more performant than selecting then trying to insert because in the case you do insert, MySQL only has to perform one search, rather than two.

If statement in multiple SQL triggers

I need some help with MySQL triggers, and my guess is it should be quite simple. I have a db which consists of 3 tables (trable1, table2, table3), each of these has two columns (column1, column2). So here is what I need. If a row is inserted into table1, I want it to be automaticaly replicated to table2 and table3. Likewise with updates on table2 and table3. But here is a trick, I heed an if condition, which checks if the row is already there, otherwise SQL throws me an error. I would be really grateful for any help.
Do you want it to throw an error or do you want to avoid it?
In the first case, you could do something like
IF EXISTS (SELECT 1 FROM table2or3 WHERE col1 = NEW.col1) THEN
SIGNAL ...
END IF;
Read more about signals here.
If you don't want to throw an error there's also the possibility to
INSERT INTO foo(col1, col2) VALUES (NEW.col1, NEW.col2)
ON DUPLICATE KEY UPDATE whatever = whatever;
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed.
Read more about it here.
Or
INSERT IGNORE ....
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.
Read more about it here.

Adding a row with a certain value if it isn't in the table

I have a table setup with a UNIQUE column called, for example, test. I want to insert a row with the column test only if there isn't already a row in the table with test. I know I could just do the INSERT query and it would throw up an error if it already existed (and wouldn't really cause any harm AFAIK), but is there a way to do this properly using only MySQL? I'm pretty sure it can be done with functions but I've never used those before and I think there's an easier way.
Sounds like a job for INSERT IGNORE:
If you use the IGNORE keyword, errors
that occur while executing the INSERT
statement are treated as warnings
instead. For example, without IGNORE,
a row that duplicates an existing
UNIQUE index or PRIMARY KEY value in
the table causes a duplicate-key error
and the statement is aborted. With
IGNORE, the row still is not inserted,
but no error is issued.
Something like this should work
INSERT INTO TABLE(column1,column2)
SELECT value1, value2
WHERE 1 NOT IN (SELECT 1 FROM TABLE WHERE test='test')
You can use the IGNORE keyword, like this:
INSERT IGNORE INTO table_name (test) VALUES('my_value');
From the MySQL documentation:
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.
If you want to update the existing row rather than ignore the duplicate update entirely, check out the ON DUPLICATE KEY UPDATE syntax.
INSERT IGNORE (v,b,g) VALUES(1.2.3)
will do nothing if you hit keys (primary or unique) but you should know your keys then.
or just as John said, with preselcted data

How do I insert data into a mysql database using a procedure?

I have a single procedure that has two insert statements in it for two different tables. I must insert data into table1 before I can insert into table2. I'm using PHP to do the data collection. What I'd like to know is how to insert multiple rows into table2, which can have many rows associated with table1. How would I do this?
I want to only store the person in table1 just one time but table2 requires multiple rows. If these insert statements were in separate procedures, I wouldn't have a problem but I just don't know how I would insert more than one row into table2 without table1 rejecting a second duplicate record.
BEGIN
INSERT INTO user(name, address, city) VALUES(Name, Address, City);
INSERT INTO order(order_id, desc) VALUES(OrderNo, Description);
END
I'd suggest you do it separately, otherwise you'd need a complicated solution which is prone to error if something changes.
The complicated solution is:
join all orderno and descriptions with a separator. (orderno#description)
join all orders with a different separator. (orderno#description/orderno#description/...)
pass it to the procedure
in the procedure, split the string by order separator, then loop through each of them
for each order, split the string by the first separator, then insert into the appropriate columns
As you can see, this is bad.
I am sorry, but what's stopping you from inserting data into these (seemingly unrelated) tables in separate queries? If you don't like the idea of it failing halfway through, you can wrap it into a transaction. I know, mysqli and pdo can do that just fine.
Answering your question directly, insert's ignore mode turns errors during insertion into warnings, so upon attempting to insert a duplicate row the warning is issued and the row is not inserted, but there is no error.
You could use the IGNORE keyword on the first statement.
http://dev.mysql.com/doc/refman/5.1/en/insert.html:
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.But somehow this seems rather inefficient to me, a "stabbed from behind through the chest in the eye"-solution.