fail to insert into two tables via stored procedures - sql-server

I'm trying to insert into two tables at the same time via stored procedure but it writes to only one table and fail to the other.
ALTER PROCEDURE [dbo].[insert_emp_pics]
#EmpName nvarchar(100),
#Nationality nvarchar(30),
#PassportPic nvarchar(100),
#Pic nvarchar(100)
AS
Begin
set nocount on;
DECLARE #ID int,
#Emp_ID int
insert into Employee (EmpName,Nationality)
values (#EmpName,#Nationality)
select #ID = ##IDENTITY
insert into DatePics
(PassportPic,Pic)
values
(#PassportPic ,#Pic)
select #Emp_ID = ##IDENTITY
end
There is relation between two tables
first table [Employee] PK ID
second table [DatePics] FK Emp_ID
this is the error message after executing this statement.
Cannot insert the value NULL into column 'Emp_ID', table 'QTecTest.dbo.DatePics';
column does not allow nulls. INSERT fails.

You need to insert the new Emp_Id as a Foreign Key to DatePics (and assuming both tables have identity columns):
insert into Employee (EmpName,Nationality)
values (#EmpName,#Nationality);
set #EMP_ID = SCOPE_IDENTITY();
insert into DatePics (PassportPic,Pic, Emp_ID)
values (#PassportPic ,#Pic, #EmpID);
set #DatePicsID = SCOPE_IDENTITY();
Also, please use SCOPE_IDENTITY over ##IDENTITY - ##Identity is vulnerable to issues where a Trigger also creates an new (unrelated) identity.

A column declared as primary key cannot have NULL values.
In your stored procedure you are not supplying value to Emp_ID column and so Insert fails.
If you want to automatically insert values in that column make it as IDENTITY column also

Related

Insert values in second table using triggers

I have one table called [FridgeTemperture], when any record inserted it should add one value in the new table MpSensors. But records are not being inserted in the new table when a record is inserted.
Error
Explicit value must be specified for identity column in table
'MpSensors' either identity_insert is set to ON or when a replication
user is inserting into a not for replication identity column.
CREATE TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
SET IDENTITY_INSERT MpSensors ON;
SET NOCOUNT ON;
DECLARE #fridge_temp varchar(10)
INSERT INTO MpSensors(fridge_temp)
VALUES(#fridge_temp)
SET IDENTITY_INSERT MpSensors OFF;
END
GO
table schema
CREATE TABLE [dbo].[MpSensors](
[id] [int] IDENTITY(1,1) NOT NULL,
[fridge_temp] [varchar](10) NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[FridgeTemperture](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ShopId] [nvarchar](4) NULL,
[Fridgetemp] [decimal](4, 2) NOT NULL,
[UpdatedDate] [datetime2](7) NOT NULL
GO
You don't need the set identity_insert on if you are not attempting to insert values to the identity column. Also, your current insert statement, if you loose the set identity_insert, will simply inside a single null row for any insert statement completed successfully on the FridgeTemperture table.
When using triggers, you have access to the records effected by the statement that fired the trigger via the auto-generated tables called inserted and deleted.
I think you are after something like this:
CREATE TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
INSERT INTO MpSensors(fridge_temp)
SELECT CAST(Fridgetemp as varchar(10))
FROM inserted
END
Though I can't really see any benefit of storing the same value in two different places, and in two different data types.
Update
Following our conversation in the comments, you can simply use an update statement in the trigger instead of an insert statement:
UPDATE MpSensors
SET fridge_temp = (
SELECT TOP 1 CAST(Fridgetemp as varchar(10))
FROM inserted
ORDER BY Id DESC
)
This should give you the latest record in case you have an insert statement that inserts more than a single record into the FridgeTemperture table in a single statement.
create TRIGGER [dbo].[FridgeTemperature_INSERT]
ON [dbo].[FridgeTemperture]
AFTER INSERT
AS
BEGIN
UPDATE MpSensors
SET fridge_temp = CAST(Fridgetemp as varchar(10))
FROM inserted
END
You need to use Select statement with CAST as [fridge_temp] is varchar in MpSensors table in Trigger. Try like this:
CREATE trigger <table_name>
ON <table_name>
AFTER Insert
AS
BEGIN
INSERT INTO <table_name>(column_name)
Select CAST(column_name as varchar(10))
FROM inserted
END
The inserted table stores copies of the affected rows during INSERT and UPDATE statements. During an insert or update transaction, new rows are added to both the inserted table and the trigger table. The rows in the inserted table are copies of the new rows in the trigger table.

SQL Insert along with matching audit at same time from app

I've got an app that will insert lines to table [P_R], which has first field being [PrimaryKey].
Now I have to add another table, [Actions] with fields [PrimaryKey],[P_R_PK],[User],[ActionTime].
When the app inserts a line to [P_R], I don't know what the PrimaryKey will be, but I have to simultaneously insert to [Actions] with the value in [P_R_PK] being the PrimaryKey I just added to [P_R]. How do I get this PrimaryKey value to [P_R_PK]?
For reference, I'm using a vb.net windows form with a SQL Server database.
If you're using a stored procedure to add the records to [P_R], you can call another stored procedure in the first that includes the primary key. For example:
CREATE PROC AddToP_R
#field1 varchar(10),
#field2...10
AS
BEGIN
declare #pk int --primary key that's created upon inserting
--insert into [P_R]
INSERT INTO [P_R]
VALUES (#field1,...)
--set the var we created to be the primary key
SET #pk = SCOPE_IDENTITY()
--call second proc
EXEC Second_Proc #pk
END
If you need other fields in the second stored procedure, include them in the first procedure parameter list.
Another way would be to a wrapper stored procedure that calls both the other two. For this to work, you would need an output variable in the first procedure to return the primary key. For example:
CREATE PROC AddWrapper
#fieldsforfirstproc...,
#fieldsforsecondproc...
AS
BEGIN
declare #outputVar int --primary key
EXEC firstproc #fieldsforfirstproc..., #outputvar output --adds the record to the first table and returns #outputvar as the primary key
EXEC secondproc #fieldsforsecondproc..., #outputvar --adds the record to the second table using #output var
END
I prefer the second option because it removes logic from the first procedure that doesn't need to be there. However, the first procedure would be slightly different to how I showed earlier.
CREATE PROC AddToP_R
#field1 varchar(10),
#field2...10,
#pk int OUTPUT --primary key that's created upon inserting
AS
BEGIN
--insert into [P_R]
INSERT INTO [P_R]
VALUES (#field1,...)
--set the var we created to be the primary key
SET #pk = SCOPE_IDENTITY()
END
You can retrieve it by using SELECT SCOPE_IDENTITY() after the INSERT.
For example:
DECLARE #T table (id int PRIMARY KEY IDENTITY, value int)
INSERT INTO #T (value) VALUES (2)
SELECT SCOPE_IDENTITY() new_pk
I would also consider doing it all in one stored procedure within a transaction. Given that you are inserting into more than one table, a transaction would allow you to roll back should anything go wrong.

How do find the last added ID in a non auto incremented table?

How do I get the ID of the last added element in the? From my searching on the web I found that you can use ##IDENTITY and IDENTITY_SCOPE() but only while adding them/being in the. I tried the following but it isn't working
CREATE TABLE Products
(PT_ID int PRIMARY KEY, Name nvarchar(20))
CREATE TABLE Storage(ST_ID int Primary key,Info nvarchar(20))
CREATE TABLE ProductStorageMM
(ST_ID int CONSTRAINT S_FK FOREIGN KEY REFERENCES Storage(ST_ID ),
PT_ID int CONSTRAINT P_FK FOREIGN KEY REFERENCES Products(PT_ID ),
Status int not null,
PRIMARY KEY (ST_ID ,PT_ID )
)
The tables above are just for the experiments sake.I am trying to, when adding a value into the Product table automatically set all the values of the given product in The storages to zero.
CREATE PROCEDURE AddingProduct
(#PID int ,#NAME nvarchar(20))
AS BEGIN
INSERT INTO Products(PT_ID,Name)
VALUES(#PID,#NAME)
INSERT INTO PSKT (PT_ID,ST_ID,Status)
SELECT PTT.PT_ID ,STT.ST_ID,0
FROM (SELECT * FROM Storage) AS STT,
(SELECT * FROM Products WHERE PT_ID=SCOPE_IDENTITY()) AS PTT;
END
The Procedure doesn't work.What am I doing wrong?
Am I missing something? Isn't #PID the last identity used? ##IDENTITY and SCOPE_IDENTITY are used for auto-increment identities. You're not showing auto-increment here, you're passing the identity in to the procedure. This inserts a row into PSKT for the #PID passed in with every row in STORAGE.
--> Given code where identity is passed in through a parameter
CREATE PROCEDURE AddingProduct
(#PID int ,#NAME nvarchar(20))
AS BEGIN
INSERT INTO Products(PT_ID,Name)
VALUES(#PID, #NAME)
INSERT INTO PSKT (PT_ID,ST_ID,Status)
SELECT #PID ,STT.ST_ID,0
FROM Storage STT
END
--> Example using auto-increment and ##identity
CREATE PROCEDURE AddingProduct
(#NAME nvarchar(20))
AS BEGIN
INSERT INTO Products(Name) --< identity is inserted through auto-increment
VALUES(#NAME)
set #pid = ##identity --< we need to get the identity created in the previous step for the next step.
INSERT INTO PSKT (PT_ID,ST_ID,Status)
SELECT #PID ,STT.ST_ID,0
FROM Storage STT
END

Error while inserting data with stored procedure in table with shared identity primary key

I've got a few tables linked together where data should be inserted to using a stored procedure. The tables are:
create table contactpersoon
(
contactpersoonnr integer identity(1,1),
klantnr integer,
naam varchar(50) not null,
telefoonnr varchar(10) not null,
emailadres varchar(50) not null,
constraint pk_contactpersoon
primary key(contactpersoonnr, klantnr),
constraint fk_contactpersoon_klantnr
foreign key(klantnr) references klant(klantnr)
)
create table klant
(
klantnr integer identity(1,1) primary key,
bedrijfsnaam varchar(50) not null
)
create table Logins
(
GebruikersNaam varchar(30),
Wachtwoord varchar(30),
Klantnr int,
MdwNr int,
constraint pk_logID primary key(GebruikersNaam),
constraint fk_klantnr foreign key(klantnr) references klant(klantnr),
constraint fk_mdwnr foreign key(mdwnr) references medewerker(mdwnr)
)
Stored procedure for adding data to these tables:
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'spKlantAanmaken')
DROP PROCEDURE spKlantAanmaken
GO
Create Procedure spKlantAanmaken
(
#bedrijfsnaam as varchar(255),
#contactnaam as varchar(255),
#telnr as integer,
#email as varchar(255),
#gebruikersnaam as varchar(255),
#wachtwoord as varchar(255)
)
AS
Begin transaction
Declare #klantnr integer
Declare #contactpersoonnr integer
Insert into Klant Values (#klantnr, #bedrijfsnaam);
Insert into contactpersoon values(#contactpersoonnr, #klantnr, #contactnaam, #telnr, #email);
Insert into Logins values (#gebruikersnaam, #wachtwoord ,#klantnr, NULL);
Select * from contactpersoon
IF ##ERROR <> 0
BEGIN
ROLLBACK
RAISERROR ('Error tijdens uitvoeren van stap 2.', 16, 1)
RETURN
END
COMMIT
GO
I don't know if it is necessary to use these identity values in the inserts.
If I try this stored procedure I get the following error:
Msg 8101, Level 16, State 1, Procedure spKlantAanmaken, Line 923
An explicit value for the identity column in table 'Klant' can only be
specified when a column list is used and IDENTITY_INSERT is ON.
If I remove the identity values from the insert I get this error:
Msg 213, Level 16, State 1, Procedure spKlantAanmaken, Line 923
Column name or number of supplied values does not match table definition.
What am I doing wrong?
When you use Identity, the columns on which the identity is applied need not be in your INSERT statement VALUES. So edit your code like below
EDIT
It also seems you are missing out the columns you are trying to insert into
Insert into Klant (bedrijfsnaam) Values (#bedrijfsnaam)
Insert into contactpersoon (klantnr, contactnaam, telnr, email) Values (#klantnr, #contactnaam, #telnr, #email)
It seems all the answers saying the same thing so hope your issued is solved
Since you have identity columns, you must specify the list of columns to insert into, in your INSERT statement, and not supply a value for the identity column - like this:
Instead of
Insert into Klant Values (#klantnr, #bedrijfsnaam);
use
Insert into Klant(bedrijfsnaam) Values (#bedrijfsnaam);
and do this for all your INSERT operations.
This is a generally accepted "Best Practice" for any time you insert something into a table - it is recommend to always explicitly specify the list of columns in your table that you're inserting into (to avoid annoying errors and surprises).
Avoid the identity columns klantnr, contactpersoonnr in the INSERT query and explicitly define your column names:
So the below code will work in your case:
Insert into Klant(bedrijfsnaam) Values (#bedrijfsnaam);
Insert into contactpersoon(klantnr, naam, telefoonnr, emailadres) values(#klantnr, #contactnaam, #telnr, #email);
Just specify the column names AND the contents in the INSERT statement like:
INSERT INTO klant (bedrijfsnaam) VALUES ('XYZ');
If you don't specify the column name list, the SQL interpreter implies, you want the identity column, too. In this case you would want to set data for 2 columns, but only provide one content element, which explains the latter error message.
Edit these two lines in your SP
Insert into Klant (bedrijfsnaam)
Values (#bedrijfsnaam);
Insert into contactpersoon(klantnr,naam,telefoonnr,emailadres)
values(#klantnr, #contactnaam, #telnr, #email);
Provide a column list, excluding the identity columns in the insert statements

Stored procedure select max value and insert

I am trying to select max: value from a table and insert value into same table.
The code is:
CREATE PROCEDURE [dbo].[InsertLogin]
#LOG_ID INT OUTPUT,
#LOG_NAME VARCHAR(100),
#LOG_EMAIL VARCHAR(100)
AS
INSERT INTO login(LOG_NAME, LOG_EMAIL)
VALUES(#LOG_NAME, #LOG_EMAIL)
SET #LOG_ID = ##IDENTITY
The other values are inserting except LOG_ID its getting null.
My guess is your Log_Id column in your Login table is not setup to be an Identity.
Through T-SQL, you have to drop and readd the column:
alter table login
drop column log_id
alter table login
alter column log_id int not null Identity(1,1)
Alternatively you can do this pretty easily in SSMS. Here's a decent article on the subject:
http://blog.sqlauthority.com/2009/05/03/sql-server-add-or-remove-identity-property-on-column/
I'd also recommend using SCOPE_IDENTITY() over ##Identity

Resources