SQL Server : parameterized stored procedure - sql-server

I have to do this in SQL Server. Assume that I have 2 tables.
Based on parameters Name and Surname, I have to take PhysicianID from Table1.
After that I have to create new record using insert into stored procedure.
Something like this
CREATE PROCEDURE FIND_PHYSICIANID
#FirstName varchar(50),
#LastName varchar(50)
AS
BEGIN
DECLARE #PhysicianID int
SELECT #PhysicianID = PhysicianID
FROM Table1
WHERE FirstName = #FirstName AND LastName = #LastName
RETURN #PhysicianID
END
EXECUTE FIND_PHYSICIANID 'Kathlin','Jones'
CREATE PROCEDURE ADD_APPOINTMENT -- Create a new appointment
#AppointmentType VARCHAR(70), --Type of new appointment
#pAppointmentDate DATE, -- Date of new appointment
#aPhysicianID INT, --PhysicianID of requested physician (in this case during execution we will take value which we know-read from table for requested first and last name)
#apPatientID INT, --PatientID of chosen patient(let's say any from 1 to 14)
#aScheduleID INT, --ScheduleID, but here we have to take some ScheduleID for chosen PhysicianID (in this case during execution we will take value which we know-based on PHYSICIANID we may read value from table SCHEDULE)
#Status CHAR(1) -- Just Y or N
AS -- This "AS" is required by the syntax of stored procedures.
BEGIN -- Insert the new appointment
INSERT INTO [APPOINTMENT]([AppointmentType], [AppointmentDate],[aPhysicianID],
[apPatientID], [aScheduleID], [Status-Canceled])
VALUES (#AppointmentType, #pAppointmentDate, #aPhysicianID,
#apPatientID, #aScheduleID, #Status);
END;
EXECUTE ADD_APPOINTMENT 'Vaccinations', '2017-0831', '#PhysicianID', '12', '289', 'N'

You can get return id like this.
DECLARE #PhysicianID int
EXECUTE #PhysicianID = FIND_PHYSICIANID 'Kathlin','Jones'
you can use this param like this
EXECUTE ADD_APPOINTMENT 'Vaccinations','2017-0831', #PhysicianID, '12','289','N'

Presuming that the ability to find a physician is a common operation you could convert the FIND_PHYSICIANID stored procedure to a function and delay the lookup to within the consuming stored procedure that performs the operation.
create function [dbo].[FIND_PHYSICIANID]
(
#FirstName varchar(50),
#LastName varchar(50)
)
returns int
as
begin
declare #PhysicianId int
select #PhysicianID = PhysicianID
from dbo.Table1
where FirstName = #FirstName
and LastName = #LastName
return #PhysicianId
end
This will still keep the logic of finding a physician centralised but allow you to perform other actions and possibly validation if the only information you have available to you is the full name. Yes, it is more parameters but this is assuming the required parameters for the stored procedures are a manageable amount.
create procedure [dbo].[ADD_APPOINTMENT] -- Create a new appointment
#AppointmentType VARCHAR(70), --Type of new appointment
#pAppointmentDate DATE, -- Date of new appointment
#PhysicianFirstName varchar(50), -- // The first name of the physician
#PhysicianLastName varchar(50), -- // The last name of the physician
#apPatientID INT, --PatientID of chosen patient(let's say any from 1 to 14)
#aScheduleID INT, --ScheduleID, but here we have to take some ScheduleID for chosen PhysicianID (in this case during execution we will take value which we know-based on PHYSICIANID we may read value from table SCHEDULE)
#Status CHAR(1) -- Just Y or N
AS -- This "AS" is required by the syntax of stored procedures.
BEGIN -- Insert the new appointment
declare #aPhysicianID int
select #aPhysicianID = [dbo].[FIND_PHYSICIANID](#PhysicianFirstName, #PhysicianLastName varchar(50))
INSERT INTO [APPOINTMENT]([AppointmentType], [AppointmentDate],[aPhysicianID],
[apPatientID], [aScheduleID], [Status-Canceled])
VALUES (#AppointmentType, #pAppointmentDate, #aPhysicianID,
#apPatientID, #aScheduleID, #Status);
END
Alternatively, if it is desired to be separated and keep the existing stored procedure parameter signature then the previous answer that has the caller lookup the physician id via the stored procedure locally and then pass that parameter into the add appointment stored procedure should suffice your requirements.
As per the below pseudocode
Declare a variable for #physicianid of type int
Assign the #physicianid variable to the output of the FIND_PHYSICIANID stored procedure
Execute ADD_APPOINTMENT stored procedure with #physicianid variable as an input

Related

Stored procedure insert issues - multiple inserts

Can you help me with this stored procedure? My problem is: when I create an account, my stored procedure works perfectly, but when I create a second account in the table evidenta_stundenti_materii, my previous id of account gets doubled.
How many times does it insert when I create an account :
in tbl_utilizatori : once
in tbl_studenti: once
in tbl_evidenta_stundenti: the previous id and the current id are re-inserted when I create the 2nd account
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[insertAnewAccAndANewStudent]
(#email varchar(30),
#parola varchar(30),
#nume varchar(30),
#prenume varchar(30),
#adresa varchar(30),
#nrTelefon varchar(30),
#conectat bit,
#idRol int,
#idSpecializare varchar(30))
AS
BEGIN
INSERT INTO dbo.tbl_utilizatori (email, parola, nume, prenume, adresa, nr_telefon, conectat, id_rol)
VALUES (#email, #parola, #nume, #prenume, #adresa, #nrTelefon, #conectat, #idRol)
IF (#idRol = '1')
BEGIN
DECLARE #id_utilizator int = ##identity
INSERT INTO dbo.tbl_studenti
VALUES (#id_utilizator, #idSpecializare, '0', '1')
END
INSERT INTO dbo.[tbl.evidenta_stundeti_materii] (id_utilizator, id_materie, id_specializare)
SELECT a.id_utilizator, b.id_materie, a.id_specializare
FROM dbo.tbl_studenti a
INNER JOIN dbo.tbl_materii b ON a.id_specializare=b.id_specializare
WHERE a.id_specializare = #idSpecializare
END
Bad English, can provide ss for a better understand problem

When exactly do we use stored procedures with output parameters?

When exactly do we use stored procedures with output parameters and when do we use stored procedures without parameters?
I base my question on an example:
Stored procedure with output parameter
CREATE PROCEDURE uspGetContactsCountByCity
#City nvarchar(60),
#ContactsCount int OUT
AS
BEGIN
SELECT #ContactsCount = COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing
DECLARE #ContactsTotal INT
EXEC uspGetContactsCountByCity #ContactsCount = #ContactsTotal OUT, #city = 'Berlin'
SELECT #ContactsTotal
Results: 2
Stored procedure without output parameter
CREATE PROCEDURE uspGetContactsCountByCity2
#City nvarchar(60)
AS
BEGIN
SELECT COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing:
EXEC uspGetContactsCountByCity2 #city = 'Berlin'
Results: 2
Both procedures return the same result, in same form, so what's the difference?
Basically, the result you're seeing is actually the result of your SELECT at the end of the procedure, which is doing the same thing.
Please take a look at this documentation:
If you specify the OUTPUT keyword for a parameter in the procedure definition, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits. To save the value of the parameter in a variable that can be used in the calling program, the calling program must use the OUTPUT keyword when executing the stored procedure.
So basically if you would like your stored procedure to just return just a value instead of a data set, you could use the output parameter. For example, let's take the procedures you have given as an example. They both do the same thing, this is why you got the same result. But what about changing a little bit in the first procedure that has the output parameter.
Here's an example:
create table OutputParameter (
ParaName varchar(100)
)
insert into OutputParameter values ('one'), ('two'),('three'),('one')
CREATE PROCEDURE AllDataAndCountWhereOne
#name nvarchar(60),
#count int OUT
as
Begin
SELECT #count = COUNT(*) from OutputParameter
Where ParaName = #name
select Distinct(ParaName) from OutputParameter
End
Declare #TotalCount int
Exec AllDataAndCountWhereOne #count = #TotalCount OUT, #name = 'One'
Select #TotalCount
With this example, you are getting all the distinct stored data in the table, plus getting the count of a given name.
ParaName
--------------------
one
three
two
(3 row(s) affected)
-----------
2
(1 row(s) affected)
This is one way of using the output parameter. You got both the distinct data and the count you wanted without doing extra query after getting the initial data set.
At the end, to answer your question:
Both procedures gives us the same result, in same form, so what's the difference?
You didn't make a difference in your own results, this is why you didn't really notice the difference.
Other Examples:
You could use the OUT parameter in other kinds of procedures. Let's assume that your stored procedure doesn't return anything, it's more like a command to the DB, but you still want a kind of message back, or more specifically a value. Take these two examples:
CREATE PROCEDURE InsertDbAndGetLastInsertedId
--This procedure will insert your name in the database, and return as output parameter the last inserted ID.
#name nvarchar(60),
#LastId int OUT
as
Begin
insert into OutputParameterWithId values (#name);
SELECT #LastId = SCOPE_IDENTITY()
End
or:
CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
--This procedure will only insert into the db if name does exist, but there's no more than 5 of it
#name nvarchar(60),
#ErrorMessage varchar(100) OUT
as
Begin
set #ErrorMessage = ''
if ((select count(*) from OutputParameterWithId) = 0)
begin
set #ErrorMessage = 'Name Does Not Exist'
return
end
if ((select count(*) from OutputParameterWithId) = 5)
begin
set #ErrorMessage = 'Already have five'
return
end
insert into OutputParameterWithId values (#name);
End
These are just dummy examples, but just to make the idea more clear.
An example, based on yours would be if you introduced paging to the query.
So the result set is constrained to 10 items, and you use a total count out parameter to drive paging on a grid on screen.
Answer from ozz regarding paging does not make sense because there is no input param that implements a contraint on the number of records returned.
However, to answer the question... the results returned by these stored procedures are not the same. The first returns the record count of contacts in given city in the out param ContactsCount. While the count may also be recieved in the second implement through examining the reader.Rows.Count, the actual records are also made a available. In the first, no records are returned - only the count.

Creating error record when SQL Server udf function returns a certain result

I have been wrecking my brain over this all weekend.
I have a SQL Server UDF to check whether a value passed as an argument will truncate.
CREATE FUNCTION willTruncate
(#fldValue nvarchar(200),
#fldSize smallint,
#fieldname nvarchar(40),
#tbl varchar(15))
RETURNS varchar(200)
AS
BEGIN
declare #Return varchar(200)
declare #fldLen smallint
SET #fldLen = len(#fldValue)
if #fldLen <= #fldSize
SET #Return = #fldValue
else
SET #Return = left(#fldValue,#fldSize-3) + '...'
RETURN #Return
END
The function works correctly to truncate the data the way I need it to when I use it in a SQL query like the sample below:
select top 10
'test' as db,
fname,
dbo.willTruncate(lname, 5, 'Last Name', 'People') as lastname,
dbo.willTruncate(address,40,'Address Line 1', 'People') as addressLine1
from
people
My problem is that I need to report back in some manner about the truncations so the end users can correct the record.
I have a table to populate and have tried to insert a record as part of the else clause, a separate function and a stored procedure. Each time I run the code it fails.
insert into tblTruncationErrors(trunkTable, trunkField, trunkValue)
values(#tbl, #fieldname, #fldValue)
or
CREATE FUNCTION dbo.logTruncation
(#fldValue nvarchar(200), #fieldname nvarchar(40), #tbl varchar(15))
RETURNS varchar(30)
AS
BEGIN
declare #Return int
insert into dbo.truncationErrors(trunkTable, trunkField, trunkValue)
Values (#tbl, #fieldname, #fldValue)
SET #Return = #fieldname
RETURN #Return
END
or
CREATE PROC sp_logTruncation
#tbl varchar(20),
#fldName varchar(30),
#fldValue varchar(200)
AS
SET NOCOUNT ON
insert into dbo.truncationErrors(trunkTable, trunkField, trunkValue)
Values (#tbl, #fldName, #fldValue)
SET NOCOUNT OFF
RETURN 1
GO
Running it as part of the original function code fails saying it needs to be done in a function or stored procedure. If I do it as a function it says I must use a stored procedure. Using it as a stored procedure results in a message saying it can only run from a function.
So, am I writing this wrong? Is there a way to do this. I am not insistent about it going into a table so a Excel or csv file output would be wonderful as well.

SQL Server: how to create a stored procedure

I'm learning sql from a book and I'm trying to write a stored procedure but I don't believe that I'm doing it correctly. Is the following way not valid in Microsoft SQL? If not, when is it valid, if ever?
create procedure dept_count(in dept_name varchar(20), out d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
I get the following error
Msg 156, Level 15, State 1, Procedure wine_change, Line 1
Incorrect syntax near the keyword 'in'.
T-SQL
/*
Stored Procedure GetstudentnameInOutputVariable is modified to collect the
email address of the student with the help of the Alert Keyword
*/
CREATE PROCEDURE GetstudentnameInOutputVariable
(
#studentid INT, --Input parameter , Studentid of the student
#studentname VARCHAR (200) OUT, -- Output parameter to collect the student name
#StudentEmail VARCHAR (200)OUT -- Output Parameter to collect the student email
)
AS
BEGIN
SELECT #studentname= Firstname+' '+Lastname,
#StudentEmail=email FROM tbl_Students WHERE studentid=#studentid
END
In T-SQL stored procedures for input parameters explicit 'in' keyword is not required and for output parameters an explicit 'Output' keyword is required. The query in question can be written as:
CREATE PROCEDURE dept_count
(
-- Add input and output parameters for the stored procedure here
#dept_name varchar(20), --Input parameter
#d_count int OUTPUT -- Output parameter declared with the help of OUTPUT/OUT keyword
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Statements for procedure here
SELECT #d_count = count(*)
from instructor
where instructor.dept_name=#dept_name
END
GO
and to execute above procedure we can write as:
Declare #dept_name varchar(20), -- Declaring the variable to collect the dept_name
#d_count int -- Declaring the variable to collect the d_count
SET #dept_name = 'Test'
Execute dept_count #dept_name,#d_count output
SELECT #d_count -- "Select" Statement is used to show the output
I think it can help you:
CREATE PROCEDURE DEPT_COUNT
(
#DEPT_NAME VARCHAR(20), -- Input parameter
#D_COUNT INT OUTPUT -- Output parameter
-- Remember parameters begin with "#"
)
AS -- You miss this word in your example
BEGIN
SELECT COUNT(*)
INTO #D_COUNT -- Into a Temp Table (prefix "#")
FROM INSTRUCTOR
WHERE INSTRUCTOR.DEPT_NAME = DEPT_COUNT.DEPT_NAME
END
Then, you can call the SP like this way, for example:
DECLARE #COUNTER INT
EXEC DEPT_COUNT 'DeptName', #COUNTER OUTPUT
SELECT #COUNTER
Try this:
create procedure dept_count(#dept_name varchar(20),#d_count int)
begin
set #d_count=(select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name)
Select #d_count as count
end
Or
create procedure dept_count(#dept_name varchar(20))
begin
select count(*)
from instructor
where instructor.dept_name=dept_count.dept_name
end
CREATE PROCEDURE [dbo].[USP_StudentInformation]
#S_Name VARCHAR(50)
,#S_Address VARCHAR(500)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Date VARCHAR(50)
SET #Date = GETDATE()
IF EXISTS (
SELECT *
FROM TB_StdFunction
WHERE S_Name = #S_Name
AND S_Address = #S_Address
)
BEGIN
UPDATE TB_StdFunction
SET S_Name = #S_Name
,S_Address = #S_Address
,ModifiedDate = #Date
WHERE S_Name = #S_Name
AND S_Address = #S_Address
SELECT *
FROM TB_StdFunction
END
ELSE
BEGIN
INSERT INTO TB_StdFunction (
S_Name
,S_Address
,CreatedDate
)
VALUES (
#S_Name
,#S_Address
,#date
)
SELECT *
FROM TB_StdFunction
END
END
Table Name : TB_StdFunction
S_No INT PRIMARY KEY AUTO_INCREMENT
S_Name nvarchar(50)
S_Address nvarchar(500)
CreatedDate nvarchar(50)
ModifiedDate nvarchar(50)
Create this way.
Create procedure dept_count(dept_name varchar(20),d_count integer)
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
try this:
create procedure dept_count( #dept_name varchar(20), #d_count INTEGER out)
AS
begin
select count(*) into d_count
from instructor
where instructor.dept_name=dept_count.dept_name
end
To Create SQL server Store procedure in SQL server management studio
Expand your database
Expand programmatically
Right-click on Stored-procedure and Select "new Stored Procedure"
Now, Write your Store procedure, for example, it can be something like below
USE DatabaseName;
GO
CREATE PROCEDURE ProcedureName
#LastName nvarchar(50),
#FirstName nvarchar(50)
AS
SET NOCOUNT ON;
//Your SQL query here, like
Select FirstName, LastName, Department
FROM HumanResources.vEmployeeDepartmentHistory
WHERE FirstName = #FirstName AND LastName = #LastName
GO
Where, DatabaseName = name of your database
ProcedureName = name of SP
InputValue = your input parameter value (#LastName and #FirstName) and type = parameter type example nvarchar(50) etc.
Source: Stored procedure in sql server (With Example)
To Execute the above stored procedure you can use sample query as below
EXECUTE ProcedureName #FirstName = N'Pilar', #LastName = N'Ackerman';

SQL Insert Procedure

Why isn't my insert procedure returning the ID of the newly inserted row? AND, when calling this procedure, why do I have to supply a value for #EventId? That column is a PK with IDENTITY.
IF OBJECT_ID ( 'vjsql.EventsINSERT', 'P') IS NOT NULL
DROP PROCEDURE EventsINSERT
GO
CREATE PROCEDURE EventsINSERT
#EventId int OUTPUT,
#EventDate datetime,
#Title varchar(100),
#IsActive bit
AS
BEGIN
INSERT INTO EventCalendar ( EventDate, Title, IsActive)
VALUES ( #EventDate, #Title, #IsActive)
SELECT #EventId = SCOPE_IDENTITY()
END
How are you making a call to the stored procedure?
This SP is returning the value of EventID by means of using OUTPUT parameters.
i.e. In programming terms, this is a procedure (not a function) that accepts an OUTPUT parameter which will be set with the value during the execution of the stored procedure.
For this, you will have to pass the variable for #EventID. The value of which will be set within the procedure and you will be able to read the value of it, once the procedure has finished.
See the example code below.
DECLARE #NewEventID INT
EXEC EventsINSERT
#EventId = #NewEventID OUTPUT,
#EventDate = '08/04/09',
#Title = 'Hello World',
#IsActive = 0
SELECT #NewEventID
Try adding some statement terminators:
BEGIN
INSERT INTO EventCalendar ( EventDate, Title, IsActive)
VALUES ( #EventDate, #Title, #IsActive);
SELECT #EventId = SCOPE_IDENTITY();
END
AND, when calling this procedure, why do I have to supply a value for #EventId? That column is a PK with IDENTITY.
You don't, but you do need to supply a variable of type int (or compatible with int) for the output value to be put into.
You don't need to specify a value for the OUTPUT parameter, you need to specify which local variable the output gets put into:
By default, SQL Management Studio names the parameter and the variable the same, which can be confusing. Here's an example of your SP being called:
DECLARE #InsertedEventId int
EXEC [dbo].[EventsINSERT]
#EventId = #InsertedEventId OUTPUT,
#EventDate = N'2009-08-05',
#Title = N'Some event',
#IsActive = 1
-- Display ID as result set
SELECT #InsertedEventId
Just to clarify: your stored procedure is fine. I used it as-is.
Why isn't my insert procedure
returning the ID of the newly inserted
row?
Your code should work. Try in the console instead of
SELECT #EventId = SCOPE_IDENTITY()
doing
SELECT SCOPE_IDENTITY()
and view what happens. Is possible that you are calling it the wrong way. You should store the value of the OUTPUT variable in a variable in the scope where you call this SP.
when calling this procedure, why do I
have to supply a value for #EventId?
Because you have to supply a value for every parameter you have. It doesn't matter if is a real value, it will be discarded, but you must call the stored procedure with a variable in this parameter to catch the returned value.
I'm pretty rusty with tsql, but don't you need to explicitly select ##identity to get that row id? That's where i'd go digging as I think scope_identity() may not return a value in the context of a user function/procedure.

Resources