mysql inserting data into multiple tables - mysql

My tables are students, class, and studentclasses. They have many to many relationships among them. Can anyone tell me why the following code is not working?
START TRANSACTION;# MySQL returned an empty result set (i.e. zero rows).
# MySQL returned an empty result set (i.e. zero rows).
INSERT INTO 'students'('StudentID','Fname','Lname')
VALUES (Null,'name','lastname')
# 1 row affected.
SET #student = LAST_INSERT_ID();
# MySQL returned an empty result set (i.e. zero rows).
INSERT INTO `classes`(`classID`, `className`)
VALUES (Null, 'Maths');# 1 row affected.
SET #class = LAST_INSERT_ID();
# MySQL returned an empty result set (i.e. zero rows).
INSERT INTO `studentclasses`(`classID`, `studentID`)
VALUES (#class, #student);
# 1 row affected.
COMMIT;# MySQL returned an empty result set (i.e. zero rows).

START TRANSACTION;
INSERT INTO students(StudentID,Fname,Lname) VALUES (Null,'name','lastname');
SET #student = LAST_INSERT_ID();
INSERT INTO classes(classID, className) VALUES (Null, 'Maths');
SET #class = LAST_INSERT_ID();
INSERT INTO studentclasses(classID, studentID) VALUES(#class, #student);
COMMIT;
It should work, try this example on new database -
CREATE TABLE classes(
classID INT(11) NOT NULL AUTO_INCREMENT,
className VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (classID)
);
CREATE TABLE studentclasses(
classID INT(11) DEFAULT NULL,
studentID INT(11) DEFAULT NULL
);
CREATE TABLE students(
StudentID INT(11) NOT NULL AUTO_INCREMENT,
Fname VARCHAR(20) DEFAULT NULL,
Lname VARCHAR(20) DEFAULT NULL,
PRIMARY KEY (StudentID)
);
START TRANSACTION;
INSERT INTO students(StudentID,Fname,Lname) VALUES (Null,'name','lastname');
SET #student = LAST_INSERT_ID();
INSERT INTO classes(classID, className) VALUES (Null, 'Maths');
SET #class = LAST_INSERT_ID();
INSERT INTO studentclasses(classID, studentID) VALUES(#class, #student);
COMMIT;
SELECT * FROM students;
+-----------+-------+----------+
| StudentID | Fname | Lname |
+-----------+-------+----------+
| 1 | name | lastname |
+-----------+-------+----------+
SELECT * FROM classes;
+---------+-----------+
| classID | className |
+---------+-----------+
| 1 | Maths |
+---------+-----------+
SELECT * FROM studentclasses;
+---------+-----------+
| classID | studentID |
+---------+-----------+
| 1 | 1 |
+---------+-----------+

use Insert statements in try block and catch the exception. if exception occur then do rollback

Related

Get id of records updated with ON DUPLICATE KEY UPDATE

I want to know if there is a way to get the ID of records updated with ON DUPLICATE KEY UDATE.
For example, I have the users table with the following schema:
CREATE TABLE `users` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(255) NOT NULL,
`username` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx-users-email` (`email`)
);
and insert some users:
INSERT INTO users (email, username) VALUES ("pioz#example.org", "pioz"),("luke#example.org", "luke"),("mike#example.org", "mike");
the result is:
+----+------------------+----------+
| id | email | username |
+----+------------------+----------+
| 1 | pioz#example.org | pioz |
| 2 | luke#example.org | luke |
| 3 | mike#example.org | mike |
+----+------------------+----------+
Now I want to know if, with a query like the following one, is possible to get the ID of the updated records:
INSERT INTO users (email, username) VALUES ("luke#example.org", "luke2"),("mike#example.org", "mike2") ON DUPLICATE KEY UPDATE username=VALUES(username);
In this example ID 2 and 3.
It seems that the only solution is to used a stored procedure. Here is an example for one row, which could be expanded.
See dbFiddle link below for schema and testing.
CREATE PROCEDURE add_update_user(IN e_mail VARCHAR(25), IN user_name VARCHAR(25) )
BEGIN
DECLARE maxB4 INT DEFAULT 0;
DECLARE current INT DEFAULT 0;
SELECT MAX(ID) INTO maxB4 FROM users;
INSERT INTO users (email, username) VALUES
(e_mail, user_name)
ON DUPLICATE KEY UPDATE username=VALUES(username);
SELECT ID INTO current FROM users WHERE email =e_mail;
SELECT CASE WHEN maxB4 < current THEN CONCAT('New user with ID ', current, ' created')
ELSE CONCAT('User with ID ', current, ' updated') END Report;
/*SELECT CASE WHEn maxB4 < current THEN 1 ELSE 0 END;*/
END
call add_update_user('jake#example.com','Jake');
| Report |
| :------------------------- |
| New user with ID 6 created |
call add_update_user('jake#example.com','Jason');
| Report |
| :--------------------- |
| User with ID 6 updated |
db<>fiddle here
Plan A: Use the technique in the ref manual -- see LAST_INSERT_ID()
Plan B: Get rid of id and make email the PRIMARY KEY

What is the best way to generate primary key automatically?

I want to generate my primary key automatically in MySQL data table. But I want it to be a character string though in sequence.
Example:
user_id (Primary Key)
USER000001
USER000002
USER000003
USER000004 ....and so on..
By separate table for sequencing and a trigger, you can generate PK automatically with your format.
Tables
CREATE TABLE tableName_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE tableName
(
id VARCHAR(10) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_table_insert
BEFORE INSERT ON tableName
FOR EACH ROW
BEGIN
INSERT INTO tableName_seq VALUES (NULL);
SET NEW.id = CONCAT('USER', LPAD(LAST_INSERT_ID(), 6, '0'));
END$$
DELIMITER ;
Then you just insert rows to table
INSERT INTO tableName (name)
VALUES ('Jhon'), ('Mark');
And you'll have
| ID | NAME |
------------------
| USER000001 | Jhon |
| USER000002 | Mark |

How to make MySQL table primary key auto increment with some prefix

I have table like this
table
id Varchar(45) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name CHAR(30) NOT NULL,
I want to increment my id field like 'LHPL001','LHPL002','LHPL003'... etc.
What should I have to do for that? Please let me know any possible way.
If you really need this you can achieve your goal with help of separate table for sequencing (if you don't mind) and a trigger.
Tables
CREATE TABLE table1_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE table1
(
id VARCHAR(7) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_table1_insert
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq VALUES (NULL);
SET NEW.id = CONCAT('LHPL', LPAD(LAST_INSERT_ID(), 3, '0'));
END$$
DELIMITER ;
Then you just insert rows to table1
INSERT INTO Table1 (name)
VALUES ('Jhon'), ('Mark');
And you'll have
| ID | NAME |
------------------
| LHPL001 | Jhon |
| LHPL002 | Mark |
Here is SQLFiddle demo
Create a table with a normal numeric auto_increment ID, but either define it with ZEROFILL, or use LPAD to add zeroes when selecting. Then CONCAT the values to get your intended behavior. Example #1:
create table so (
id int(3) unsigned zerofill not null auto_increment primary key,
name varchar(30) not null
);
insert into so set name = 'John';
insert into so set name = 'Mark';
select concat('LHPL', id) as id, name from so;
+---------+------+
| id | name |
+---------+------+
| LHPL001 | John |
| LHPL002 | Mark |
+---------+------+
Example #2:
create table so (
id int unsigned not null auto_increment primary key,
name varchar(30) not null
);
insert into so set name = 'John';
insert into so set name = 'Mark';
select concat('LHPL', LPAD(id, 3, 0)) as id, name from so;
+---------+------+
| id | name |
+---------+------+
| LHPL001 | John |
| LHPL002 | Mark |
+---------+------+
I know it is late but I just want to share on what I have done for this. I'm not allowed to add another table or trigger so I need to generate it in a single query upon insert. For your case, can you try this query.
CREATE TABLE YOURTABLE(
IDNUMBER VARCHAR(7) NOT NULL PRIMARY KEY,
ENAME VARCHAR(30) not null
);
Perform a select and use this select query and save to the parameter #IDNUMBER
(SELECT IFNULL
(CONCAT('LHPL',LPAD(
(SUBSTRING_INDEX
(MAX(`IDNUMBER`), 'LHPL',-1) + 1), 5, '0')), 'LHPL001')
AS 'IDNUMBER' FROM YOURTABLE ORDER BY `IDNUMBER` ASC)
And then Insert query will be :
INSERT INTO YOURTABLE(IDNUMBER, ENAME) VALUES
(#IDNUMBER, 'EMPLOYEE NAME');
The result will be the same as the other answer but the difference is, you will not need to create another table or trigger. I hope that I can help someone that have a same case as mine.
Here is PostgreSQL example without trigger if someone need it on PostgreSQL:
CREATE SEQUENCE messages_seq;
CREATE TABLE IF NOT EXISTS messages (
id CHAR(20) NOT NULL DEFAULT ('message_' || nextval('messages_seq')),
name CHAR(30) NOT NULL,
);
ALTER SEQUENCE messages_seq OWNED BY messages.id;

Two primary keys & auto increment

I have a MySQL table with two fields as primary key (ID & Account), ID has AUTO_INCREMENT.
This results in the following MySQL table:
ID | Account
------------------
1 | 1
2 | 1
3 | 2
4 | 3
However, I expected the following result (restart AUTO_INCREMENT for each Account):
ID | Account
------------------
1 | 1
2 | 1
1 | 2
1 | 3
What is wrong in my configuration? How can I fix this?
Thanks!
Functionality you're describing is possible only with MyISAM engine. You need to specify the CREATE TABLE statement like this:
CREATE TABLE your_table (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
account_id INT UNSIGNED NOT NULL,
PRIMARY KEY(account_id, id)
) ENGINE = MyISAM;
If you use an innoDB engine, you can use a trigger like this:
CREATE TRIGGER `your_table_before_ins_trig` BEFORE INSERT ON `your_table`
FOR EACH ROW
begin
declare next_id int unsigned default 1;
-- get the next ID for your Account Number
select max(ID) + 1 into next_id from your_table where Account = new.Account;
-- if there is no Account number yet, set the ID to 1 by default
IF next_id IS NULL THEN SET next_id = 1; END IF;
set new.ID= next_id;
end#
Note ! your delimiter column is # in the sql statement above !
This solution works for a table like yours if you create it without any auto_increment functionality like this:
CREATE TABLE IF NOT EXISTS `your_table` (
`ID` int(11) NOT NULL,
`Account` int(11) NOT NULL,
PRIMARY KEY (`ID`,`Account`)
);
Now you can insert your values like this:
INSERT INTO your_table (`Account`) VALUES (1);
INSERT INTO your_table (`Account`, `ID`) VALUES (1, 5);
INSERT INTO your_table (`Account`) VALUES (2);
INSERT INTO your_table (`Account`, `ID`) VALUES (3, 10205);
It will result in this:
ID | Account
------------------
1 | 1
2 | 1
1 | 2
1 | 3

MSSQL Try Catch and Set Identity Insert in MySQL?

Do you know how to rewrite these this query in MySQL ?
I can't find Identity insert, I can't find any try catch,
I don't understand it.
CREATE TRIGGER T1 ON DB1.dbo.A
AFTER INSERT AS
BEGIN TRY
SET IDENTITY_INSERT DB2.dbo.B ON
INSERT INTO dbo.B(id, text) SELECT A.id,A.text FROM dbo.A INNER JOIN inserted I ON I.id = A.id
SET IDENTITY_INSERT DB2.dbo.B OFF
SET IDENTITY_INSERT DB2.dbo.D ON
INSERT INTO dbo.D(id, text) SELECT A.id,A.text FROM dbo.A INNER JOIN inserted I ON I.id = A.id
SET IDENTITY_INSERT DB2.dbo.D OFF
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SET IDENTITY_INSERT DB2.dbo.B OFF
SET IDENTITY_INSERT DB2.dbo.D OFF
END CATCH
GO
MySQL triggers have implicit transaction support, so the trigger cannot use statements that explicitly or implicitly begin or end a transaction such as START TRANSACTION, COMMIT, or ROLLBACK.
It is not necessary in MySQL to enable the insertion of values into primary key columns - this is already allowed. You can, however, toggle foreign key constraint checking and unique index checking:
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_unique_checks
A common way to do this is to store the existing values in user variables, change the settings, then restore the settings after your script is complete:
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
-- Your SQL statements here.
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
I'm not sure why you would need to do that in your trigger, so your MySQL trigger would look something like this:
DELIMITER |
CREATE TRIGGER T1 AFTER INSERT ON A FOR EACH ROW
BEGIN
INSERT INTO B (id, text) VALUES (NEW.id, NEW.text);
INSERT INTO C (id, text) VALUES (NEW.id, NEW.text);
END;|
DELIMITER ;
Here's the results of a quick test:
CREATE TABLE `A` (
`id` int(11) NOT NULL auto_increment,
`text` varchar(255) default NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `B` (
`id` int(11) NOT NULL auto_increment,
`text` varchar(255) default NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `C` (
`id` int(11) NOT NULL auto_increment,
`text` varchar(255) default NULL,
PRIMARY KEY (`id`)
);
DELIMITER |
CREATE TRIGGER T1 AFTER INSERT ON A FOR EACH ROW
BEGIN
INSERT INTO B (id, text) VALUES (NEW.id, NEW.text);
INSERT INTO C (id, text) VALUES (NEW.id, NEW.text);
END;|
DELIMITER ;
INSERT INTO `A` (id, text) VALUES (1, 'Line 1');
INSERT INTO `A` (id, text) VALUES (2, 'Line 3');
INSERT INTO `A` (id, text) VALUES (3, 'Line 3');
SELECT * FROM `A`;
+----+--------+
| id | text |
+----+--------+
| 1 | Line 1 |
| 2 | Line 3 |
| 3 | Line 3 |
+----+--------+
SELECT * FROM `B`;
+----+--------+
| id | text |
+----+--------+
| 1 | Line 1 |
| 2 | Line 3 |
| 3 | Line 3 |
+----+--------+
SELECT * FROM `C`;
+----+--------+
| id | text |
+----+--------+
| 1 | Line 1 |
| 2 | Line 3 |
| 3 | Line 3 |
+----+--------+
If you want something similar to TRY ... CATCH, you'll need to use handlers instead:
http://dev.mysql.com/doc/refman/5.1/en/declare-handler.html
Here's the documentation on MySQL triggers:
http://dev.mysql.com/doc/refman/5.1/en/commit.html
Just set id column to AUTO_INCREMENT. You don't need to toggle something on and off.
Read more in documentation