Insert into multiple(7) tables with no duplicates - sql

Trying to create a query/SP that will take data from one table and insert it into multiple tables. I have one main table that everything is put into at the beginning like a temp table.
Temp table
CREATE TABLE Employee
(
userID INT IDENTITY(1,1) NOT NULL,
userName VARCHAR(50) NULL,
FirstName VARCHAR(50) NULL,
LastName VARCHAR(50) NUll,
UserPassWd VARCHAR(50) NULL,
EmailId VARCHAR(100) NULL
CONSTRAINT PK_Employee PRIMARY KEY (userID)
)
Than when employee is verified it will be split up into multiple tables that only need a field or two from the temp table as needed. The UserEmail table I have listed below is one of the tables. I'm trying to get it to work for one table right now and then I'm guessing i will just copy the insert part and change the table name and attributes to the new tables
Here is what i have so far.
DECLARE #EMAIL VARCHAR(100)
DECLARE #USERID INT
SELECT #USERID = userID
,#EMAIL = EmailId
FROM Employee
WHERE userID = 1004
INSERT INTO UserEmail
(
EmailAddress
,EmailTypeID
,ExternalUserID
,Active
,CreatedByID
,CreatedDate
,UpdatedByID
,UpdatedDate
)
SELECT #EMAIL -- Email Address
,1 -- Email Type
,1 -- ExternalUserID
,1 -- Active
,1 -- CreatedByID
,CURRENT_TIMESTAMP -- CreatedDate
,1
,CURRENT_TIMESTAMP -- UpdatedDate
FROM Employee X
WHERE 1=1
AND X.userID = '####'-- INSERT USERID HERE for testing
This will insert the record into the UserEmail table but will create duplicate users, which i cant have so I tried adding this but it doesn't do what I want it to do.
WHERE 1=1
AND NOT EXISTS(
SELECT userID
FROM Employee
WHERE userID = 1004
)
Any guidance or help would be much appreciated. Thank You!

