MySQL Insert into multiple tables? (Database normalization?) [duplicate] - mysql

This question already has answers here:
Insert into multiple tables in one query
(6 answers)
Closed 1 year ago.
I tried searching a way to insert information in multiple tables in the same query, but found out it's impossible?
So I want to insert it by simply using multiple queries i.e;
INSERT INTO users (username, password) VALUES('test', 'test')
INSERT INTO profiles (userid, bio, homepage) VALUES('[id of the user here?]','Hello world!', 'http://www.stackoverflow.com')
But how can I give the auto-increment id from the users to the "manual" userid for the profile table?

No, you can't insert into multiple tables in one MySQL command. You can however use transactions.
BEGIN;
INSERT INTO users (username, password)
VALUES('test', 'test');
INSERT INTO profiles (userid, bio, homepage)
VALUES(LAST_INSERT_ID(),'Hello world!', 'http://www.stackoverflow.com');
COMMIT;
Have a look at LAST_INSERT_ID() to reuse autoincrement values.
You said "After all this time trying to figure it out, it still doesn't work. Can't I simply put the just generated ID in a $var and put that $var in all the MySQL commands?"
Let me elaborate: there are 3 possible ways here:
In the code you see above. This
does it all in MySQL, and the
LAST_INSERT_ID() in the second
statement will automatically be the
value of the autoincrement-column
that was inserted in the first
statement.
Unfortunately, when the second statement itself inserts rows in a table with an auto-increment column, the LAST_INSERT_ID() will be updated to that of table 2, and not table 1. If you still need that of table 1 afterwards, we will have to store it in a variable. This leads us to ways 2 and 3:
Will stock the LAST_INSERT_ID() in
a MySQL variable:
INSERT ...
SELECT LAST_INSERT_ID() INTO #mysql_variable_here;
INSERT INTO table2 (#mysql_variable_here, ...);
INSERT INTO table3 (#mysql_variable_here, ...);
Will stock the LAST_INSERT_ID() in a
php variable (or any language that
can connect to a database, of your
choice):
INSERT ...
Use your language to retrieve the LAST_INSERT_ID(), either by executing that literal statement in MySQL, or using for example php's mysql_insert_id() which does that for you
INSERT [use your php variable here]
WARNING
Whatever way of solving this you choose, you must decide what should happen should the execution be interrupted between queries (for example, your database-server crashes). If you can live with "some have finished, others not", don't read on.
If however, you decide "either all queries finish, or none finish - I do not want rows in some tables but no matching rows in others, I always want my database tables to be consistent", you need to wrap all statements in a transaction. That's why I used the BEGIN and COMMIT here.

fairly simple if you use stored procedures:
call insert_user_and_profile('f00','http://www.f00.com');
full script:
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) unique not null
)
engine=innodb;
drop table if exists user_profile;
create table user_profile
(
profile_id int unsigned not null auto_increment primary key,
user_id int unsigned not null,
homepage varchar(255) not null,
key (user_id)
)
engine=innodb;
drop procedure if exists insert_user_and_profile;
delimiter #
create procedure insert_user_and_profile
(
in p_username varchar(32),
in p_homepage varchar(255)
)
begin
declare v_user_id int unsigned default 0;
insert into users (username) values (p_username);
set v_user_id = last_insert_id(); -- save the newly created user_id
insert into user_profile (user_id, homepage) values (v_user_id, p_homepage);
end#
delimiter ;
call insert_user_and_profile('f00','http://www.f00.com');
select * from users;
select * from user_profile;

What would happen, if you want to create many such records ones (to register 10 users, not just one)?
I find the following solution (just 5 queryes):
Step I: Create temporary table to store new data.
CREATE TEMPORARY TABLE tmp (id bigint(20) NOT NULL, ...)...;
Next, fill this table with values.
INSERT INTO tmp (username, password, bio, homepage) VALUES $ALL_VAL
Here, instead of $ALL_VAL you place list of values: ('test1','test1','bio1','home1'),...,('testn','testn','bion','homen')
Step II: Send data to 'user' table.
INSERT IGNORE INTO users (username, password)
SELECT username, password FROM tmp;
Here, "IGNORE" can be used, if you allow some users already to be inside. Optionaly you can use UPDATE similar to step III, before this step, to find whom users are already inside (and mark them in tmp table). Here we suppouse, that username is declared as PRIMARY in users table.
Step III: Apply update to read all users id from users to tmp table. THIS IS ESSENTIAL STEP.
UPDATE tmp JOIN users ON tmp.username=users.username SET tmp.id=users.id
Step IV: Create another table, useing read id for users
INSERT INTO profiles (userid, bio, homepage)
SELECT id, bio, homepage FROM tmp

