How to use last_insert_id() in MySQL? - mysql

My SQL statements like this:
INSERT INTO foo (val1) VALUES('v1'); -- ID in first table
foo_id = SELECT last_insert_id();
INSERT INTO bar (val2) VALUES ('v2'); -- ID in second table
bar_id = SELECT last_insert_id();
INSERT INTO foobar (foo_id, bar_id, val3)
VALUES (foo_id, bar_id, 'text'); -- third table
The above is not working, it doesn't recognize the foo_id = statement.

INSERT INTO foo (val1) VALUES ('v1'); -- ID in first table
SET #foo_id = last_insert_id();
INSERT INTO bar (val2) VALUES ('v2'); -- ID in second table
SET #bar_id = last_insert_id();
INSERT INTO foobar (foo_id, bar_id, val3)
VALUES (#foo_id, #bar_id, 'text'); -- third table

Related

Disable manually setting auto-incremented ids in MySQL

I want to disallow users from inserting into a table product (which has auto-incremented ids) if they're setting the id manually.
So this would be valid (id generated automatically since it's set as AUTO_INCREMENT):
INSERT INTO product (name) VALUES ("Product1")
But this wouldn't (id being set manually):
INSERT INTO product (id, name) VALUES (10, "Product1")
Is this possible in any way?
Trigger logic may help.
SET SESSION sql_mode := '';
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
val INT
) AUTO_INCREMENT = 123;
CREATE TRIGGER fail_explicit_id
BEFORE INSERT ON test
FOR EACH ROW
BEGIN
IF NEW.id <> 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Explicit ''id'' value is not allowed.';
END IF;
END
INSERT INTO test (val) VALUES (111);
INSERT INTO test VALUES (NULL, 222);
INSERT INTO test VALUES (0, 333);
INSERT INTO test VALUES (DEFAULT, 444);
INSERT INTO test VALUES (456, 555);
Explicit 'id' value is not allowed.
SET SESSION sql_mode := CONCAT_WS(',', ##sql_mode, 'NO_AUTO_VALUE_ON_ZERO');
SELECT ##sql_mode;
INSERT INTO test VALUES (0, 666);
INSERT INTO test VALUES (0, 777);
Duplicate entry '0' for key 'test.PRIMARY'
SELECT * FROM test;
id
val
0
666
123
111
124
222
125
333
126
444
fiddle
Give the user column-level permissions.
grant insert(`name`) on yourdatabase.product to theuser#thehost;
Then the user tries these:
mysql> INSERT INTO product (name) VALUES ("Product1");
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO product (id, name) VALUES (10, "Product1");
ERROR 1143 (42000): INSERT command denied to user 'theuser'#'thehost' for column 'id' in table 'product'

TRIGGER with insert partial field

2 tables
tb_product :
product_id,
product_size_values
tb_product_category :
product_id ,
category_id
product_size_values contains '41,42,46' or '44,45,46,47' or any values from 42 to 48 with coma separator ....
and the trigger
CREATE TRIGGER trg_product_size AFTER UPDATE ON tb_product
FOR EACH ROW
BEGIN
IF (NEW.product_size_values != OLD.product_size_values) THEN
INSERT INTO tb_product_category (product_id, product_size_values)
VALUES (NEW.product_id, 42) WHERE NEW.product_size_values LIKE '%42%'
;
INSERT INTO tb_product_category (product_id, product_size_values)
VALUES (NEW.product_id, 43) WHERE NEW.product_size_values LIKE '%43%'
;
END IF;
END //
of course the WHERE NEW.product_size_values LIKE does not work
my normal query to do that actually (without trigger ) is
insert into tb_product_category (product_id,category_id)
select product_id,42
from tb_product
where product_size_values like '%42%' ;
insert into tb_product_category (product_id,category_id)
select product_id,43
from tb_product
where product_size_values like '%43%' ;
and NO the comma separated field cannot be changed
thanks for helping
I guess the problem is that you cannot use a like test in a conditional statement and you cannot use a where clause with values and an insert select seems wasteful. You may be able to ditch the like clause and use and instr or locate to check values for example
drop table if exists tb_product,tb_product_category;
create table tb_product
(product_id int,
product_size_values varchar(20));
insert into tb_product values
(1,'42');
create table tb_product_category
(product_id int,
category_id int);
drop trigger if exists trg_product_size;
delimiter $$
CREATE TRIGGER trg_product_size AFTER UPDATE ON tb_product
FOR EACH ROW
BEGIN
IF (NEW.product_size_values != OLD.product_size_values) THEN
if instr(NEW.product_size_values,42) > 0 then
INSERT INTO tb_product_category (product_id, category_id) values (new.product_id,42);
end if;
if INSTR(NEW.product_size_values,43) > 0 then
INSERT INTO tb_product_category (product_id, category_id) values (new.product_id,43);
end if;
END IF;
END $$
delimiter ;
select product_size_values from tb_product;
update tb_product
set product_size_values = '42,43' where product_id = 1;
select * from tb_product_Category;
+------------+-------------+
| product_id | category_id |
+------------+-------------+
| 1 | 42 |
| 1 | 43 |
+------------+-------------+
Works as coded. You may wish to change the insert logic to check for existence before inserting to avoid duplicates.

Looping over a SQL result with multiple rows in MySQL

Let's say I have a "source table" which holds some rows, in this case four. Now I'd like to insert new rows into a "target table" for each of the rows from the source table.
My current statement is:
SET #id = 1;
INSERT INTO target_table (id, value)
VALUES (#id, 1),
(#id, 2),
(#id, 3),
(#id, 4);
However I'd like to do something like this...
SET #id = 1;
myResultSet = SELECT value FROM source_table;
FOR EACH value in myResultSet
INSERT INTO target_table (#id, #value)
END
You can use Insert ... Select statement:
INSERT INTO `target_table` (`id`, `value`)
SELECT 1, `value`
FROM `source_table`
Completely possibilities of this statement can be seen from the syntax below:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...
[ON DUPLICATE KEY UPDATE assignment_list]
value:
{expr | DEFAULT}
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...
INSERT INTO target_table ( id, value )
SELECT row_number() OVER (order by <whatever>) , value FROM source_table
or
INSERT INTO target_table( id, value )
SELECT 1, value FROM source_table
depending on what you mean
INSERT INTO target_table( id, value )
SELECT 1, value FROM source_table

No query result with SCOPE_IDENTITY() [duplicate]

What is the equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?
This is what you are looking for:
LAST_INSERT_ID()
In response to the OP's comment, I created the following bench test:
CREATE TABLE Foo
(
FooId INT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE Bar
(
BarId INT AUTO_INCREMENT PRIMARY KEY
);
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
CREATE TRIGGER FooTrigger AFTER INSERT ON Foo
FOR EACH ROW BEGIN
INSERT INTO Bar () VALUES ();
END;
INSERT INTO Foo () VALUES (); SELECT LAST_INSERT_ID();
This returns:
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 1 |
+------------------+
So it uses the LAST_INSERT_ID() of the original table and not the table INSERTed into inside the trigger.
Edit: I realized after all this time that the result of the SELECT LAST_INSERT_ID() shown in my answer was wrong, although the conclusion at the end was correct. I've updated the result to be the correct value.
open MySql command type SELECT LAST_INSERT_ID(); then ENTER

The equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?

What is the equivalent of SQLServer function SCOPE_IDENTITY() in mySQL?
This is what you are looking for:
LAST_INSERT_ID()
In response to the OP's comment, I created the following bench test:
CREATE TABLE Foo
(
FooId INT AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE Bar
(
BarId INT AUTO_INCREMENT PRIMARY KEY
);
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
INSERT INTO Bar () VALUES ();
CREATE TRIGGER FooTrigger AFTER INSERT ON Foo
FOR EACH ROW BEGIN
INSERT INTO Bar () VALUES ();
END;
INSERT INTO Foo () VALUES (); SELECT LAST_INSERT_ID();
This returns:
+------------------+
| LAST_INSERT_ID() |
+------------------+
| 1 |
+------------------+
So it uses the LAST_INSERT_ID() of the original table and not the table INSERTed into inside the trigger.
Edit: I realized after all this time that the result of the SELECT LAST_INSERT_ID() shown in my answer was wrong, although the conclusion at the end was correct. I've updated the result to be the correct value.
open MySql command type SELECT LAST_INSERT_ID(); then ENTER