If you only like NOT to insert to UserEmail if user already exists just extend
INSERT INTO UserEmail ....
SELECT ....
FROM ....
WHERE ..
AND NOT EXISTS (select 1 from UserEmail where EmailAddress = X.emailAddress)
Otherwise review MERGE syntax (https://learn.microsoft.com/en-us/sql/t-sql/statements/merge-transact-sql)

Related

How to insert data into another table when the condition is met with trigger

I have these 4 tables:
CREATE TABLE dbo.person
(
personId INT IDENTITY(1,1) NOT NULL,
firstName NVARCHAR(30) NOT NULL,
lastName NVARCHAR(30) NOT NULL,
CONSTRAINT pkPerson PRIMARY KEY (personId),
);
CREATE TABLE dbo.personRegistration
(
person_registrationId INT IDENTITY(1,1) NOT NULL,
personId INT,
firstName NVARCHAR(30) NOT NULL,
lastName NVARCHAR(30) NOT NULL,
confirmed NCHAR(1) DEFAULT 'N' NOT NULL,
CONSTRAINT pkpersonRegistration PRIMARY KEY (person_registrationId),
CONSTRAINT fkpersonRegistration FOREIGN KEY (personId) REFERENCES dbo.person (personId)
CONSTRAINT personConfirmed CHECK (confirmed IN ('Y', 'N'))
);
CREATE TABLE dbo.person_organizationalUnit
(
personId INT NOT NULL,
organizationalUnitId INT NOT NULL,
CONSTRAINT pkorganizationalUnit PRIMARY KEY (personId, organizationalUnitId),
CONSTRAINT fkperson FOREIGN KEY (personId) REFERENCES dbo.person (personId),
CONSTRAINT fkorganizationalUnit FOREIGN KEY (organizationalUnitId) REFERENCES dbo.organizatinalUnit(unicOrgUnitId),
);
CREATE TABLE dbo.organizatinalUnit
(
organizationalUnitId INT IDENTITY(1,1) NOT NULL,
organizationalUnitName NVARCHAR(130) NOT NULL,
CONSTRAINT pkorganizationalUnit PRIMARY KEY (organizationalUnitId)
);
I need to create a trigger which will do that when I add new person in table personRegistration (his personId is set to NULL, and initial value for confirmed is 'N') and when I update personRegistration and set confirmed to 'Y', that person is going to be inserted into table person (value for personId is generated because the personId is an identity column) and the confirmed is going to change it's value to 'Y' and is going to be inserted in table person_organizationalUnit. I have written the trigger but the problem is when I update the personRegistration for more than one person my data double with each update.
CREATE TRIGGER personConfirmed
ON dbo.personRegistration
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.person (firstName, lastName)
SELECT
firstName, lastName
FROM
dbo.personRegistration
SET NOCOUNT ON
DECLARE #idPerson int
SELECT #idPerson = personId
FROM dbo.person
INSERT INTO dbo.person_organizationalUnit (personId, organizationalUnitId)
SELECT #idPerson, I.organizationalUnitId
FROM Inserted AS I
JOIN dbo.person p ON p.personId = #idPerson
WHERE confirmed = 'Y';
END
Data for insert:
INSERT INTO dbo.personRegistration (personId, firstName, lastName, confirmed)
VALUES (NULL, 'John', 'Smith', 'N');
Data for update:
UPDATE dbo.personRegistration
SET confirmed = 'Y'
WHERE personRegistrationId = 1;
SQL Server triggers works with sets not single register i did some small changes in your trigger
create TRIGGER dbo.usp_PersonConfirmed ON dbo.personRegistration
AFTER UPDATE
AS
BEGIN
-- create person if not exists
INSERT INTO dbo.person (firstName, lastName)
SELECT firstName, lastName
FROM dbo.personRegistration p
where not exists(select * from dbo.Person where firstName = p.firstName
and lastName = p.lastName)
-- create orgonization unit if person dont exist and confirmed is Y
INSERT INTO dbo.person_organizationalUnit (personId, organizationalUnitId)
SELECT i.personId, I.organizationalUnitId
FROM Inserted AS I
where not exists(select * from dbo.person_organizationalUnit where
personId = i.personId)
and confirmed = 'Y';
-- update orgonization unit if person exist and confirmed is Y
update pou set organizationalUnitId = I.organizationalUnitId
from dbo.person_organizationalUnit pou
inner join Inserted AS I on i.personID = pou.personId
where i.confirmed = 'Y';
END
Your trigger has a fatal flaw: it does not deeal properly with multiple rows. It is also not using the inserted table in the first INSERT, and instead selecting from the whole original table.
So you need to OUTPUT the identity column from the first insert in order to use it in the second.
Because you don't have the identity column yet, you need to join onto firstName and lastName, which I need not say isn't a very good primary key
CREATE OR ALTER TRIGGER personConfirmed
ON dbo.personRegistration
AFTER UPDATE
AS
SET NOCOUNT ON
IF NOT UPDATE(confirmed) OR NOT EXISTS (SELECT 1 FROM inserted)
RETURN; --early bailout
DECLARE #ids TABLE (personId int PRIMARY KEY, firstName nvarchar(100), lastName nvarchar(100));
INSERT INTO dbo.person (firstName, lastName)
OUTPUT inserted.personId, inserted.firstName, inserted.lastName
SELECT
i.firstName,
i.lastName
FROM
inserted i
WHERE i.confirmed = 'Y';
INSERT INTO dbo.person_organizationalUnit (personId, organizationalUnitId)
SELECT ids.personId, i.organizationalUnitId
FROM inserted AS i
JOIN #ids ids ON i.firstName = ids.firstName AND i.lastName = ids.lastName;
Ideally, you have some kind of unique primary key on personRegistration. then your trigger would look like this:
CREATE OR ALTER TRIGGER personConfirmed
ON dbo.personRegistration
AFTER UPDATE
AS
SET NOCOUNT ON
IF NOT UPDATE(confirmed) OR NOT EXISTS (SELECT 1 FROM inserted)
RETURN; --early bailout
DECLARE #ids TABLE (personId int PRIMARY KEY, registrationId int);
MERGE dbo.person p
USING (
SELECT *
FROM inserted i
WHERE i.confirmed = 'Y'
) i
ON 1 = 0 -- never match
WHEN NOT MATCHED THEN
INSERT (firstName, lastName)
VALUES (i.firstName, i.lastName)
OUTPUT inserted.personId, i.organizationalUnitId
INTO #ids (personId, organizationalUnitId)
;
INSERT INTO dbo.person_organizationalUnit (personId, organizationalUnitId)
SELECT ids.personId, i.organizationalUnitId
FROM #ids ids;
We need that funny MERGE because we want to OUTPUT columns that we are not inserting. You can only do this using MERGE.

Get AutoIncrement ID and insert into Foreign Key Table

I have 3 tables User, Profile and ProfilePicture. Profile and ProfilePicture have a foreign key relation with User table. What I want to do here is whenever I insert data into the User table through web application their AutoGeneratedID get and inserted into Profile and ProfilePicture tables.
CREATE TABLE User
(
UserId INT(11) NOT NULL AUTO_INCREMENT,
Username VARCHAR(45) NOT NULL,
Password VARCHAR(50) NOT NULL,
PRIMARY KEY (`UserId`),
UNIQUE INDEX `UserIdId_UNIQUE` (`UserId` ASC)
);
CREATE TABLE Profile
(
UserId INT(11) NOT NULL,
Firstname VARCHAR(50) NULL,
Lastname VARCHAR(50) NULL,
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
CREATE TABLE ProfilePicture
(
UserId INT(11) NOT NULL,
Picture image NULL,
insertdate date NULL,
FOREIGN KEY (UserId) REFERENCES User (UserId)
)
I know I have to use a trigger but I don't understand how to do this.
I am supposing that you are doing this using stored procedure or raw queries. This thing can be achieved by using OUTPUT clause.
Define a local table with column Id
DECLARE #OutputTbl TABLE (ID INT)
Now when you save the User then insert the new gnerated id into #OutputTbl
INSERT INTO User (Username, Password)
OUTPUT INSERTED.UserId INTO #OutputTbl(ID)
VALUES ('name', 'password')
Now when you need this id in Profile/ProfilePicture, get this id from local table
insert into Profile (
UserId ,
Firstname,
Lastname) Values ((Select ID from #OutputTbl),'fName','lName')
You can try something as below :
CREATE TABLE #tempUser(
UserId INT,
ShopRef INT
)
INSERT INTO [User] (UserPassword,Name,MobileNo,Gender,Dob,Country,State,City,StreetAddress
,ZipCode,IsActive
,CreatedDate,ModifiedBy,CreatedBy,IsAdmin,EmailOtp,UserImage,Rating
,ContactNo)
OUTPUT inserted.UserId, inserted.EmailOtp INTO #tempUser
SELECT 'NA', [Name], [MobileNo], '-','1900-01-01',[Country],[State],[City],[StreetAddress],
[ZipCode], 1
,#Date,#UserId,#UserId,0,ID,'NA',0
,'NA'
FROM #temp WHERE Status ='SUCCESS'
If you are executing these inserts in the same SP then you can use, make sure UserId is an Identity Column :
SET #UserId = SCOPE_IDENTITY()
you can after insert into table, call SCOPE_IDENTITY() function, to get the latest
identity inserted
for more informatin see:
https://msdn.microsoft.com/en-us/library/ms190315.aspx
http://www.codeproject.com/Articles/103610/Difference-between-IDENTITY-SCOPE-IDENTITY-IDENT-C

Relation between users with messages

I have a table of Users:
create table dbo.User
(
Id int identity not null,
Name nvarchar (400) null,
// Other coluns as Login, Password, etc.
)
create table dbo.Role
(
Id int identity not null,
Name nvarchar (20) null
)
create table dbo.UserRole
(
UserId int not null,
RoleId int not null
)
Each user has one or more roles.
I need to relate users one to each other in periods of type.
For example, one professor to its students during 4 months in 2015.
And I also need to track messages between users.
One of my ideas would be the following:
create table dbo.UserToUser
(
FirstUserId int not null,
SecondUserId int not null,
StartDate datetime not null,
EndDate datetime not null
)
Being both FirstUserId and SecondUserId FK's of Users table.
create table dbo.Message
(
ToId int not null,
FromId int not null,
Text nvarchar(max) not null,
Created datetime not null
)
Being both ToId and FromId FK's of Users table.
Should this be done in another way?
This seems fine but you could be more generic with the relationships. For example you might want to have more than 2 people in a relationship. There are a number of ways to do this but I would do it like this:
Relationship
------------
ID
StartDate
EndDate
Category
... etc
RelationshipMembers
-------------------
RelationshipID
UserID
Order (may not be needed)
MembershipCategory (eg Professors and Students // messageFrom and messageTo)

Using a Query or Stored Procedure to Report on the differences between two tables

I have created the following two tables:
Table1:
CREATE TABLE employees
(
PersonID NUMBER(10) NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255) NOT NULL,
JobRole varchar(255) NOT NULL,
Location varchar(255) NOT NULL,
CONSTRAINT pk_employee PRIMARY KEY (personid) USING INDEX
);
Table 2:
CREATE TABLE DBAteam
(
PersonID NUMBER(10) NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255) NOT NULL,
JobRole varchar(255) NOT NULL,
Location varchar(255) NOT NULL,
CONSTRAINT pk_dbateam PRIMARY KEY (personid) USING INDEX
);
The following is the trigger and stored procedure I'm using to populate the two tables:
Trigger:
CREATE OR REPLACE TRIGGER trg_trigger_test AFTER INSERT ON employees FOR EACH ROW
BEGIN
p_procedure_test(:NEW.personid, :NEW.lastname, :NEW.firstname, :NEW.jobrole, :NEW.location);
END trg_trigger_test;
/
Stored procedure:
CREATE OR REPLACE PROCEDURE p_procedure_test
(
i_personid IN employees.personid%TYPE,
i_lastname IN employees.lastname%TYPE,
i_firstname IN employees.firstname%TYPE,
i_jobrole IN employees.jobrole%TYPE,
i_location IN employees.location%TYPE
) AS
--
BEGIN
--
INSERT INTO dbateam
(
personid,
lastname,
firstname,
jobrole,
location
)
VALUES
(
i_personid,
i_lastname,
i_firstname,
i_jobrole,
i_location);
--
END p_procedure_test;
/
I need to find a way in which I can create a stored procedure or query to show me the differences between the two tables
Any help would be greatly appreciated, I've been struggling with this.
In Oracle :
SELECT * FROM table1
MINUS
SELECT * FROM table2
OR
SELECT *
FROM table1 t1
WHERE NOT EXISTS( SELECT 1
FROM table2 t2
WHERE t1.some_key = t2.some_key )
In Mysql:
SELECT * FROM table1
WHERE ID NOT IN (SELECT ID FROM table2 )
UNION
SELECT * FROM table2
WHERE ID NOT IN (SELECT ID FROM table1 )
In SQL SERVER
select * from table1
except
select * from table2

How to group several INSERTs?

I'm inserting data from one table into several others. The first insert will create a new userid. This new userid will be used in succeeding inserts. I will also continue inserting username from the source table into other tables. The chain of inserts below are for one user. There will be probably 2000 users involved.
I'm familiar with how this can be done using a cursor. Is there some other way to do this chain of inserts without a cursor?
insert into table 1 using #username and #firstname from source table
insert into table 2 using userid generated from table 1 (userid1)
insert into table 3 using #username and userid1
insert into table 4 using userid1
You can use the Output Clause of an Insert statement to capture generated Ids in bulk.
For example:
Create Table dbo.Source (
FirstName nvarchar(100),
LastName nvarchar(100)
);
Create Table dbo.Attrs (
Id int Identity Not Null Primary Key,
Name nvarchar(100) Not Null,
DefaultVal nvarchar(100)
);
Create Table dbo.Table1 (
Id Int Identity Not Null Primary Key,
FirstName nvarchar(100),
LastName nvarchar(100)
);
Create Table dbo.Table2 (
Id int Identity Not Null Primary Key,
Table1ID int Not Null Foreign Key References dbo.Table1 (Id),
AttrId int Not Null Foreign Key References dbo.Attrs (Id)
);
Insert Into dbo.Source Values
(N'Mickey', N'Mouse'),
(N'Donald', N'Duck'),
(N'Goofy', Null);
Insert Into dbo.Attrs Values
('Size', 'Small'),
('Wings', 'No');
Declare #Temp1 Table (Id Int, FirstName nvarchar(100), LastName nvarchar(100))
Declare #Temp2 Table (Id int, Table1ID int, AttrId int)
Insert Into dbo.Table1
(FirstName, LastName)
Output
inserted.Id, inserted.FirstName, inserted.LastName
Into
#Temp1
Select
FirstName, LastName
From
dbo.Source
Insert Into dbo.Table2
(Table1ID, AttrId)
Output
inserted.Id, Inserted.Table1ID, Inserted.AttrID
Into
#Temp2
Select
t.Id,
a.Id
From
#Temp1 t
Cross Join
dbo.Attrs a
Select * From #Temp2
http://sqlfiddle.com/#!3/31110/3