SQL Server stored procedure with multiple table insert - sql

I am using SQL Server Management Studio 2014 and I am writing a stored procedure to insert into many tables with foreign keys.
I am getting two errors:
Msg 547, Level 16, State 0, Procedure insertintoorders, Line 163
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Customers__Addre__145C0A3F". The conflict occurred in database "FlowerCompany", table "dbo.Addresses", column 'AddressID'.
Msg 547, Level 16, State 0, Procedure insertintoorders, Line 178
The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Orders__Customer__1FCDBCEB". The conflict occurred in database "FlowerCompany", table "dbo.Customers", column 'CustomerID'.
Here is my stored procedure and my testing execution of it:
CREATE PROCEDURE insertintoorders
#Street varchar(50),
#City varchar(30),
#State varchar(2),
#Zip varchar(9),
#Phone varchar(10),
#FlowerName varchar(50),
#FirstName varchar(40),
#LastName varchar(40),
#OrderStatus varchar(12),
#DeliverDate date,
#OrderMessage varchar(100),
#OrderDate date,
#Vase bit,
#OrderCost decimal(6,2)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #flower int;
SELECT #flower = Arr.FlowerID
FROM Arrangements Arr
WHERE FlowerName = #FlowerName
DECLARE #AddID int;
SELECT #AddID = coalesce((SELECT MAX(AddressID) + 1 FROM Addresses), 1)
DECLARE #PhoneID int;
SELECT #PhoneID = coalesce((SELECT MAX(PhoneID) + 1 FROM Phone), 1)
DECLARE #CustID int;
SELECT #CustID = coalesce((SELECT MAX(CustomerID) + 1 FROM Customers), 1)
DECLARE #Del int;
SELECT #Del = coalesce((SELECT MAX(DeliveryID) + 1 FROM Delivery), 1)
DECLARE #Ords int;
SELECT #Ords = coalesce((select max(StatusID) + 1 from OrderStatus), 1)
DECLARE #Ord int;
SELECT #Ord = coalesce((select max(OrderID) + 1 from Orders), 1)
INSERT INTO Addresses (Street, City, States, Zip)
VALUES (#Street, #City, #State, #Zip)
SET #AddId = SCOPE_IDENTITY()
INSERT INTO Phone (Phone)
VALUES (#Phone)
SET #PhoneID = SCOPE_IDENTITY()
INSERT INTO Customers (AddressID, PhoneID, FirstName, LastName)
VALUES (SCOPE_IDENTITY(), SCOPE_IDENTITY(), #FirstName, #LastName)
SET #CustID = SCOPE_IDENTITY()
INSERT INTO Delivery (DeliverDate)
VALUES (#DeliverDate)
SET #Del = SCOPE_IDENTITY()
INSERT INTO OrderStatus (OrderStatus)
VALUES (#OrderStatus)
SET #Ords = SCOPE_IDENTITY()
INSERT INTO Orders ([CustomerID], [FlowerID], [StatusID],[DeliveryID], OrderMessage, OrderDate, OrderCost, Vase)
VALUES (SCOPE_IDENTITY(), #flower, SCOPE_IDENTITY(), SCOPE_IDENTITY(), #OrderMessage, #OrderDate, #OrderCost, #Vase)
SET #Ord = SCOPE_IDENTITY()
END
GO
EXEC insertintoorders #Street = '555 LANE', #City='Somewhere', #State = 'XX', #Zip = '99999', #Phone = '1234567896', #FlowerName = 'The Flower of Love', #FirstName = 'George',
#LastName = 'Fish', #DeliverDate = '10/10/2016', #OrderStatus = 'Completed', #OrderMessage = 'Fishy flowers', #OrderDate = '03/03/2016', #OrderCost = '200', #Vase = '1'
Although I had read the errors, I am not understanding how to fix them or why they are there.

You are using IDENTITY_INSERT and inserting your own values for PhoneId and AddressId. SCOPE_IDENTITY() is always the last value inserted into an identity column, so after you insert into phone it will return PhoneId and never AddId.
Option 1: Use the values you have. This is a bad idea because if you do two adds at the same time, you might get conflicts
SET IDENTITY_INSERT dbo.Customers ON
INSERT INTO Customers (CustomerID,AddressID,PhoneID,FirstName,LastName)
VALUES (#CustID, #AddId, #PhoneId ,#FirstName, #LastName)
SET IDENTITY_INSERT dbo.Customers OFF
Option 2: Just let the system set the identity values and get them after each insert, i.e.:
INSERT INTO Addresses (Street, City, States, Zip)
VALUES (#Street,#City,#State,#Zip)
SET #AddId = SCOPE_IDENTITY()

Related

SQL Server: How to use result from one INSERT for another INSERT

I have a stored procedure that is meant to update two tables at once.
My problem here is that the first table has an auto-incrementing ID column ("commentID") and my second table has a relationship on this so I need the newly created ID from the first INSERT in order to make the second INSERT.
I tried the following which I can save without errors but it doesnt execute as it should and does not update the tables as intended.
Can someone tell me what I am doing wrong here ?
My SQL:
ALTER PROCEDURE [dbo].[MOC_UpdateComment]
#imgID int,
#commentID int = '999999',
#comment nvarchar(1000),
#lastUpdate nvarchar(50),
#modBy varchar(50)
AS
BEGIN
DECLARE #temp AS TABLE
(
commentID int
)
SET NOCOUNT ON;
BEGIN TRANSACTION;
INSERT INTO MOC_BlogComments
(
imgID,
comment
)
OUTPUT inserted.commentID INTO #temp(commentID)
SELECT #imgID,
#comment
INSERT INTO MOC_LogComments
(
commentID,
lastUpdate,
modTime,
modBy
)
SELECT commentID,
#lastUpdate,
GETDATE(),
#modBy
FROM #temp
COMMIT TRANSACTION;
END
DECLARE #imgID INT,
#commentID INT = '999999',
#comment NVARCHAR(1000),
#lastUpdate NVARCHAR(50),
#modBy VARCHAR(50)
DECLARE #MORC_BlogComments AS TABLE
(
id INT IDENTITY(1, 1) NOT NULL,
imgid INT,
comment VARCHAR(100)
)
DECLARE #MORC_LogComments AS TABLE
(
commentid INT,
lastupdate DATETIME,
modtime DATETIME,
modby VARCHAR(100)
)
DECLARE #TEMP AS TABLE
(
commentid INT
)
SET nocount ON;
BEGIN TRANSACTION;
INSERT INTO #MORC_BlogComments
(imgid,
comment)
output inserted.id
INTO #TEMP(commentid)
VALUES (#imgID,
#comment)
INSERT INTO #MORC_LogComments
(commentid,
lastupdate,
modtime,
modby)
SELECT commentid,
#lastUpdate,
Getdate(),
#modBy
FROM #temp
SELECT *
FROM #MORC_LogComments
Function SCOPE_IDENTITY() returns the identity of last insert operation. You can use it to get the value which you need to use in second INSERT statement
You can use it like this in your statement:
INSERT INTO MORC_BlogComments (imgID, comment)
VALUES (#imgID, #comment)
INSERT INTO MORC_LogComments (commentID, lastUpdate, modTime, modBy)
VALUES (SCOPE_IDENTITY(), #lastUpdate, GETDATE(), #modBy)

Pass Output Value of one stored procedure to another stored procedure

I want to use output value of one stored procedure in another stored procedure .
Stored procedure 1:
Create PROCEDURE [dbo].[usp_AddUpdateUser]
#UserId INT,
#Email varchar(50),
#FirstName varchar(50)
AS
BEGIN
MERGE [User] AS target
USING (SELECT #UserId) AS source (Id)
ON target.Id = source.Id
WHEN MATCHED THEN
UPDATE
SET Email = #Email,
FirstName = #FirstName
WHEN NOT MATCHED THEN
INSERT (Email, FirstName)
VALUES (#Email, #FirstName)
OUTPUT inserted.Id;
END
Now I want to use the inserted Id of above stored procedure to below stored procedure:
ALTER PROCEDURE usp_AddUpdateDealer
(#Id INT,
#DealerName varchar(55),
#Email varchar(55),
#UserId INT)
AS
BEGIN
DECLARE #NewUserId INT
EXEC #NewUserId = usp_AddUpdateUser #UserId, #Email, #DealerName
MERGE Dealer AS target
USING (SELECT #Id) AS source (Id) ON target.Id = source.Id
WHEN MATCHED THEN
UPDATE
SET #DealerName = #DealerName,
Email = #Email,
UserId = #NewUserId
WHEN NOT MATCHED THEN
INSERT (DealerName, Email, UserId)
VALUES (#DealerName, #Email, #NewUserId)
OUTPUT inserted.Id;
END
#NewUserId not gives the output value.
How can I got the output option of the usp_AddUpdateUser stored procedure to use that in next statement?
ALTER PROCEDURE usp_AddUpdateDealer
(
#Id INT,
#DealerName varchar(55),
#Email varchar(55),
#UserId INT
)
AS
BEGIN
DECLARE #t table(NewUserId INT )
INSERT #t(NewUserId)
EXEC #NewUserId = usp_AddUpdateUser #UserId,#Email,#DealerName
DECLARE #NewUserId INT
SELECT #NewUserId = NewUserId FROM #t
MERGE Dealer AS target
USING (SELECT #Id) AS source (Id)
ON target.Id = source.Id
WHEN MATCHED THEN
UPDATE
SET #DealerName = #DealerName,
Email = #Email,
UserId=#NewUserId
WHEN NOT MATCHED THEN
INSERT (DealerName,Email,UserId)
VALUES (#DealerName,#Email,#NewUserId)
OUTPUT inserted.Id;
END

How to have multiple inserts in one sql query that uses the identities from the previous table

I am trying to insert data into many tables in one SQL Server stored procedure. I am also using the identities from the tables that I have inserted data into to then resolve the many to many relationship by writing those identities to another table.
In theory the logic seems to be there for the stored procedure, but on execution only the first insert statement has been executed. Please could anyone assist with this.
The stored procedure is as follows:
Create Procedure [dbo].[InsertAllCustomerDetails]
(
--#CustomerID Bigint output,
#Firstname varchar(100),
#LastName varchar(100),
#Initials varchar(10),
#Title varchar(20),
#DateCreated datetime,
#isDeleted Bit,
--#ContactNumberID BIGINT Output,
#ContactNumber Varchar(100),
#ContactTypeID bigint,
#Street Varchar(550),
#AreaID BIGINT,
#isPreferred Bit
--#AddressID Bigint OutPut
)
AS
Insert Into Customer
(
FisrtName,
LastName,
Initials,
[Title],
DateCreated,
isDeleted
)
Values
(
#Firstname,
#LastName,
#Initials,
#Title,
#DateCreated,
#isDeleted
)
Declare #CustomerID BIGINT
SELECT #CustomerID = ##IDENTITY
RETURN #CustomerID
--This will now insert the contact details for the customer
Insert Into ContactNumber
(
ContactNumber,
ContactTypeID
)
Values
(
#ContactNumber,
#ContactTypeID
)
Declare #ContactNumberID BIGINT
SELECT #ContactNumberID = ##IDENTITY
--This will insert into the CustomerContactNumber
Insert Into CustomerContactNumber
(
ContactNumberID,
CustomerID
)
Values
(
#ContactNumberID,
#CustomerID
)
--This will insert the address
Insert Into [Address]
(
Street,
AreaID,
isPreferred
)
Values
(
#Street,
#AreaID,
#isPreferred
)
Declare #AddressID BIGINT
SELECT #AddressID = ##IDENTITY
--This will insert the relationship for the customer Address table
Insert into CustomerAddress
(
CustomerID,
AddressID
)
Values
(
#CustomerID,
#AddressID
)
I see two things:
You seem to have a typo in the Customer insert:
Insert Into Customer
(
FisrtName, <-- should be FirstName?
LastName,
You are RETURNing after the Customer insert - that's why only the first one runs
Declare #CustomerID BIGINT
SELECT #CustomerID = ##IDENTITY
RETURN #CustomerID <---- This exits the sproc
--This will now insert the contact details for the customer
Insert Into ContactNumber
I'm guessing the RETURN was there for debugging and not removed since it's obscured by the indentation.

MSSQL-server Stored procedure inserting only last Row

I have created a stored procedure to Move all items from IDx to IDz and as it does that it has to log some data of each row it moves. The procedure moves rows from ID< to IDz without any problems. But when it has to log the information it only logs the last row that is moved. What am i doing wrong?
this is my code:
USE [TrackIT_Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[MoveCustIDAndAlias]
-- Add the parameters for the stored procedure here
#SourceAdrID int,
#TargetAdrID int,
#Username varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #custID varchar(50)
set #custID = ''
declare #alias varchar(50)
set #alias = ''
-- Insert statements for procedure here
Select #custID = (CustID), #alias = (Alias) from dbo.Alias where AdrID = #SourceAdrID;
Insert into dbo.AliasMoveLog (CustID, Alias, Username) VALUES (#custID, #alias, #Username);
UPDATE dbo.Alias SET AdrID = #TargetAdrID WHERE AdrID = #SourceAdrID;
Can anyone help ?
Yes, I see your problem.
When you're using variable and set the variable value with select, it will store only the value in the last row.
You can try this to prove it:
CREATE TABLE tbl
(
col1 INT
);
INSERT INTO tbl VALUES (1);
INSERT INTO tbl VALUES (2);
INSERT INTO tbl VALUES (3);
DECLARE #x int
SELECT #x = col1 FROM tbl
PRINT #x -- will print 3
For your sp, try to change this line:
Select #custID = (CustID), #alias = (Alias) from dbo.Alias where AdrID = #SourceAdrID;
Insert into dbo.AliasMoveLog (CustID, Alias, Username) VALUES (#custID, #alias, #Username);
to:
Insert into dbo.AliasMoveLog (CustID, Alias, Username)
Select CustID, Alias, #Username from dbo.Alias where AdrID = #SourceAdrID;
More detail: SELECT #local_variable
Well you cannot bulk insert values once you declare the variable like that.
Simple way is to do it this way:
INSERT INTO dbo.AliasMoveLog (CustID, Alias, Username)
SELECT CustID, Alias, #Username FROM dbo.Alias WHERE AdrID = #SourceAdrID;

Upsert SQL query

I am looking for some advice how to optimize a couple of SQL stored procedures. With the 1st query I am doing insert, and with the 2nd one I am doing update, if the data exists.
What I want to do is merge both stored procedures in one, where the query will check if the data exists than update, else insert a new row.
Here is what I have at this time:
update SP:
ALTER PROCEDURE [dbo].[UpdateStep1](#UserId nvarchar(50), #First_Name nvarchar(50), #Last_Name nvarchar(50),
#TitlePosition nvarchar(30))
AS
BEGIN
UPDATE Company_Information
SET First_Name = #First_Name,
Last_Name = #Last_Name,
Title_Position=#TitlePosition,
WHERE UserId = #UserId
END
insert SP:
ALTER PROCEDURE [dbo].[InsertStep1](#UserId nvarchar(50), #First_Name nvarchar(50), #Last_Name nvarchar(50),
#TitlePosition nvarchar(30))
AS
BEGIN
INSERT INTO Company_Information(UserId,
First_Name,
Last_Name,
Title_Position)
VALUES
(#UserId,
#First_Name,
#Last_Name,
#TitlePosition)
END
So, I would like to merge both SP in one, and the SP to check if there is already data for that UserId than update, else insert a new row.
MERGE Statement?
CREATE PROCEDURE [dbo].[MERGEStep1](#UserId nvarchar(50), #First_Name nvarchar(50), #Last_Name nvarchar(50), #TitlePosition nvarchar(30))
AS
BEGIN
MERGE Company_Information WITH(HOLDLOCK) AS T
USING(SELECT 1 S) S
ON T.UserId = #UserId
WHEN MATCHED THEN UPDATE SET
First_Name = #First_Name,
Last_Name = #Last_Name,
Title_Position=#TitlePosition
WHEN NOT MATCHED THEN
INSERT (UserId, First_Name, Last_Name, Title_Position)
VALUES(#UserId, #First_Name,#Last_Name,#TitlePosition);
END
Follow these steps:
Create a variable to test it (ex: #id)
Select #id = UserId from Company_Information where UserId = #UserId
If #id = #userId update, otherwise insert
As #gbn specified, be aware of concurrence issues.