how to insert a data into many tables - sql

For example, I have a 3 table
Table name: Role
table Attributes: roleid (pk), rolename
role to user one to many
Table name: user
table Attributes: roleid (fk), userid(pk), trackingid(fk) username, password, email
user to tacking one to one
Table name: tracking
table Attributes: trackingid(pk) approvalstatus*, status, createdby, createdDate(yyyy-mm-dd).
*meaning of attributes
approval status - admin will approve any changes so it can be pending, approved or rejected
status is to indicated whether the change request is new user/ edit or delete user.
How do I do a insert into statement to insert a new user for approval. As, when you insert the data in the database should look like this
+----------+----------+--------------------+----------+--------+----------------+-----------+-------------+
| username | password | email | rolename | status | approvalstatus | createdby | createdDate |
+----------+----------+--------------------+----------+--------+----------------+-----------+-------------+
| harry | password | harry#yahoo.com.sg | Admin | New | Pending | Barry | 2016-09-20 |
+----------+----------+--------------------+----------+--------+----------------+-----------+-------------+

This really depends on how you're interacting with the Database.
If you're using an ORM like Entity Framework or NHibernate, this comes out of the box depending on how you map your tables.
For information on this please view:
Entity Framework
NHibernate
If you're doing this direct to SQL Server you can use the following:
Stored Procedure - In this case you'll call a single stored procedure on your DB Server, which will do three inserts for you based on your inputs.
You can perform 3 operations to the DB using a single connection.
Regardless of whether you pick a Stored Proc. or manual statement your inserts will look like:
INSERT INTO ROLE (RoleID, RoleName) VALUES (newID(), 'Your Role Name'); --If you have auto increment on your PK you can ignore inserting into RoleID. Most Systems I work with now use GUID's for ID's so this is just an example.
INSERT INTO User (RoleID, UserID, TrackingID, UserName, Password, Email) Values (....)
INSERT INTO Tracking (TrackingID, ApprovalStatus, Status, CreatedBy, CreatedDate) values (....)
Once you have an entry in your DB you can update that using:
UPDATE Tracking SET ApprovalStatus = 'whatever you want here' where id = X
IF you need to maintain history of tracking, rather than update Tracking, you need to insert a new row and always make sure when you're SELECT'ing your data, you get the latest one based on the DateTime stamp.
Your table in your question is misleading. You're joining three tables to get those results, which is maybe what you want on our output.

Related

Data extract and import from CSV with foreign keys - Postgresql

I have a multi tenant database. My requirement is to extract a single tenant's data from a database and insert in to other database.
So I have 2 tables: users and identities.
users table has foreign key identity_id connected with identities table
There can be many identities and users under a customer.
I am extracting the data to a csv file and inserting into new database from the csv file.
primary key is set to auto increment, so users and identities table generate id while inserting data from csv.
Table data from existing database
Users table
| id | identity_id |
| --- | ------------|
| 86 | 70 |
| 193 | 127 |
| 223 | 131 |
Identities table
|id |name |email |
|---|------------|-----------------|
|70 |Alon muscle |muscle#test.com |
|131|james |james#james.com |
|127|watson |watson#watson.com|
Now identity_id is the foreign key in users table mapping to identities table.
I am trying to insert users and identities data to new database
So primary key will be auto incremented for users and identities.
The problem comes here with foreign key.
How can I maintain foreign_key relationship as I have multiple users and identities records?
Well you did not actually provide details on your tables, that would be the actual definitions (ddl). Nor provide the CVS contents, which I assume your stage table contains same. However with the test data provided and a couple assumptions the following demonstrates a method to load your data. The method is to build a procedure which uses the stage table to load identities table then selects the generates id from the email provided to populate users table. Assumptions:
email must be unique in identities (at least in lower case).
stage table reflects name and email for identities.
Procedure to load identities and users.
create or replace procedure generate_user_idents()
language sql $
insert into identities(name, email)
select name, email
from stage
on conflict (low_email)
do nothing ;
as $$
insert into users(ident_id)
select ident.ident_id
from identities ident
where ident.low_email in
( select lower(email)
from stage
) ;
$$;
Script to clear and repopulate stage data then load stage to identities and users.
do $$
begin
execute 'truncate table stage';
-- replace the following with your \copy to load stage
insert into stage(name, email)
values ( 'Alon muscle', 'muscle#test.com' )
, ( 'watson', 'watson#watson.com')
, ( 'james', 'james#james.com' );
call generate_user_idents();
end ;
$$;
See demo here. Since the demo generates the ids, it does not exactly match your provided values, but close. As it stands the procedure would be happy generating duplicates should you fail to clear the stage table or reenter the same values into it. You have to decide how to handle that.

