MySQL "insert.... where not exists" is coming up all errors - mysql

This works:
insert into answers
(survey,user,answer)
values(1,'hi',1)
;
This works:
select * from answers where survey=1 and user='hi';
This doesn't work:
insert
into answers
(survey,user,answer)
values(1,'hi',1)
where not exists (select * from answers where survey=1 and user='hi')
;
It gives me an error 1064 right around the "where not exists" clause. I've looked up all the documentation I can find, but I can't find anything wrong with it.
Thoughts?

You can do this with insert . . . select, but not insert . . . values:
insert into answers(survey, user, answer)
select survey, user, answer
from (select 1 as survey, 'hi' as user, 1 as answer) s
where not exists (select 1 from answers a where a.survey= s.survey and a.user = s.user);
That said, I would advise you to make answer(survey, user) either a unique or primary key, so the database enforces the uniqueness constraint.

Syntax for the INSERT statement in MySQL (https://dev.mysql.com/doc/refman/5.6/en/insert.html) has no "where not exists".
What you probably want is INSERT IGNORE INTO answers (survey,user,answer) values(1,'hi',1). This inserts the values unless it clashes with a primary or unique key on the table, in which case the values are ignored.

Indeed, the INSERT INTO ... VALUES ... notation doesn't support a WHERE clause. Instead, you need to use the INSERT INTO ... SELECT ... notation, where you specify an actual query to generate the rows to insert. That query can, of course, contain a WHERE clause:
insert
into answers
(survey,user,answer)
select 1,'hi',1
from (select 1)
where not exists (select * from answers where survey=1 and user='hi')
;

Related

ERROR 1093 (HY000): Nested select on insert [duplicate]

Clearly the following is incorrect.
INSERT INTO `aTable` (`A`,`B`) VALUES((SELECT MAX(`A`) FROM `aTable`)*2),'name');
I get the value:
SQL query:
INSERT INTO `aTable` (`A`, `B` )
VALUES
(
(
SELECT MAX(`A`)
FROM `aTable`
) *2
, 'name'
)
MySQL said:
1093 - You can't specify target table 'aTable' for update in FROM clause
So, I'm trying to make a bitmap table, each row corresponds to one Bit, and has a 'map' value.
To insert in the table, I don't want to do two queries, I want to do one.
How should I do this?
No one commented on this, but since I am trying to make a bitmap, it should be * 2 not ^ 2, my mistake, please note that is why the comments often say ^ 2, it was an error in the version that the commenters read.
try:
insert into aTable select max(a)^2, 'name' from aTable;
or
insert into aTable select max(a)^2, 'name' from aTable group by B;
If you need a join, you can do this:
insert into aTable select max(a)^2, 'name' from aTable, bTable;
My "Server version" is "5.0.51b-community-nt MySQL Community Edition (GPL)"
Actually, you can alias the table on the insert. I've seen this question all over the place, but no one seems to have tried that. Use a subquery to get the max from the table, but alias the table in the subquery.
INSERT INTO tableA SET fieldA = (SELECT max(x.fieldA) FROM tableA x)+1;
A more complex example, where you have a corresponding secondary key and might be inserting the FIRST record for the corresponding secondary key:
INSERT INTO tableA SET secondaryKey = 123, fieldA = COALESCE((SELECT max(x.fieldA) FROM tableA x WHERE x.secondaryKey = 123)+1,1);
By aliasing the table, it doesn't throw the error and seems to work. I just did this while coding something, although I can't see if there area any silly syntax errors above, I would try that type of syntax.
I take it that INSERT ... SELECT isn't working? I see this in the documentation for it:
The target table of the INSERT
statement may appear in the FROM
clause of the SELECT part of the
query. (This was not possible in some
older versions of MySQL.) In this
case, MySQL creates a temporary table
to hold the rows from the SELECT and
then inserts those rows into the
target table.
Out of curiosity, which version of MySQL are you using?
I think you need to drop the "VALUES", and have a valid select statement.
see this link
I'm not particularly a mySQL guy, I use MSSQL mostly. But If you format the select statement correctly, It should work.
as soon as the Select is correct you can do this.

