Stored Procedure for Multi-Table Insert Error: Cannot Insert the Value Null into Column - sql-server-2005

Good Evening All,
I've created the following stored procedure:
CREATE PROCEDURE AddQuote
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #CompanyName nvarchar(50),
#Addr nvarchar(50),
#City nvarchar(50),
#State nvarchar(2),
#Zip nvarchar(5),
#NeedDate datetime,
#PartNumber float,
#Qty int
-- Insert statements for procedure here
Insert into dbo.Customers
(CompanyName, Address, City, State, ZipCode)
Values (#CompanyName, #Addr, #City, #State, #Zip)
Insert into dbo.Orders
(NeedbyDate)
Values(#NeedDate)
Insert into dbo.OrderDetail
(fkPartNumber,Qty)
Values (#PartNumber,#Qty)
END
GO
When I execute AddQuote, I receive an error stating:
Msg 515, Level 16, State 2, Procedure AddQuote, Line 31
Cannot insert the value NULL into column 'ID', table 'Diel_inventory.dbo.OrderDetail'; column does not allow nulls. INSERT fails.
The statement has been terminated.
I understand that I've set Qty field to not allow nulls and want to continue doing so. However, are there other syntax changes I should make to ensure that this sproc works correctly?
Thanks,
Sid

You have an ID column in the OrderDetail table
You are not giving a value for ID in the INSERT
so
change the OrderDetail insert to give a value
or ensure the column has an IDENTITY
or ensure it has a default (not useful if it's the PK but generally it's an option)

Looks to me like you forgot to enable "identity specification" for the ID column of the OrderDetail table. It has nothing to do with your stored procedure per se.
You will need to recreate the table to make the ID column have IDENTITY, but SQL Management Studio will script that for you.

Related

Get the inserted row causing the execution of the trigger

I want to get the value of the row causing the execution of the trigger. So I can pass it (as a parameter) to a stored procedure.
The stored procedure accepts as input a table type which is defined in the script below:
CREATE TYPE PersonTableType AS TABLE
(
Id int primary key,
FirstName nvarchar(50),
LastName nvarchar(50)
)
The procedure (insert in the ArchivePerson table the inserted row from the trigger)
Create PROCEDURE sp1
#PersonType PersonTableType Readonly
As
BEGIN
Insert Into ArchivePerson
Select * From #PersonType
END
How do I declare my trigger?
I tried something like:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
??
Exec sp1 #PersonType
END
The inserted table has the rows which were, well, inserted. It has the same columns with your original [Person] table, so use the appropriate columns:
Alter TRIGGER insertPerson
ON Person
AFTER Insert
AS
BEGIN
declare #PersonType PersonTableType;
insert #PersonType(Id,FirstName,LastName)
select <corresponding columns>
from inserted
Exec sp1 #PersonType
END

Select specific columns from the stored procedure

I have a stored procedure in other database which is maintained by other team. Assume that it is currently returning 3 columns, and my system only needs those 3 columns
but the other team can add few more columns for their own use which is causing my system to fail.
Other database SP
ALTER PROCEDURE FirstSP
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #A (Id INT, Name VARCHAR(200), Amount VARCHAR(100), TestColumn INT)
INSERT INTO #A VALUES
(1,'ABC','23',1), (2,'CDF','35454',2), (3,'hjhj','9809909',3)
SELECT * FROM #A
DROP TABLE #A
END
GO
And below is my query, which was only expecting 3 columns from the source
CREATE TABLE #MyTable (Id INT, Name VARCHAR(200), Amount INT)
INSERT INTO #MyTable
EXEC dbo.FirstSP;
SELECT * FROM #MyTable
DROP TABLE #MyTable
Is there any way I can provide the column list?
This is what I am trying but it seems that I can't use server name as the parameter
DECLARE #ServerName VARCHAR(100) = ##SERVERNAME
SELECT * FROM OPENQUERY(#ServerName,'EXEC dbo.FirstSP')
My whole problem is to just select required columns from the SP. SP can have many columns in future.
Try this:
/*
-----------------------------------------------------------------------
Replace <SERVERNAME>\<INSTANCENAME>], <DATABASENAME> with your names
*/ ------------------------------------------------------------------------
-- First, enable Data Access (One time only)
EXEC sp_serveroption '<SERVERNAME>\<INSTANCENAME>', 'DATA ACCESS', TRUE;
-- Then SELECT just the fields you need
SELECT ID, Name, Amount
FROM OPENQUERY([<SERVERNAME>\<INSTANCENAME>], 'EXEC <DATABASENAME>.dbo.FirstSP')
I would ask the team that develops the stored procedure to create a parameter "Team" or something and slightly change the sp so that it will return the expected columns based on this parameter.
A more cumbersome solution is to use this stored procedure the get the colum names of the (first) result returned by the sp.
sp_describe_first_result_set 'dbo.usp_mySp';
And then use the result to create some dynamic SQL.

List of foreign keys in an insert SQL Server

I am trying to set up a stored proc that will have three variables
FK_List
String_of_Info
CreateId
I need to insert into the table one entry per foreign key from the FK_List. I was curious what the best way to structure the stored procedure to do this efficiently.
EDIT: Code snippet added
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes NVARCHAR(1000),
#CreateId VARCHAR(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID], [Notes], [CreateId], [UpdateId])
VALUES (#FKList, <---- this is the problem spot
#Notes, #CreateId, #CreateId)
END
GO
Based off your comments, you simply need a slight edit
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select
someID
,#Notes
,#CreateId
,#CreateId
from FKListTable
END
GO
Here is a simple demo
This will insert a row into your table for each FK reference in the reference table with the parameters you pass in. That's all there is to it!
Here's another demo that may be more clear as I use a GUID for the primary key on the secondary table.
SECOND EDIT
Based off your comments, you will need a string splitter. I have added a common one which was created by Jeff Moden. See the example here
The final proc, after you create the function, will be like below. You need to change the comma in the function to what ever the delimiter is for your application. Also, you should start using table valued parameters.
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select item
,#Notes
,#CreateId
,#CreateId
from dbo.DelimitedSplit8K(#FKList,',')
END
And you can call it like so:
declare #FKList varchar(1000) = '1,2,3,4,5,6'
declare #Notes varchar(1000) = 'here is my note'
declare #CreatedId int = 1
exec StackOverFlowExample_BulkAdd #FKList, #Notes, #CreatedId

problem with raiseerror()

what I want to do is to create a stored procedure that executes insert statement.There is a possibility the execution to fail because of a check constraint for the table Employee.In that case I want to handle a user-defined error.Obviously the following procedure is not working properly because it always raises my error,but not only when insertion fails.
EXEC sp_addmessage 50001, 16, N'Title must be one of the following - Captain,Engineer,Flight-attendant,Purser,First-officer';
CREATE PROCEDURE InsertIntoEmployee
#firstName nvarchar(30),
#familyName nvarchar(30),
#title nvarchar(50),
#address nvarchar(50),
#chiefID int ,
#salary money ,
#FK_IDCrew int,
#FK_DepartmentID int
AS
BEGIN
declare #err_num int;
declare #err_sev int;
declare #err_msg int;
begin try
insert into Employee(firstName, familyName, title, address, chiefID, salary, FK_IDCrew,
FK_DepartmentID)
values(#firstName, #familyName, #title, #address, #chiefID, #salary, #FK_IDCrew,
#FK_DepartmentID);
raiserror(50001,16,1);
END try
begin catch
set #err_num=ERROR_NUMBER();
set #err_sev=ERROR_SEVERITY();
set #err_msg=ERROR_STATE();
raiserror(#err_num,#err_sev,#err_msg);
end catch
end
GO
In this case:
Title should be a lookup to another table and a foreign key
In the CATCH block you can trap the FK constraint violation separately if you want...
...but you'd only allow rows from the new table in your client so I wouldn't personally
No need for a sys.messages entry
Your code will also always hit the RAISERROR too which doesn't add any value,
I hope that the dimensions mentioned in the parameter list is sycn with table columns length.
Before insertion, You should check take care of following points.
Check the existence of #FK_IDCrew value in it's table.
Check the existence of #FK_DepartmentID value in it's table.
It should be like below.
If Not Exists(Select IDCrewColumnName From Table Where columnName = #FK_IDCrew)
Begin
return here from the stored procedure.
End
In case any of them fails to meet the conditions, you should show some user friendly message to user that
(a) Crew ID, you are going to insert, either deleted or does not exists in the database.
(b) DepartmentID, you are going to insert, either deleted or does not exists in the database.
In this way the probability of error will also come to an end.

What is wrong with the syntax of this OUTPUT statement (SQL Server 2005)?

I'm trying to use the OUTPUT statement in a stored procedure in order to return the ID of a newly inserted row. The stored procedure is:
CREATE PROCEDURE PROC_RESTORE_REQUEST_TO_QUEUE
#cs_uri_stem varchar(900),
#cs_uri_query varchar(2500),
#date datetime,
#time datetime,
#queue_state smallint,
#process_id int,
#simulation_start_time bigint,
#num_failures smallint
AS
SET NOCOUNT ON
INSERT INTO [DD#WORK].[dbo].[ebhFifoQueue] ([cs-uri-stem],[cs-uri-query],[date],[time],[queue_state],[process_id],[simulation_start_time],[num_failures])
VALUES (#cs_uri_stem,#cs_uri_query,#date,#time,#queue_state,#process_id,#simulation_start_time,#num_failures)
OUTPUT INSERTED.id
When I try to compile this stored procedure, I get an error message:
Incorrect syntax near 'OUTPUT'.
I've tried several permutations of this code to no avail (same error message), including moving the OUTPUT statement onto the same line as the INSERT statement. Do you know what the problem is with my syntax? Thanks in advance for your help,
-Eric
Its the order. The OUTPUT clause should go between the INSERT and the VALUES lines.
Just move yours, like this:
INSERT INTO [DD#WORK].[dbo].[ebhFifoQueue] ([cs-uri-stem],[cs-uri-query],[date],[time],[queue_state],[process_id],[simulation_start_time],[num_failures])
OUTPUT INSERTED.id
VALUES (#cs_uri_stem,#cs_uri_query,#date,#time,#queue_state,#process_id,#simulation_start_time,#num_failures)
I think it should be like:
INSERT INTO [DD#WORK].[dbo].[ebhFifoQueue] ([cs-uri-stem],[cs-uri-query],[date],[time],[queue_state],[process_id],[simulation_start_time],[num_failures])
OUTPUT INSERTED.id
VALUES
(#cs_uri_stem,#cs_uri_query,#date,#time,#queue_state,#process_id,#simulation_start_time,#num_failures)
You can also add a "INTO #MyVariable" or "INTO MyTable" after the OUPUT statement
From MSDN
DECLARE #MyTableVar table( NewScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO #MyTableVar
VALUES (N'Operator error', GETDATE());
Should be something like:
CREATE PROCEDURE PROC_RESTORE_REQUEST_TO_QUEUE
#cs_uri_stem varchar(900),
#cs_uri_query varchar(2500),
#date datetime,
#time datetime,
#queue_state smallint,
#process_id int,
#simulation_start_time bigint,
#num_failures smallint,
#new_id int OUTPUT
AS
SET NOCOUNT ON
INSERT INTO [DD#WORK].[dbo].[ebhFifoQueue] ([cs-uri-stem],[cs-uri-query],[date],[time],[queue_state],[process_id],[simulation_start_time],[num_failures])
VALUES (#cs_uri_stem,#cs_uri_query,#date,#time,#queue_state,#process_id,#simulation_start_time,#num_failures)
SET #new_id = SCOPE_IDENTITY()