Get back the id of each insert in SQL Server

Let's say we want to insert two users and I want to know the userId of each record I inserted.
Example:
Db:
User.lookup database with these columns:
UserId(PK, identity) | Username
Setup, insert two users:
declare #users table (uniqueId INT, name nvarchar(100));
insert into #users (0, 'TestUser')--Two users with the same name, they'll get a different userid in the db
insert into #users (1, 'TestUser')--Uniqueid is just an autonumber I use to tell the difference between them.
Insert statement:
insert into user.lookup (userName)
output inserted.userid
select name from #users;
This will return two usersIds, example 1 & 2. But how do I know which of the two users got which userId?
I can differentiate them in code with their 'uniqueid' I pass but I don't know how to return it.
Don't just output the id. You can include other columns:
insert into user.lookup (userName)
output inserted.*
select name from #users;
Here is a db<>fiddle.
You can't correlate the inserted rows with the database-assigned IDs, at least not without inserting an alternate key as well. INSERT ... OUTPUT will not let you output a row that wasn't actually inserted, so the column that correlates the un-keyed rows with the new key values has to be actually inserted.
So the options are:
To use a SEQUENCE instead of IDENTITY and and either assign IDs to the table variable before insert, or assign IDs to the entities on the client, eg by calling sp_sequence_get_range.
Use MERGE instead of INSERT. This is what Entity Framework Core does. See eg The Case of Entity Framework Core’s Odd SQL
As Gordon explained, one can output more than 1 column.
But just to put my 2 cents in, such insert doesn't really need an intermediate table variable.
create table lookup (
lookupId int identity primary key,
userName nvarchar(100),
createdOn datetime2 not null
default sysdatetime()
)
GO
✓
insert into lookup (userName) values
('TestUser1')
,('TestUser2')
;
GO
2 rows affected
insert into lookup (userName)
output inserted.lookupId, inserted.userName
values
('Testuser3'),
('Testuser3')
GO
lookupId | userName
-------: | :--------
3 | Testuser3
4 | Testuser3
select lookupId, userName
--, convert(varchar,createdOn) as createdOn
from lookup
order by lookupId
GO
lookupId | userName
-------: | :--------
1 | TestUser1
2 | TestUser2
3 | Testuser3
4 | Testuser3
db<>fiddle here

How to insert row in a table every time I insert a new row in the main table?