In SQL, can you nest a SELECT statement in the VALUES clause of the INSERT statement?

In SQL is it possible to nest a SELECT statement in the VALUES clause of the INSERT statement? I'm using MySQL and would like to query the table for the max value of a field plus one when creating a new record, as shown below.
INSERT into attornies (
LawOfficeId, LawOfficeName
) VALUES (
(select max(LawOfficeID)+1 from attornies),
'Wee, Sue Em and Howe'
);
I'm not sure if my syntax is bad, what I'm trying to do is not possible, etc. Of course, If I try this as two separate statements it works but I would like to make it one statement. I know one suggestion is to use auto increment but I don't want to.
If this question has already been answered please point me in that direction. If not .... Help.
Yes you can do it
INSERT into attornies (
LawOfficeId, LawOfficeName
)
select max(LawOfficeID) + 1,'Wee, Sue Em and Howe' from attornies;
However this is not recommended over auto increment since you are likely going to run into duplicate primary key situation if multiple threads are doing the insert
Your query should work. Scalar subqueries are allowed in the values clause of the insert.
In general, it would more commonly be written as:
insert into attornies (LawOfficeId, LawOfficeName)
select max(LawOfficeID)+1, 'Wee, Sue Em and Howe'
from attornies;
However, this is not the right way to do what you seem to want. Instead, create attornies -- which I am renaming to lawOffices because that seems to be the intention -- with an auto-increment column:
create table lawOffices (
lawOfficeId int auto_increment primary key,
lawOfficeName varchar(255)
);
And then do:
insert into lawOffices (lawOfficeName)
values ( 'Wee, Sue Em and Howe' );
The database does the work of incrementing the id.
You can't use the syntax you show.
mysql> INSERT into attornies (
-> LawOfficeId, LawOfficeName
-> ) VALUES (
-> (select max(LawOfficeID)+1 from attornies),
-> 'Wee, Sue Em and Howe'
-> );
ERROR 1093 (HY000): You can't specify target table 'attornies' for update in FROM clause
https://dev.mysql.com/doc/refman/8.0/en/subquery-errors.html says:
You can use a subquery for assignment within an UPDATE statement because subqueries are legal in UPDATE and DELETE statements as well as in SELECT statements. However, you cannot use the same table (in this case, table t1) for both the subquery FROM clause and the update target.
The doc is talking about using a subquery in an UPDATE statement, but the same rule applies in an INSERT or DELETE statement.
However, this works:
mysql> INSERT into attornies (
-> LawOfficeId, LawOfficeName
-> )
-> select max(LawOfficeID) + 1,'Wee, Sue Em and Howe' from attornies;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
https://dev.mysql.com/doc/refman/8.0/en/insert-select.html says:
The target table of the INSERT statement may appear in the FROM clause of the SELECT part of the query. However, you cannot insert into a table and select from the same table in a subquery.
When selecting from and inserting into the same table, MySQL creates an internal temporary table to hold the rows from the SELECT and then inserts those rows into the target table.
I agree with the other answers and comments who warn you against using the MAX()+1 method of getting the next id value. This method is susceptible to race conditions. Use an auto-increment column instead.
Okay, you've all convinced me. In addition, I did a bit of testing of import/export with an auto-increment field in MySQL. My concerns are no longer justified. I'll discard my max()+1 idea as unnecessary and go with auto-increment.
I would also like to thank Steve, Bill Karwin and Gordon Linoff for correcting my SQL and pointing me in the proper direction if I had continued with my original idea.

Some problems with INSERT INTO statement

