Stored Procedure with two raiserrors - sql-server

I use SQL Server.
I want to write a stored procedure that looks if a questionid and employeeid exists (questionid is in the table question, same for employeeid, is in the table employee) AND looks if they not already existing in the table (you don't get a duplicate in the table contentment). I want raiserror's for the user if so.
In my case it is possible to have a duplicate but not on the same DATE!
Contentment table has columns:
employeeid, questionid, date, score
employeeid, questionid, date make up the primary key.
So I want something like this:
1,1, 18-11-2018, null
1,1, 19-11-2018, null
and not something like this:
1,1, 18-11-2018, null
1,1, 18-11-2018, null
I already made something but it is not working (1-1-1900 is a standard date, because it is primary key it needs to be inserted, score is not inserted because the user needs to do this):
#employeeid int,
#questionid int
as
begin
if exists (select * from question where questionid = #questionid)
and exists (select * from employee where employeeid= #employeeid)
begin
insert into contentment (employeeid, questionid, date, score)
values (#employeeid, #questionid, '1-1-1900', null)
end
if (select count(*)
from contentment
where employeeid = #employeeid
and questionid = #questionid
and date = date) = 0
raiserror ('#employeeid or #questionid already existing', 16, 1)
else
raiserror ('#employeeid or #questionid are not existing', 16, 1, null)
end

If you want to date validation you need to provide #date as well. I have created a sample stored procedure with detail that you provide:
DROP PROCEDURE P_ContentmentInsert
GO
CREATE PROCEDURE P_ContentmentInsert
#employeeid int,
#questionid int,
#date DATE
AS
BEGIN
--Check if exists Employee, Question and Contentment
DECLARE #IsEmployeeExists INT=ISNULL((SELECT COUNT(1) FROM employee WHERE employeeid= #employeeid),0)
DECLARE #IsQuestionExists INT=ISNULL((SELECT COUNT(1) FROM question WHERE questionid = #questionid),0)
DECLARE #IsContentmentExists INT=ISNULL((SELECT COUNT(1) FROM contentment WHERE questionid = #questionid and employeeid= #employeeid and [date]=#date),0)
DECLARE #ErrorMessage VARCHAR(1000)=''
--If one of the validation not passed give error message
IF (#IsEmployeeExists=0 OR #IsQuestionExists=0 OR #IsContentmentExists=0)
BEGIN
IF #IsEmployeeExists=0
SET #ErrorMessage='-EmployeeId Not exists'
IF #IsQuestionExists=0
SET #ErrorMessage=#ErrorMessage+'-QuesitonId Not exists'
IF #IsContentmentExists=0
SET #ErrorMessage=#ErrorMessage+'-Contentment already exists'
RETURN
END
--If there is no problem insert it.
IF #IsEmployeeExists>0 and #IsQuestionExists>0 and #IsContentmentExists>0
BEGIN
INSERT INTO contentment (employeeid, questionid, date, score)
VALUES (#employeeid, #questionid, #date, null)
END
END

Related

How to load in data and insert data together with a stored procedure

I need to load in data first and then insert data into the same table.
I use a stored procedure to load in the data (I'm using SQL Server):
#employeeid int,
#thequestion varchar (220) output
)
as
begin
begin transaction
select #thequestion = thequestion
from question q
join contentment c on q.questionid= c.questionid
where c.employeeid = #employeeid
if ##ERROR <> 0
begin
rollback
raiserror ('You don't have question to answer', 16, 1)
return
end
commit
end
Then the user can add data to the table contentment. He only can add a score and a comment
Contentment table:
employeeid,
questionid,
date,
score,
comment
I using this stored procedure:
(#score int,
#comment varchar(50),
#date date
)
as
begin
begin transaction
insert into contentment (date, score, comment)
values (#date, #score, #comment)
if ##ERROR <> 0
begin
rollback
raiserror ('-some error-', 16, 1)
return
end
commit
end
The problem is that in the second stored procedure questionid and employeeid should not be inserted, it is already inserted, to link a employeeid to a questionid. But when I want to add a score and comment to this, I get an error that questionid and employeeid need to be inserted (otherwise it has value NULL). Also the problem is that my second stored procedure doesn't know which question belongs to the questionid/employeeid. I hope someone understand this, I know it is a bit weird.
Sorry I was busy travelling.
I tried creating 2nd procedure as follows.
Here I have created employeeid and questionid as 2 variables which we will passs while executing this stored procedure:
create procedure Proc2
(
#employeeid int
,#questionid int
,#score int
,#comment varchar(50)
,#date date
)
as
begin
begin transaction
insert into contentment (date, score, comment)
select #date = date, #score = score, #comment = comment
where employeeid = #employeeid and questionid = #questionid
if ##ERROR <> 0
begin
rollback
raiserror ('-some error-', 16, 1)
return
end
end transaction
commit
end

How to use output parameter with other columns names in SQL Server

I have a simple table with columns - id, name, and salary.
I want to get the name, salary and annual salary by id using a stored procedure.
I thought of creating a simple stored procedure like this:
CREATE PROCEDURE spGetDetails
#id int,
#annualSal int out
AS
BEGIN
SELECT
name, salary,
#annualSal = (salary * 12)
FROM
tblPrac
WHERE
id = #id
END
But I'm getting an error:
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations
If this qs is already asked please give me the link and I'll delete this qs. I searched but I think I'm missing the key word. Thanks
You don't need an OUTPUT parameter. You can simply query like this -
CREATE PROCEDURE spGetDetails
#id int
AS
BEGIN
SET NOCOUNT ON
SELECT Name, Salary, (Salary*12) AS AnnualSalary FROM tblPrac WHERE id = #id
END
You have stuff mixed so you need to choose between 2 possibilities
CREATE PROCEDURE spGetDetails
#id int,
#name varchar(100) out,
#salary decimal(16,2) out,
#annualSal decimal(16,2) out
AS
BEGIN
set nocount on
SELECT #name = name,
#salary = salary,
#annualSal = (salary * 12)
FROM tblPrac
WHERE id = #id
END
or this
CREATE PROCEDURE spGetDetails
#id int
AS
BEGIN
set nocount on
SELECT name,
salary,
(salary * 12) as anualSal
FROM tblPrac
WHERE id = #id
END
You need to store the data and separate the operations (as the error message is explaining):
CREATE PROCEDURE spGetDetails
(
#id int,
#annualSal int out
)
AS
BEGIN;
SET NOCOUNT ON;
DECLARE #DataSource TABLE
(
[name] VARCHAR(12)
,[salary] DECIMAL(9,2)
);
INSERT INTO #DataSource ([name], [salary])
SELECT name, salary
FROM tblPrac
WHERE id = #id;
SELECT [name]
,[salary]
FROM #DataSource;
SELECT #annualSal = 12 * [salary]
FROM #DataSource;
SET NOCOUNT OFF;
RETURN;
END;

Triggers not working when inserting data through OPEN XML in sql ser

I have created a trigger for a asset_verification. Whenever a new record is inserted in this table, the same record is inserted in the asset_verification_history table because of this trigger.
The trigger is as follows
Create trigger [dbo].[tr_insert_after_asset_verification] on [dbo].[asset_verification]
for insert
As
Begin
declare #verification_id int
declare #id int
declare #audit_id int
declare #date date
declare #status varchar(15)
declare #remarks varchar(200)
declare #creationDate datetime
declare #modificationDate datetime
declare #updatedBy int
declare #audit_action varchar(20)
Select #verification_id = i.verification_id from inserted i
If #verification_id IS NOT NULL
Begin
Select #id = i.id from inserted i
Select #audit_id = i.audit_id from inserted i
Select #date = i.date from inserted i
Select #status = i.status from inserted i
Select #remarks = i.remarks from inserted i
Select #creationDate = i.creationDate from inserted i
Select #modificationDate = i.modificationDate from inserted i
Select #updatedBy = i.updatedBy from inserted i
set #audit_action = 'Insert Record'
INSERT INTO [dbo].[asset_verification_history]
([verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action])
VALUES
(#verification_id
,#id
,#audit_id
,#date
,#status
,#remarks
,#creationDate
,#modificationDate
,#updatedBy
,#audit_action)
End
End
When I insert the data in the asset_verification table using a procedure in which OPEN XML is used, then this trigger works only for the first record. For the rest of the records the trigger doesn't work
The procedure is as follows
Create procedure [dbo].[usp_AddVerificationBulkData]
(
#vXML XML
)
As
Begin
DECLARE #DocHandle INT
SET NOCOUNT ON
EXEC sp_xml_preparedocument #DocHandle OUTPUT, #vXML
Update asset_verification
set
audit_id = x.AuditId,
id = x.SerialId,
date = x.VerificationDate,
status = x.Status
,remarks = x.Remarks
,creationDate = x.CreatedOn
,modificationDate = x.ModifiedOn
,updatedBy = x.ModifiedBy
From
asset_verification a
Inner Join
OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
On a.audit_id = x.AuditId where a.id = x.SerialId;
INSERT INTO [dbo].[asset_verification]
([id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy])
select SerialId,AuditId,VerificationDate,Status,Remarks,CreatedOn,ModifiedOn,ModifiedBy from OpenXml(#DocHandle,'/ArrayOfAssetVerificationModel/AssetVerificationModel',2)
With(SerialId int, AuditId int, VerificationDate datetime, Status int, Remarks varchar(200), CreatedOn datetime, ModifiedOn datetime, ModifiedBy int) x
where SerialId NOT IN (select a.id from asset_verification a where a.audit_id = x.AuditId);
End
Problem:- How to make this trigger work for every record that is inserted through Open XML ?
You've made the classic mistake of thinking that triggers fire once-per-row. They dont, it's once-per-action, so the inserted pseudo table holds all the rows affected by the action. Your trigger needs to work in a set based manner, not row based. Try this;
CREATE TRIGGER [dbo].[tr_insert_after_asset_verification] ON [dbo].[asset_verification] FOR INSERT AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[asset_verification_history]
( [verification_id]
,[id]
,[audit_id]
,[date]
,[status]
,[remarks]
,[creationDate]
,[modificationDate]
,[updatedBy]
,[audit_action]
)
SELECT i.verification_id
,i.id
,i.audit_id
,i.date
,i.status
,i.remarks
,i.creationDate
,i.modificationDate
,i.updatedBy
,'Insert Record'
FROM inserted i
WHERE i.verification_id IS NOT NULL
END
As an aside, and strictly speaking, your original trigger will log one row, not necessarily the first.

to insert into one table if record is null

Hi I have a problem with my stored procedure, I want to insert into three tables which I created a stored procdure to do that, yet I have these two tables called wishlist and general. I want to insert into the wishlist table if the dateaquired row is null but the script I created inserts into the the table regardless, could someone please improve my script so that it does not insert into my wishlist table if my dateaquired row from my general table is not null.
USE [MediaPlayer]
GO
/****** Object: StoredProcedure [dbo].[CreateBooks] Script Date: 12/03/2013 19:05:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[CreateBooks]
-- Add the parameters for the stored procedure here
#Name nvarchar (250),
#FileName nvarchar (250),
#FilePath nvarchar (50),
#FileSize float,
#DateAdded date,
#MediaLength nvarchar (50),
#MediaSubType nvarchar(50),
#MediaType nvarchar(50),
#Thumbnail image,
#DateAquired nvarchar(50),
#BooksName nvarchar (50),
#Publisher nvarchar(50),
#Author nvarchar(50),
#YearOfPublication date,
#Genre nvarchar(50),
#ISBN nvarchar (50),
#Synoposis nvarchar(50),
#SeriesTitle nvarchar(50),
#SeriesNumber nvarchar(50),
#GeneralID int output,
#BookID int output,
#WishListID int output
AS
BEGIN
Insert into dbo.General
(Name, FileName, FilePath, FileSize, DateAdded, MediaLength,
MediaSubType, MediaType, Thumbnail, DateAquired)
values (#Name, #FileName, #FilePath, #FileSize, #DateAdded, #MediaLength,
#MediaSubType, #MediaType, #Thumbnail, #DateAquired)
SET #GeneralID = ##IDENTITY
insert into dbo.Book
(GeneralID, BooksName, Publisher, Author, [Year of publication], Genre,
ISBN, Synoposis,[Series Title],[Series Number])
Values (IDENT_CURRENT('dbo.General'), #BooksName, #Publisher, #Author, #YearOfPublication, #Genre,
#ISBN, #Synoposis, #SeriesTitle, #SeriesNumber)
SET #BookID = ##IDENTITY
Select GeneralID, Name, FileName, FilePath,FileSize,DateAdded,MediaLength,MediaSubType,MediaType, Thumbnail,DateAquired As Wishlist
From General where NULLIF(DateAquired,'')IS Null
Select * from WishLists
select GeneralID, MediaSubType, Name
From General where NOT EXISTS (Select Name from WishLists Where Name =#Name);
insert into Wishlists (generalID ,MediaType, Name)
values ((IDENT_CURRENT('dbo.General')),#MediaSubType, #Name)
SET #WishListID = ##IDENTITY
select * from wishlists
END
I could be wrong but to me it seems you are missing some logic cases.
Your code:
Select GeneralID, Name, FileName, FilePath, FileSize, DateAdded,
MediaLength,MediaSubType,MediaType, Thumbnail, DateAquired As Wishlist
From General where NULLIF(DateAquired,'')IS Null
What this does is selects the named fields from General where DateAcquired is Null. On a side note, I believe (I may be wrong) that if you want all those fields AS Wishlist, you should have them all in parentheses like:
Select (GeneralID, Name, FileName, FilePath, FileSize, DateAdded,
MediaLength,MediaSubType,MediaType, Thumbnail, DateAquired) As Wishlist
From General where NULLIF(DateAquired,'')IS Null
Regardless, once you have this data you aren't doing anything with it, you are moving into a new select query, selecting * from Wishlists. Then you are selecting from General again where the the name is not in the table already. Then you are inserting into Wishlists the current Identity value of dbo.General, #MediaSUbType, #Name.
So all this code is really doing is running some queries, then regardless of those results, is inserting the Identity value of dbo.General, and the status values #MediaSubType and #Name into the table wishlist. In order for all the queries you run before to have an affect on what gets inserted, you need to use cases.
I don't know enough about the tables and things to write up the code you will need, but this answer should give you an idea of how to use CASE WHEN to do what you need.
Hope this helps some and isn't just useless ramblings from me.
If you're just trying to skip the WishList insert based on the #DateAquired being null you can modify your script as below. Please reply if this is not what you want.
BEGIN
Insert into dbo.General(Name, FileName, FilePath, FileSize, DateAdded, MediaLength, MediaSubType, MediaType, Thumbnail, DateAquired)
values (#Name, #FileName, #FilePath, #FileSize, #DateAdded, #MediaLength, #MediaSubType, #MediaType, #Thumbnail, #DateAquired);
SET #GeneralID = scope_identity(); --use this instead of ##IDENTITY
insert into dbo.Book(GeneralID, BooksName, Publisher, Author, [Year of publication], Genre, ISBN, Synoposis,[Series Title],[Series Number])
Values (#GeneralID, #BooksName, #Publisher, #Author, #YearOfPublication, #Genre, #ISBN, #Synoposis, #SeriesTitle, #SeriesNumber)
SET #BookID = scope_identity(); --use this instead of ##IDENTITY
-- you already have the DateAquired from the insert into dbo.General above, so just use the param #DateAquired
if(#DateAquired is null)
begin
insert into Wishlists (generalID, MediaType, Name)
values (#GeneralId, #MediaSubType, #Name)
SET #WishListID = scope_identity(); --use this instead of ##IDENTITY
end
select [InsertedGeneralId] = #GeneralID, [InsertedBookID] = #BookID, [InsertedWishListID] = #WishListID
END
AS
BEGIN
Insert into dbo.General
(Name, FileName, FilePath, FileSize, DateAdded, MediaLength,
MediaSubType, MediaType, Thumbnail, DateAquired)
values (#Name, #FileName, #FilePath, #FileSize, #DateAdded, #MediaLength,
#MediaSubType, #MediaType, #Thumbnail, #DateAquired)
SET #GeneralID = SCOPE_IDENTITY() --<--
insert into dbo.Book
(GeneralID, BooksName, Publisher, Author, [Year of publication], Genre,
ISBN, Synoposis,[Series Title],[Series Number])
Values (IDENT_CURRENT('dbo.General'), #BooksName, #Publisher, #Author,
#YearOfPublication, #Genre, #ISBN, #Synoposis, #SeriesTitle, #SeriesNumber)
SET #BookID = SCOPE_IDENTITY()
Select GeneralID, Name, FileName, FilePath,FileSize,DateAdded,MediaLength
,MediaSubType,MediaType, Thumbnail,DateAquired As Wishlist
From General where NULLIF(DateAquired,'')IS Null
Select * from WishLists
select GeneralID, MediaSubType, Name
From General where NOT EXISTS (Select Name from WishLists Where Name =#Name);
IF (#DateAquired IS NULL)
BEGIN
insert into Wishlists (generalID ,MediaType, Name)
values ((IDENT_CURRENT('dbo.General')),#MediaSubType, #Name)
SET #WishListID = SCOPE_IDENTITY()
END
select * from wishlists
END
Also use SCOPE_IDENTITY() instead of ##IDENTITY as it will return last generate Identity in that column , even if it was created by a concurrent connection.

SQL Trigger, sub query returning more then one value.

I m having a trouble with my trigger, it works for single row update, but for multiple updates it gives error that sub query is returning more then one value. how to handle this.
GO
ALTER TRIGGER [dbo].[OnpaymentUpdate]
ON [dbo].[paymentData]
AFTER UPDATE
AS
BEGIN
SET NOCOUNT ON;
DECLARE #customerID NCHAR(50), #lastpaymentDate DATETIME, #stat nchar(50), #month int;
SET #customerID= (SELECT customerID FROM inserted)
SET #stat= (SELECT stat FROM inserted) --table inserted contains inserted rows (or new updated rows)
set #lastpaymentDate = (SELECT MAX(paymentDate) FROM paymentReceipt where customerID=#customerID)
SET #month= (SELECT DATEDIFF(MONTH, #lastpaymentDate,GETDATE()))
DECLARE #balance BIGINT
SET #balance =
(
SELECT (totalprice-(paidAmount+concession))
FROM paymentData
WHERE customerID = #customerID
)
Declare #paid int
SET #paid =
(
SELECT paidAmount
FROM paymentData
WHERE customerID = #customerID
)
UPDATE PaymentData
SET balanceAmount = #balance ,
lastpaymentDate=#lastpaymentDate
WHERE customerID = #customerID
if (#month >=2 and #stat!='Cancel' and #stat!='Refund' And #stat!='Refunded' and #stat!='Transfered' and #stat!='Transfer')
Begin
IF (#month <2 and #stat='Defaulter')
SET #stat='Regular'
IF (#balance<=0 and #paid >0)
SET #stat='Payment Completed'
else
SET #stat='Defaulter'
End
else
Begin
if #stat='Refund'
Set #stat='Refunded'
if #stat='Cancled'
Set #stat='Cancel'
if #stat='Transfer'
Set #stat='Transfered'
End
UPDATE PaymentData
SET stat =#stat
WHERE customerID = #customerID
END
I wouldn't have a trigger at all. I'd rebuild your table and then create a view that mimics your current table definition. Of course, I don't know your current tables, so I can only write my best guess for now. And as I said, I don't understand your status logic at the bottom where #month can apparently be, simultaneously, both >=2 and <2, so I've left that portion incomplete:
create table dbo._PaymentData (
CustomerID nchar(50) not null,
_Status nchar(50) not null,
TotalPrice bigint not null,
PaidAmount bigint not null,
Concession bigint not null,
Balance as TotalPrice - (PaidAmount + Concession)
)
go
create view dbo.PaymentData
with schemabinding
as
with RecentReceipts as (
select CustomerID,MAX(PaymentDate) as LastPayment from dbo.PaymentReceipt group by CustomerID
), MonthsDelinquent as (
select CustomerID,LastPayment,DATEDIFF(month,LastPayment,CURRENT_TIMESTAMP) as Months from RecentReceipts
)
select
pd.CustomerID,
TotalPrice,
PaidAmount,
Concession,
Balance,
LastPayment,
CASE
WHEN _Status in ('Cancel','Refund','Refunded','Transfered','Transfer')
THEN _Status
WHEN md.Months > 2 and Balance<= 0 and PaidAmount > 0
THEN 'Payment Complete'
--More conditions here to work out the actual status
END as Status
from
dbo._PaymentData pd
left join
MonthsDelinquent md
on
pd.CustomerID = md.CustomerID
go
And now, we don't need the trigger - the table and/or the view are always up correct (although a trigger may be required on the view to allow Status/_Status to be updated - it's not currently clear whether that's necessary or whether _Status actually needs to exist at all)
Could their be more than one CustomerID added in the process? This line is trouble:
SET #customerID= (SELECT customerID FROM inserted)
SET #stat= (SELECT stat FROM inserted) --table inserted contains inserted
If customerID and stat are guaranteed to be consistent for all rows, you can fix it with a MAX, like:
SET #customerID= (SELECT MAX(customerID) FROM inserted)
SET #stat= (SELECT MAX(stat) FROM inserted) --table inserted contains inserted
But, if those items aren't guaranteed to be consistent for all rows inserted, you will run into trouble. If that's the case, you'll need a cursor to cursor through the values.
Also Change to this:
SET #balance =
(
SELECT SUM( (totalprice-(paidAmount+concession)) )
FROM paymentData
WHERE customerID = #customerID
)
Declare #paid int
SET #paid =
(
SELECT SUM(paidAmount)
FROM paymentData
WHERE customerID = #customerID
)

Resources