have a look at mysql_insert_id()
here the documentation: http://in.php.net/manual/en/function.mysql-insert-id.php

try this
$sql= " INSERT INTO users (username, password) VALUES('test', 'test') ";
mysql_query($sql);
$user_id= mysql_insert_id();
if(!empty($user_id) {
$sql=INSERT INTO profiles (userid, bio, homepage) VALUES($user_id,'Hello world!', 'http://www.stackoverflow.com');
/* or
$sql=INSERT INTO profiles (userid, bio, homepage) VALUES(LAST_INSERT_ID(),'Hello world!', 'http://www.stackoverflow.com'); */
mysql_query($sql);
};
References
PHP
MYSQL

Just a remark about your saying
Hi, I tried searching a way to insert information in multiple tables in the same query
Do you eat all your lunch dishes mixed with drinks in the same bowl?
I suppose - no.
Same here.
There are things we do separately.
2 insert queries are 2 insert queries. It's all right. Nothing wrong with it. No need to mash it in one.
Same for select. A query must be sensible and do its job. That's the only reasons. Number of queries is not.
There is no point in looking for a way to stuff different queries in one call. Different calls is how the database API is meant to work.

For PDO You may do this
$dbh->beginTransaction();
$stmt1 = "INSERT INTO users (username, password) VALUES('test', 'test')";
$stmt2 = "INSERT INTO profiles (userid, bio, homepage) VALUES('LAST_INSERT_ID(),'Hello world!', 'http://www.stackoverflow.com')";
$sth1 = $dbh->prepare($stmt1);
$sth2 = $dbh->prepare($stmt2);
$sth1->execute (array ('test','test'));
$sth2->execute (array ('Hello world!','http://www.stackoverflow.com'));
$dbh->commit();

Related

Auto generate Primary Key if not present in MySQL INSERT Query

I created a table in MySql
CREATE TABLE newuser(id VARCHAR(10) PRIMARY KEY,sname VARCHAR(20));
When I INSERT record it works fine
INSERT INTO newuser VALUE('abc123','monika');
But sometimes I don't want to supply id in the INSERT query and sometimes I want to supply. In case I don't supply id MySql automatically generate one.
What can I do to get both below query works?
INSERT INTO newuser VALUE('abc123','monika');
INSERT INTO newuser VALUE('nikita');
'I don't understood ANYTHING' - very new then.
Firstly second insert statement is invalid please review https://dev.mysql.com/doc/refman/8.0/en/insert.html -
'If you do not specify a list of column names for INSERT ... VALUES or INSERT ... SELECT, values for every column in the table must be provided by the VALUES list, SELECT statement, or TABLE statement.'
Secondly uuid is a function in which 'A UUID is designed as a number that is globally unique in space and time.' https://dev.mysql.com/doc/refman/8.0/en/insert.html
You can easily select uuid() to see what it produces.
You will need to increase the id size
If you wish to use it in an insert
insert into users values (uuid(),<sname>);

filtering from sql

I use my SQL for my app.
Say I have a table of all registered users for my app.
say I have users at hand and I want to filter (or select) from my database the only ones that are registered.
For example my data base have user1,user2......user100
and input user set : user3,user5,user10,user999,user2000 so the output of the query will be : user3,user5 and user 10 only.
Thank you in advance
You seem to want in:
select t.*
from t
where user_id in ('user3', 'user5', 'user10', 'user999', 'user2000')
This will return only the matching users.
The format the user is passing these values is very important here. I am assuming that you have different rows of information. If in that case, you could make use of the below code.
Declare #MyTableVar table
(User_ID VARCHAR(32) primary key)
INSERT #MyTableVar VALUES ('user3')
INSERT #MyTableVar VALUES ('user5')
INSERT #MyTableVar VALUES ('user10')
INSERT #MyTableVar VALUES ('user999')
INSERT #MyTableVar VALUES ('user2000')
SELECT *
FROM #MyTableVar
WHERE User_ID NOT IN (SELECT USER_ID FROM database.schema.table_name)
If your user is passing values in the same row you can convert them to multiple rows using CROSS APPLY. Example can be seen here
Kartheek

MySQL - select or insert

I have users from many external sources which I try to map to internal userId, so the table I have is:
userId, externalSourceId, externalUserId
In my code, I'm getting externalSourceId and externalUserId and want to get the userId from the database, if exists, otherwise, create one and return the newly created value. I need this action to be atomic because several processes may try to do the same thing at the same time, so I wished only the first time will create a userId.
In pseudo code it will look like that:
u = find user with (externalSourceId, externalUserId)
if no u:
2.1. u = create new user with (externalSourceId, externalUserId) and random userId
return u
INSERT INTO `users`
(`externalSourceId`, externalUserId)
VALUES( 10, 100)
ON DUPLICATE KEY
UPDATE userId=userId
You can also use insert ignore. You can read more about DUPLICATE KEY versus INSERT IGNORE
INSERT IGNORE INTO test (externalSourceId,externalUserId) VALUES (23,32);
SELECT userId FROM test WHERE externalSourceId=23 AND externalUserId=32;
You can use this if externalSourceId and externalUserId are defined unique.

MySql Insert to multiple tables based on the ID generated in the first table

I have three tables in my database. A users table, StoreA and StoreB
StoreA and StoreB both have a unique key which is the user ID value.
What I want is; When I create a user and insert them into the database, how can I Insert a row into the other two tables without too many additional queries.
I figure I can do this by inserting the user in one query,
then in another return the newly created user ID,
then in another, using said ID, create rows in StoreA and StoreB
Can I cut out the middle query?
Can I cut out the middle query?
YES
START TRANSACTION;
INSERT INTO user (id, name, other)
VALUES (null, 'John','rest of data');
INSERT INTO storeA (id, user_id, other)
VALUES (null, #user_id:= LAST_INSERT_ID(), 'rest of data');
INSERT INTO storeB (id, user_id, other)
VALUES (null, #user_id, 'rest of data');
COMMIT;
See: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
It's a good idea to do this in a transaction, you you're not stuck with just a user with no other data if something goes wrong.
It's not a DB requirement though.
Yes - there should be a function available to get the last inserted ID (assuming it's an autoincrement field) without another query. In PHP, it's mysql_insert_id(). Just call that after the first query.
YES
Q1: insert into table1 values (...);
Q2: insert into table2 values (last_insert_id(), ...);
last_insert_id is the default mysql build-in function
Most of the mysql libraries in various programming language did support return last insert id.
But You did not mention what sort of language you are using to connect to mysql.,
so cannot provide any example
I just wanted to share a php solution.
If you're using mysqli, first execute your insert query.
Then do
$db_id = $this->db->insert_id;
Why don't you use their username as the primary key instead of creating an arbitrary user_id field thats auto incremented? Their user names are unique, right?

I need a logic to implement Mysql query

I have a 3 tables:
1. Users -- here "userd id" is primary key
2. UserPermision --here "userd id" is a foreign key and there is "pageid" coloumn
3. Page -- here page id is a primary key
Now i need to write a query when i inser a new user say user id = "1" then this user id 1 should be inserted into Userpermision table and for this user it shouls have all the pages from page table .
I'm assuming you are using InnoDB.
In that case you have foreign key constraints and transactions.
If not you'll have to use triggers.
START TRANSACTION;
INSERT INTO users (name, etc) VALUES ('test', 'remainder');
SELECT last_insert_id() INTO #my_user_id;
INSERT INTO userpermission (userid, permission, pageid)
SELECT
#my_user_id as user_id
, 'all' as permission
, pageid
FROM pages
WHERE pages.userid = #my_user_id;
COMMIT;
This is assuming you've already made pages for that user.
link
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
You need two INSERT queries, one for each table.
INSERT INTO Users (user_id,...) VALUES (:user_id,...)
INSERT INTO UserPermission (user_id,page_id)
SELECT :user_id, page_id FROM Page
You can either execute them within the same transaction, or execute the second one from the AFTER INSERT trigger on the Users table.