I have this mysql syntax:
INSERT INTO `utilizatori`(
utilizator
)
SELECT
'Mama'
FROM
`utilizatori`
WHERE
NOT EXISTS (SELECT `utilizator` FROM `utilizatori` WHERE utilizator='Mama')
utilizatori is a table, utilizator is a column, Mama is a value
This syntax will insert a value in table only if it doesnt exist.If the value exist it wont create it,so until now it works fine,but if there is no 'Mama' value,then it will insert it...the only problem is that it will insert it multiple times.For example if i have 4 rows,it will insert 'Mama' value 4 times,creating 4 rows.Any idea??
I would make the task easier, clearer by making utilizator field unique.
That way when you add new rows with existing value 'Mama' for utilizator in this case: mysql returns error with the code: 1062, and don't let user have multiple rows with Mama in the table.
So when you run query:
INSERT INTO `utilizatori` (utilizator) VALUES ('Mama')
You can check if MySQL returns any error, but better to check number of affected rows, if insert was successful it will be equal to 1 otherwise 0.
Checking mechanism depends what language and driver you use for connecting to database.
Since you had PHP tag selected you may be using PDO than
$statement->rowCount(); // $statement = PDOStatement, I assume you know this thing well
will give you desired result
Final simple example:
...
if ($statement->rowCount())
{
echo "Cool! You have been added to database";
}
else
{
echo "Hmms! Are you trying to duplicate something?";
}
Try to use group by :
INSERT INTO `utilizatori`(
utilizator
)
SELECT
'Mama'
FROM
`utilizatori`
WHERE
NOT EXISTS (SELECT `utilizator` FROM `utilizatori` WHERE utilizator='Mama')
group by utilizator
You are basically doing:
SELECT ... WHERE NOT EXISTS
...and inserting this in your table. As stated in the comments, just make your utilizator field unique and drop the whole SELECT part from your query.
Where Column is missing...
INSERT INTO `utilizatori`(
utilizator
)
SELECT
'Mama'
FROM
`utilizatori`
WHERE
'Mama'
NOT EXISTS (SELECT `utilizator` FROM `utilizatori` WHERE utilizator='Mama')

How do I make a MySQL insert query that "inserts if not exists"?

