Some problems with INSERT INTO statement - mysql

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')

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.

Database INSERT INTO SET ... WHERE(SELECT ...)

I am trying to insert my values into table if Admin_User_Role_Id value against Admin_Id is not present in the table. Is it possible to insert!
My Table Structure:
Admin_User_Id (FK)
Admin_User_Role_Id (FK)
Is_Enabled (boolean flag)
Query which I tried, but not success
INSERT INTO role_association
SET Admin_User_Id=61, Admin_User_Role_Id=2, Is_Enabled=0
WHERE Admin_User_Role_Id
NOT IN
(SELECT Admin_User_Id, Admin_User_Role_Id FROM role_association)
I think it is possible but my logic is wrong. How should I manage this query to work successfully!
INSERT syntax cannot have WHERE clause. The only time you will find INSERT has WHERE clause is when you are using INSERT INTO...SELECT statement.
Probably you take care about where condition in your programming logic and write a simple insert statement and the depending on your logic use this statement to insert the records. Hope you got my point.
You want to insert your values in your table using this query for your reference
INSERT INTO Yourtablename(column1,column2,column3,...)
VALUES ('value1','value2','value3',.....);
You want to ADD one new column in your table means using this query
** ALTER TABLE table_name ADD column_name datatype**

How make insert if select rows == '0' in one query?

In mysql, I have the following:
Structure Table:
id(int primary key)
name(varchar 100 unique)
Values:
id name
1 test
2 test1
I have two queries:
1) SELECT count(*) FROM Table WHERE name='test'
2) if count select rows == 0 second query INSERT INTO Table (name) VALUES ('test')
I know that may be use:
$res = mysql(SELECT count(*) as count FROM Table WHERE name='test');
// where mysql function make query in db
$i = $res -> fetch_assoc();
if($i['count'] < 1 ){$res = mysql(INSERT INTO Table (name) VALUES ('test');}
But I would like know how to make two query in one query.
How do I make one query inside of two?
You can do it with a simple trick, like this:
insert into Table1(name)
select 'test' from dual
where not exists(select 1 from Table1 where name='test');
This will even work if you do not have a primary key on this column.
Explanation: DUAL is a special dummy table that is only referenced here to enable the WHERE clause. You would not be able to have a statement without a FROM clause (like select 'test' where not exists(select 1 from Table1 where name='test')) as it will be incomplete.
Assuming your name column has a UNIQUE constraint, just add IGNORE to the INSERT statement.
INSERT IGNORE INTO Table (name) VALUES ('test')
This will skip the insertion if a record already exists for a particular value and return 0 affected rows. Note that a primary key is also considered a UNIQUE constraint.
If the name column doesn't have such a constraint, I would advice that you add one:
ALTER TABLE `Table` ADD UNIQUE(name)
See also the documentation for INSERT
If you don't need to check whether there is duplication, other's suggestion is good for you. But you need, use 'INSERT' and check error number like this:
mysql_query('INSERT INTO ...');
if (mysql_errno() == 1062)
{
echo "duplicated";
}
else
{
echo "inserted";
}
(I know mysql_XXXX() is deprecated.. just example)

MySQL LAST_INSERT_ID() used with multiple records INSERT statement

If I insert multiple records with a loop that executes a single record insert, the last insert id returned is, as expected, the last one. But if I do a multiple records insert statement:
INSERT INTO people (name,age)
VALUES ('William',25), ('Bart',15), ('Mary',12);
Let's say the three above are the first records inserted in the table. After the insert statement I expected the last insert id to return 3, but it returned 1. The first insert id for the statement in question.
So can someone please confirm if this is the normal behavior of LAST_INSERT_ID() in the context of multiple records INSERT statements. So I can base my code on it.
Yes. This behavior of last_insert_id() is documented in the MySQL docs:
Important
If you insert multiple rows using a single INSERT statement, LAST_INSERT_ID() returns the value generated for the first inserted row only. The reason for this is to make it possible to reproduce easily the same INSERT statement against some other server.
This behavior is mentioned on the man page for MySQL. It's in the comments but is not challenged, so I'm guessing it's the expected behavior.
I think it's possible if your table has unique autoincrement column (ID) and you don't require them to be returned by mysql itself. I would cost you 3 more DB requests and some processing. It would require these steps:
Get "Before MAX(ID)" right before your insert:
SELECT MAX(id) AS before_max_id FROM table_name`
Make multiple INSERT ... VALUES () query with your data and keep them:
INSERT INTO table_name
(col1, col2)
VALUES
("value1-1" , "value1-2"),
("value2-1" , "value2-2"),
("value3-1" , "value3-2"),
ON DUPLICATE KEY UPDATE
Get "After MAX(ID)" right after your insert:
SELECT MAX(id) AS after_max_id FROM table_name`
Get records with IDs between "Before MAX(ID)" and "After MAX(ID)" including:
SELECT * FROM table_name WHERE id>$before_max_id AND id<=$after_max_id`
Do a check of retrieved data with data you inserted to match them and remove any records that were not inserted by you. The remaining records have your IDs:
foreach ($after_collection as $after_item) {
foreach ($input_collection as $input_item) {
if ( $after_item->compare_content($input_item) ) {
$intersection_array[] = $after_item;
}
}
}
This is just how a common person would solve it in a real world, with parts of code. Thanks to autoincrement it should get smallest possible amount of records to check against, so they will not take lot of processing. This is not the final "copy & paste" code - eg. you have to create your own function compare_content() according you your needs.