I have a Vb.net app that is connected to an Access 2010* Database, I have a table with personal information of many students and another table with multiple true/false fields for every course the student has succed.
The structure is something like this
Table students
|Id_student | Name | Phone |
Table finishedCourses
| Id_stutent | chemistry | physics | maths |
How can I add a new row into finishedCourses table every time that I insert a new row into students table.
I don't know how add the rows with the same id in both tables.
I expect something like this
Table students
Id_student | Name | Phone
1234456 | abc | 12432534645
Table finishedCourses
Id_stutent | chemistry | physics | maths
1234456 | false | false | false
The default values for Courses are `False'. Initial status of each course is incomplete.
I tried to undestand what you want, you want to insert a initial values in finishedCourses when you insert a student information in table students, am I right?
I am not familiar with the Access database, I realized that the Access database may not have the trigger function, otherwise you can use the trigger to implement your requirement.
And in this problem, you can just write two insert SQLs to complete this with the same studentId, like below:
insert into students(id_101, 'Bob', '88089901');
insert into finishedCourses(id_101, false, false, false...);
If you are using SQL server then you can use trigger. The sample code is as below, I have no idea about MS-Access
CREATE TRIGGER trgAfterInsert ON [dbo].[students]
FOR INSERT
AS
DECLARE #Id_stutent int;
SELECT #Id_stutent=i.Id_student FROM inserted i;
INSERT INTO finishedCourses
(Id_stutent,chemistry,physics,maths)
VALUES(#Id_stutent ,false , false , false ,false );
GO

Sqlite: Insert if not exist, Update if exist

I have a database with 2 tables like this:
cg_resp
id | name | email
1 | George | george#yahoo.com
id column is primary_key,autoincremented and name is unique
and
equip_info
id | description | cg_resp_id
1 | Caliper | 1
In the application form I have 2 edit boxes named edit_resp_name and edit_resp_email
If user insert a new responsible name like John with the email john#yahoo.com then during the save of form I would like to insert a new responsible into cg_resp table, get the last inserted id and update it to equip_info.cg_resp_id.
If the user maintain the name George but it's updating the email like george01#gmail.com then I would like to update the id = 1 from cg_resp with the new email address and the rest of them (equip_info.cg_resp_id and cg_resp.id) to remain the same.
I would like to maintain the original reference of cg_resp_id from table equip_info if the name of responsible is the same, so it's necessary to avoid situation like delete and insert a new one.
How can be done this in one Sqlite sql sequence?
SQLite has no built-in mechanism that would not delete the existing row.
The easiest way to do this is to put the logic into your application:
cursor = db.execute("SELECT ...")
if cursor.empty:
db.execute("INSERT ...")
else:
db.execute("UPDATE ...")
If your language allows to read the number of affected rows, it is possible to do this with two SQL commands:
db.execute("UPDATE ...")
if db.rowcount == 0:
db.execute("INSERT ...")
Use INSERT OR REPLACE which does exactly what you want : insert a new row when the name does not exists or update otherwise.

SQL - keep values with UPDATE statement

I have a table "news" with 10 rows and cols (uid, id, registered_users, ....) Now i have users that can log in to my website (every registered user has a user id). The user can subscribe to a news on my website.
In SQL that means: I need to select the table "news" and the row with the uid (from the news) and insert the user id (from the current user) to the column "registered_users".
INSERT INTO news (registered_users)
VALUES (user_id)
The INSERT statement has NO WHERE clause so i need the UPDATE clause.
UPDATE news
SET registered_users=user_id
WHERE uid=post_news_uid
But if more than one users subscribe to the same news the old user id in "registered_users" is lost....
Is there a way to keep the current values after an sql UPDATE statement?
I use PHP (mysql). The goal is this:
table "news" row 5 (uid) column "registered_users" (22,33,45)
--- 3 users have subscribed to the news with the uid 5
table "news" row 7 (uid) column "registered_users" (21,39)
--- 2 users have subscribed to the news with the uid 7
It sounds like you are asking to insert a new user, to change a row in news from:
5 22,33
and then user 45 signs up, and you get:
5 22,33,45
If I don't understand, let me know. The rest of this solution is an excoriation of this approach.
This is a bad, bad, bad way to store data. Relational databases are designed around tables that have rows and columns. Lists should be represented as multiple rows in a table, and not as string concatenated values. This is all the worse, when you have an integer id and the data structure has to convert the integer to a string.
The right way is to introduce a table, say NewsUsers, such as:
create table NewsUsers (
NewsUserId int identity(1, 1) primary key,
NewsId int not null,
UserId int not null,
CreatedAt datetime default getdaete(),
CreatedBy varchar(255) default sysname
);
I showed this syntax using SQL Server. The column NewsUserId is an auto-incrementing primary key for this table. The columns NewsId is the news item (5 in your first example). The column UserId is the user id that signed up. The columns CreatedAt and CreatedBy are handy columns that I put in almost all my tables.
With this structure, you would handle your problem by doing:
insert into NewsUsers
select 5, <userid>;
You should create an additional table to map users to news they have registeres on
like:
create table user_news (user_id int, news_id int);
that looks like
----------------
| News | Users|
----------------
| 5 | 22 |
| 5 | 33 |
| 5 | 45 |
| 7 | 21 |
| ... | ... |
----------------
Then you can use multiple queries to first retrieve the news_id and the user_id and store them inside variables depending on what language you use and then insert them into the user_news.
The advantage is, that finding all users of a news is much faster, because you don't have to parse every single idstring "(22, 33, 45)"
It sounds like you want to INSERT with a SELECT statement - INSERT with SELECT
Example:
INSERT INTO tbl_temp2 (fld_id)
SELECT tbl_temp1.fld_order_id
FROM tbl_temp1
WHERE tbl_temp1.fld_order_id > 100;