How to use DECLARE in a stored procedure - sql

I am creating a stored procedure that will create a new row in a table once the record is new and update the existing record if the record is present in the table.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [procedurename]
(#UserName [varchar](50),
#UserEmail [varchar](50),
#Role [varchar](30),
#Status [varchar](30),
#CreationDate [Date])
AS
DECLARE #countRec INT
SELECT #countRec = COUNT(*)
FROM [Synapse].[tablename]
WHERE [UserName] = #Username
BEGIN
IF (#countRec = 0)
BEGIN
INSERT INTO [Synapse].[tablename] ([UserName], [UserEmail], [Role], [Status], [CreationDate])
VALUES (#Username, #UserEmail, #Role, #Status, #CreationDate)
END
ELSE (#countRec > 0)
BEGIN
UPDATE [Synapse].[tablename]
SET [Role] = #Role,
[Status] = #Status,
[CreationDate] = #CreationDate
WHERE [UserName] = #Username
INSERT INTO [Synapse].[tablename]
END
And I am getting the following error:
Msg 103010, Level 16, State 1, Line 8
Parse error at line: 39, column: 7: Incorrect syntax near '#countRec'.
I am not sure why it is pointing at the countRec variable. I was able to use a similar set-up without any issues. Does anyone know what I am doing wrong here?
Kind regards,
Rutger

You have a number of syntax errors - mostly: you need to start your proedure with a BEGIN before doing any declarations or selects - and you're missing an END at the end.
Try this:
CREATE PROCEDURE [procedurename]
(#UserName [varchar](50),
#UserEmail [varchar](50),
#Role [varchar](30),
#Status [varchar](30),
#CreationDate [Date])
AS
BEGIN -- put the "BEGIN" before you start declaring and selecting stuff
DECLARE #countRec INT
SELECT #countRec = COUNT(*)
FROM [Synapse].[tablename]
WHERE [UserName] = #Username
IF (#countRec = 0)
BEGIN
INSERT INTO [Synapse].[tablename] ([UserName], [UserEmail], [Role], [Status], [CreationDate])
VALUES (#Username, #UserEmail, #Role, #Status, #CreationDate)
END
-- either you have just an "ELSE" here - or if you want to
-- check another conditions, you need to use "ELSE IF ....."
ELSE IF (#countRec > 0)
BEGIN
UPDATE [Synapse].[tablename]
SET [Role] = #Role,
[Status] = #Status,
[CreationDate] = #CreationDate
WHERE [UserName] = #Username
END
END -- this was missing

Related

execute stored procedure with a loop and combine results

I have a stored procedure in SQL server 2008.
This stored procedure (lets call it sp1), accepts ID (string),FromDate,ToDate and returns col1,col2,col3
I tried to alter sp1 to accept IDList (ID1,ID2,...,IDn), but it is way over my head.
I need help with creating a new SP (lets call it SP2) that accepts IDList,FromDate,ToDate , and then loops with the id list and calls SP1 and union the results.
I hope I am clear...
This is the original SP, If you can make it accept UnitIMEIList it will also be great:
CREATE PROCEDURE [dbo].[GetGeneratorsReport]
#UnitIMEI varchar(15),
#DateFrom [datetime],
#DateTo [datetime]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #mycur CURSOR
DECLARE #GeneratorId int
DECLARE #FieldId int
DECLARE #SensorName nvarchar(50)
DECLARE #StateNO bit
DECLARE #ReadingDate [datetime]
DECLARE #Value bit
DECLARE #FirstRun bit
DECLARE #SDate [datetime]
DECLARE #UnitName nvarchar(50)
--SET #UnitIMEI='358484004085845'
SET #UnitName = (SELECT TOP 1 NickName FROM Vehicles WHERE UnitIEMI = #UnitIMEI)
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE ID = OBJECT_ID(N'tempdb..#GeneratorsTempTable')) BEGIN DROP TABLE #GeneratorsTempTable END
CREATE TABLE #GeneratorsTempTable (
SensorId int,
UnitIMEI varchar(15),
UnitName nvarchar(50),
SensorName nvarchar(50),
FromDate [datetime],
ToDate [datetime]
)
SET #mycur = CURSOR
FOR
SELECT 104+[GPIO], [Name], [StateNO]
FROM [VehicleTrack].[dbo].[UnitSensors]
WHERE [UnitIMEI]=#UnitIMEI AND Type=3
OPEN #mycur
FETCH NEXT FROM #mycur INTO #FieldId, #SensorName, #StateNO
WHILE ##FETCH_STATUS = 0
BEGIN
SET #FirstRun = 1
SET #SDate = NULL
DECLARE messageCur CURSOR
FOR
SELECT ProtocolMessages.Date, convert(bit, AdditionalReadings.Value) AS Value
FROM ProtocolMessages INNER JOIN
AdditionalReadings ON ProtocolMessages.Id = AdditionalReadings.MessageId
WHERE (ProtocolMessages.UnitIEMI = #UnitIMEI) AND AdditionalReadings.FieldId = #FieldId AND ProtocolMessages.Date >= #DateFrom AND ProtocolMessages.Date <= #DateTo
ORDER BY ProtocolMessages.Date
OPEN messageCur
FETCH NEXT FROM messageCur INTO #ReadingDate, #Value
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#Value > 1)
SET #Value = #Value - 2
IF (#FirstRun = 1 AND #SDate IS NULL)
BEGIN -- the first run
SET #FirstRun = 0 -- flip the bit for all future runs
IF (#Value = #StateNO)
SET #SDate = #ReadingDate
END
ELSE -- all subsequent runs after the first
BEGIN
IF (#SDate IS NULL)
BEGIN
IF (#Value = #StateNO)
SET #SDate = #ReadingDate
END
ELSE
BEGIN
IF (#Value <> #StateNO)
BEGIN
-- Store
INSERT INTO #GeneratorsTempTable ([SensorId], [UnitIMEI], [UnitName], [SensorName] , [FromDate], [ToDate]) VALUES (#FieldId - 104, #UnitIMEI, #UnitName, #SensorName, #SDate, #ReadingDate)
SET #SDate = NULL
END
END
END
FETCH NEXT FROM messageCur INTO #ReadingDate, #Value
END
CLOSE messageCur
DEALLOCATE messageCur
IF (#Value = #StateNO)
BEGIN
INSERT INTO #GeneratorsTempTable ([SensorId], [UnitIMEI], [UnitName], [SensorName] , [FromDate], [ToDate]) VALUES (#FieldId - 104, #UnitIMEI, #UnitName, #SensorName, #SDate, GETUTCDATE())
END
FETCH NEXT FROM #mycur INTO #FieldId, #SensorName, #StateNO
END
DEALLOCATE #mycur
SELECT * FROM #GeneratorsTempTable
END
GO
Thanks
For the benefit of other google users :)
I did it all by myself !
I created a database named 'SandBox' for that.
Create a sample table :
USE [SandBox]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[tblStudentGrades](
[StudentGradeID] [bigint] IDENTITY(1,1) NOT NULL,
[StudentID] [bigint] NOT NULL,
[TestID] [bigint] NOT NULL,
[TestDate] [date] NOT NULL,
[TestGrade] [int] NULL
) ON [PRIMARY]
GO
Put some data (If you are lazy:) ) :
USE [SandBox]
GO
SET IDENTITY_INSERT [dbo].[tblStudentGrades] ON
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (1, 1, 1, CAST(0x6E390B00 AS Date), 60)
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (2, 1, 2, CAST(0x70390B00 AS Date), 80)
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (3, 2, 1, CAST(0x6E390B00 AS Date), 90)
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (4, 2, 2, CAST(0x70390B00 AS Date), 100)
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (5, 3, 1, CAST(0x6E390B00 AS Date), 95)
INSERT [dbo].[tblStudentGrades] ([StudentGradeID], [StudentID], [TestID], [TestDate], [TestGrade]) VALUES (6, 3, 2, CAST(0x0F230100 AS Date), 98)
SET IDENTITY_INSERT [dbo].[tblStudentGrades] OFF
Create the SP that accepts a single id:
* This is just a sample ... don't forget it - I know I can send multiple IDs as a parameter...
USE [SandBox]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spGetStudentGrades]
#StudentID bigint
AS
BEGIN
SELECT * FROM [SandBox].[dbo].[tblStudentGrades]
WHERE StudentID = #StudentID;
END
GO
Now for the new SP that will allow multiple execution of the above SP (exactly what I was looking for):
USE [SandBox]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spGetMultiple]
#StudentIDList varchar(100)
AS
BEGIN
DECLARE #StudentID VARCHAR(10)
--------------------------------------------------
-- Create a temporary table to hold the results:
--------------------------------------------------
IF EXISTS (SELECT * FROM tempdb.dbo.sysobjects WHERE ID = OBJECT_ID(N'tempdb..#tblTemporaryGrades')) BEGIN DROP TABLE #tblTemporaryGrades END
CREATE TABLE #tblTemporaryGrades (
StudentGradeID bigint,
StudentID bigint,
TestID bigint,
TestDate date,
TestGrade int
)
--------------------------------------------------
-- Add a comma to the end of the ID list,
-- so the last ID will be also included.
SET #StudentIDList = #StudentIDList + ',' ;
---------------------------------------------------
WHILE CHARINDEX(',', #StudentIDList) > 0
BEGIN
-- STEP 1 :
-- Extract the current StudentID we want to get from the original SP
SET #StudentID = SUBSTRING(#StudentIDList, 1, ( CHARINDEX(',', #StudentIDList) - 1 ))
PRINT '#StudentID = ' + #StudentID;
-- STEP 2 :
-- Gather the data using the original SP
INSERT INTO #tblTemporaryGrades EXEC spGetStudentGrades #StudentID
-- STEP 3 :
-- Update the student ID to exclude the last StudentID we worked with
SET #StudentIDList = SUBSTRING(#StudentIDList, CHARINDEX(',', #StudentIDList) + 1, LEN(#StudentIDList))
PRINT 'NEW #StudentIDList = ' + #StudentIDList;
END
SELECT * FROM #tblTemporaryGrades
END
GO
Feel like testing it ?
Go ahead:
USE [SandBox]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[spGetMultiple]
#StudentIDList = N'3,2,1'
SELECT 'Return Value' = #return_value
GO
Good luck all !

Stored procedure help required

I am running this stored procedure and I need it to return a string value of
Success
or
Failed
But the following procedure is missing something, not sure what?
ALTER PROCEDURE [dbo].[sp_Log_Audit]
(
#username varchar(254) = NULL,
#password varchar(254) = NULL,
#User_ID int = NULL,
#Method varchar(10) = NULL,
#Result varchar(10) = Failed
)
AS
SET NOCOUNT ON;
INSERT INTO dbo.[A_Logins]([Username], [Password], [User_ID], [Method], [Result])
VALUES(#userName, #Password, #User_ID, #Method, #Result)
SET NOCOUNT OFF;
RETURN
It should return #Result as it will be having a Success or Failed message
I think you haven't return any value, can you try this at the place of where you wrote return?
SELECT #Result As ReturnVal

SQL Stored Procedure to Check if exists then add. If not to update

I'm trying to write a stored procedure to populate a user table (Named CSLL.Users)
The procedure is given a series of user details when triggered.
It then checks to see if the Alias exists in the table. If not it adds the alias. The sp then goes on to populate the rest of the columns (using the update command)
It is called using vba, but is throwing an error when it is called. I think it is with the first IF NOT EXISTS statement but can't see where I'd possibly going wrong.
ALTER procedure [CSLL].[UploadUser]
-- Add the parameters for the stored procedure here
#Name varchar(max) = NULL,
#FirstName varchar(max) = NULL,
#LastName varchar(max) = NULL,
#Email varchar(max) = NULL,
#Telephone varchar(max) = NULL,
#Division varchar(max) = NULL,
#Manager varchar(max) = NULL,
#DirectReports varchar(max) = NULL,
#Title varchar(max) = NULL
AS
SET NOCOUNT ON
IF NOT EXISTS(SELECT 1 FROM [CSLL].[Users] Where [Alias] = #Name) INSERT INTO [CSLL.Users] ([Alias], [Country], [Role]) VALUES (#Name, 'UK', 'Employee')
UPDATE [CSLL].[Users]
SET FirstName = #FirstName,
LastName = #LastName,
Email = #Email,
Telephone = #Telephone,
Division = #Division,
Manager = #Manager,
DirectReports = #DirectReports,
Title = #Title
WHERE Alias = #Name
DECLARE #Pos int
DECLARE #DR varchar(max)
SET #DirectReports = #DirectReports + ','
WHILE LEN(#DirectReports) > 0
BEGIN
SET #Pos = CHARINDEX(',', #DirectReports, 1)
SET #DR = (CASE #Pos
WHEN 0 THEN RTRIM(LTRIM(#DirectReports))
ELSE RTRIM(LTRIM(LEFT(#DirectReports, #Pos - 1)))
END)
IF NOT EXISTS(SELECT 1 FROM [CSLL].[Users] where [Alias] = #DR) INSERT INTO [CSLL].[Users] ([Alias], [Country], [Role]) VALUES (#DR, 'UK', 'Employee')
SET #DirectReports = RIGHT(#DirectReports, LEN(#DirectReports) - #Pos)
END
This seems to be caused by a typo:
-- you currently use: [CSLL.Users]
IF NOT EXISTS(SELECT 1 FROM [CSLL].[Users] WHERE [Alias] = #Name)
INSERT INTO [CSLL.Users] ([Alias], [Country], [Role])
VALUES (#Name, 'UK', 'Employee')
Instead try:
-- use: [CSLL].[Users]
IF NOT EXISTS(SELECT 1 FROM [CSLL].[Users] Where [Alias] = #Name)
INSERT INTO [CSLL].[Users] ([Alias], [Country], [Role])
VALUES (#Name, 'UK', 'Employee')

Procedure or function has too many arguments SQL server

I getting this error while executing the stored procedure in SQL Server:
Msg 8144, Level 16, State 2, Procedure sp_adduser, Line 2
Procedure or function sp_adduser has too many arguments specified.
The weird thing is that the number of parameters is the same as declared in the procedure, even when I execute it while right-click on the procedure and press execute, input the parameters from the fields and still the same error.
This is the code of the procedure and the exec:
create procedure [dbo].[sp_addUser]
(
#userID nvarchar(50),
#pw nvarchar(50),
#fName nvarchar(50),
#lname nvarchar(50),
#email nvarchar(150),
#address nvarchar(150),
#city int,
#country int,
#phone nvarchar(50),
#gender nvarchar(10),
#dob date,
#photo nvarchar(150),
#secq int,
#secAnswer nvarchar(150),
#completed int output)
as
declare #found int
/*
usertype:
0 - Administrator
1 - User
*/
begin
begin
select #found=count(*) from registration r
where REPLACE(r.firstname,' ','')=REPLACE(#fName,' ','')
and REPLACE(r.lastname,' ','')=REPLACE(#lname,' ','')
and r.dateofbirth=#dob;
end
begin
if #found=0
begin
begin
insert into Login values(#userID,#pw,0,1);
end
begin
insert into registration values(
#userID,#fName,#lname,#email,
#address,#city,#country,#phone,
#gender,#dob,#photo,#secq,#secAnswer
)
end
begin
set #completed=1;
end
end
else set #completed=0
end
return #completed
end
And here is the exec:
DECLARE #return_value int,
#completed int
SELECT #completed = 0
EXEC #return_value = [dbo].[sp_addUser]
#userID = N'a',
#pw = N'a',
#fName = N'a',
#lname = N'a',
#email = N'a',
#address = N'a',
#city = 1,
#country = 1,
#phone = N'a',
#gender = N'a',
#dob = '01/01/2000',
#photo = N'a',
#secq = 1,
#secAnswer = N'a',
#completed = #completed OUTPUT
SELECT #completed as N'#completed'
SELECT 'Return Value' = #return_value
Thanks in advance!
sp_adduser is a procedure which is built-in to SQL Server - see https://msdn.microsoft.com/en-us/library/ms181422.aspx
Don't use the sp_ prefix for your own stored procedures, maybe call it proc_adduser instead, I think that will work
You are actually calling the system stored procedure sp_adduser. The "sp_" prefix is special and has its own rules on resolution, so using it is recommended against. If you want to use your own prefix, whatever you do, don't use "sp_".
Per #marc_s, even if your stored procedure doesn't clash with an existing system stored procedure, you will still get a noticeable performance hit due to cache misses.

Returning a string after inserting data into SQL through a stored procedure

I'm new to SQL and my first time to create a stored procedure.
I was supposed to insert data and get a return string. The return value should be Successfully inserted or if failed, should notify me if a username already exists.. or something like that however
I'm stuck in codes for error:
So here is my code..
Create Proc Mock_InsertUser
(
#Username varchar(20),
#Password varchar(100),
#fullName varchar(60),
#Activated bit,
#Suspended bit
)
as
Begin
DECLARE
#Error INT,
#rowcount INT,
#log varchar(1000)
IF EXISTS(SELECT username FROM Users_mock WHERE username = #Username)
BEGIN
SET #log = 'Username ' + #Username + ' already exists.'
GOTO ERROR
END
Insert into Users_mock
(username, [password], full_name, Activated, Suspended)
values
(#Username, #Password, #fullName, #Activated, #Suspended)
SELECT #Error = ##ERROR, #rowcount = ##ROWCOUNT
--if there is an error OR If row is not inserted..
IF #Error <> 0 OR #rowcount < 1
BEGIN
SET #log = 'Failed to Insert Account.'
GOTO ERROR
END
-----------------------------------------------------------
Error:
--Some code here
END
Sorry for lousy question :)
Why don't you use something like this:
CREATE PROCEDURE dbo.Mock_InsertUser
(#Username VARCHAR(20),
#Password VARCHAR(100),
#fullName VARCHAR(60),
#Activated BIT,
#Suspended BIT )
AS
BEGIN
BEGIN TRY
DECLARE #Error INT, #rowcount INT, #log VARCHAR(1000)
-- check if user exists
IF EXISTS (SELECT * FROM dbo.Users_mock WHERE username = #Username)
BEGIN
-- yes - just define the response message
SET #log = 'Username ' + #Username + ' already exists.'
END
ELSE BEGIN
-- doesn't exist - insert data
INSERT INTO
dbo.Users_mock(username, [password], full_name, Activated, Suspended)
VALUES
(#Username, #Password, #fullName, #Activated, #Suspended)
-- set response message
SET #log = 'Username ' + #Username + ' successfully inserted.'
END
END TRY
BEGIN CATCH
-- handle exceptions - you can access error details here, too, if you need to
SET #log = 'Some really weird error happened.'
END CATCH
-- return the message back to the caller
SELECT #Log
END
Points to see:
use BEGIN TRY/END TRY - BEGIN CATCH/END CATCH like in C# to handle exceptions - no need to constantly check for ##ERROR values ....
basically just check for existence of the user - set the #Log message accordingly. If user doesn't exist, insert it and set #Log message to "success"
no need for label, GOTO and other stuff like that....
use the ELSE keyword:
IF EXISTS(SELECT username FROM Users_mock WHERE username = #Username)
BEGIN
SET #log = 'Username ' + #Username + ' already exists.'
SELECT #log --this end the stored procedure. it is like the return keyword.
END
ELSE
BEGIN
Insert into Users_mock
(username, [password], full_name, Activated, Suspended)
values
(#Username, #Password, #fullName, #Activated, #Suspended)
DECLARE #Error = ##ERROR
DECLARE #rowcount = ##ROWCOUNT
--if there is an error OR If row is not inserted..
IF #Error <> 0 OR #rowcount < 1
BEGIN
SET #log = 'Failed to Insert Account.'
SELECT #log
END
END