INSERT INTO table('name') VALUES("abc") IF NOT EXISTS name='abc'
If abc doesn't exist in the name column, then insert it. How can I write that query?
INSERT IGNORE INTO table(name) VALUES('abc')
This will ignore the value if it already exists. Like pjotr said, this will require name to be a unique index.
Source
Try:
insert into table('name')
select 'abc'
where not exists (select 1 from table where name='abc')
You may either use REPLACE (syntax, or, equivalent INSERT ON DUPLICATE KEY UPDATE). This is more appropriate if there's more columns and you want to update the others for the given key.
Or the IGNORE modifier (INSERT syntax) along with a unique index for the 'name' column. In that case, the insert will be ignored if it violates the unique index, but won't throw an error. That's more appropriate if you don't want to change any values and just keep the record if it already exists.
One way to do it is testing it with an IF:
IF (select count(*) from table where name = 'abc') = 0
THEN
INSERT INTO table('name') VALUES("abc")
I would enforce the column as UNIQUE and catch the exception on the code side, if you have a unicity constraint on that field. Otherwise I tend to agree with other answers.
I have Some Code...hope it will help you..
mysql_query("INSERT INTO authors (author) VALUES ('$rec_fic_author')
WHERE NOT EXISTS (SELECT * FROM authors WHERE author='$rec_fic_author')")
or die("cannot insert author");
here author is the name of table
authorID (pk)
author $rec_fic_author is _POST variable

Prevent auto increment on MySQL duplicate insert

Using MySQL 5.1.49, I'm trying to implement a tagging system
the problem I have is with a table with two columns: id(autoincrement), tag(unique varchar) (InnoDB)
When using query, INSERT IGNORE INTO tablename SET tag="whatever", the auto increment id value increases even if the insert was ignored.
Normally this wouldn't be a problem, but I expect a lot of possible attempts to insert duplicates for this particular table which means that my next value for id field of a new row will be jumping way too much.
For example I'll end up with a table with say 3 rows but bad id's
1 | test
8 | testtext
678 | testtextt
Also, if I don't do INSERT IGNORE and just do regular INSERT INTO and handle the error, the auto increment field still increases so the next true insert is still a wrong auto increment.
Is there a way to stop auto increment if there's an INSERT duplicate row attempt?
As I understand for MySQL 4.1, this value wouldn't increment, but last thing I want to do is end up either doing a lot of SELECT statements in advance to check if the tags exist, or worse yet, downgrade my MySQL version.
You could modify your INSERT to be something like this:
INSERT INTO tablename (tag)
SELECT $tag
FROM tablename
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Where $tag is the tag (properly quoted or as a placeholder of course) that you want to add if it isn't already there. This approach won't even trigger an INSERT (and the subsequent autoincrement wastage) if the tag is already there. You could probably come up with nicer SQL than that but the above should do the trick.
If your table is properly indexed then the extra SELECT for the existence check will be fast and the database is going to have to perform that check anyway.
This approach won't work for the first tag though. You could seed your tag table with a tag that you think will always end up being used or you could do a separate check for an empty table.
I just found this gem...
http://www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/
INSERT INTO [table name] SELECT '[value1]', '[value2]' FROM DUAL
WHERE NOT EXISTS(
SELECT [column1] FROM [same table name]
WHERE [column1]='[value1]'
AND [column2]='[value2]' LIMIT 1
)
If affectedRows = 1 then it inserted; otherwise if affectedRows = 0 there was a duplicate.
The MySQL documentation for v 5.5 says:
"If you use INSERT IGNORE and the row is ignored, the AUTO_INCREMENT counter
is **not** incremented and LAST_INSERT_ID() returns 0,
which reflects that no row was inserted."
Ref: http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
Since version 5.1 InnoDB has configurable Auto-Increment Locking. See also http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc...
Workaround: use option innodb_autoinc_lock_mode=0 (traditional).
I found mu is too short's answer helpful, but limiting because it doesn't do inserts on an empty table. I found a simple modification did the trick:
INSERT INTO tablename (tag)
SELECT $tag
FROM (select 1) as a #this line is different from the other answer
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
Replacing the table in the from clause with a "fake" table (select 1) as a allowed that part to return a record which allowed the insert to take place. I'm running mysql 5.5.37. Thanks mu for getting me most of the way there ....
The accepted answer was useful, however I ran into a problem while using it that basically if your table had no entries it would not work as the select was using the given table, so instead I came up with the following, which will insert even if the table is blank, it also only needs you to insert the table in 2 places and the inserting variables in 1 place, less to get wrong.
INSERT INTO database_name.table_name (a,b,c,d)
SELECT
i.*
FROM
(SELECT
$a AS a,
$b AS b,
$c AS c,
$d AS d
/*variables (properly escaped) to insert*/
) i
LEFT JOIN
database_name.table_name o ON i.a = o.a AND i.b = o.b /*condition to not insert for*/
WHERE
o.a IS NULL
LIMIT 1 /*Not needed as can only ever be one, just being sure*/
Hope you find it useful
You can always add ON DUPLICATE KEY UPDATE Read here (not exactly, but solves your problem it seems).
From the comments, by #ravi
Whether the increment occurs or not depends on the
innodb_autoinc_lock_mode setting. If set to a non-zero value, the
auto-inc counter will increment even if the ON DUPLICATE KEY fires
I had the same problem but didn't want to use innodb_autoinc_lock_mode = 0 since it felt like I was killing a fly with a howitzer.
To resolve this problem I ended up using a temporary table.
create temporary table mytable_temp like mytable;
Then I inserted the values with:
insert into mytable_temp values (null,'valA'),(null,'valB'),(null,'valC');
After that you simply do another insert but use "not in" to ignore duplicates.
insert into mytable (myRow) select mytable_temp.myRow from mytable_temp
where mytable_temp.myRow not in (select myRow from mytable);
I haven't tested this for performance, but it does the job and is easy to read. Granted this was only important because I was working with data that was constantly being updated so I couldn't ignore the gaps.
modified the answer from mu is too short, (simply remove one line)
as i am newbie and i cannot make comment below his answer. Just post it here
the query below works for the first tag
INSERT INTO tablename (tag)
SELECT $tag
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
I just put an extra statement after the insert/update query:
ALTER TABLE table_name AUTO_INCREMENT = 1
And then he automatically picks up the highest prim key id plus 1.