Must declare scalar variable in sql procedure - sql-server

Please what is wrong with the procedure statement below
DECLARE #result int
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
set #result = (select COUNT(*) from populate)
if (#result > 1)
Begin
insert into populate (brch, terminal_id) values(#branch, #atmid)
end
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE insertion #id varchar(50), #brch varchar(50)
-- Add the parameters for the stored procedure here
AS
BEGIN
DECLARE #result int
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
set #result = (COUNT(*) from populate)
if (#result > 1)
Begin
insert into populate (brch, terminal_id) values(#id, #brch)
end
END
GO

It seems that you have confused things by first posting a piece of code that gives the error Msg 137, Level 15, State 2, Line 11 Must declare the scalar variable "#branch". and then later adding a complete procedure that gives the error Msg 156, Level 15, State 1, Procedure insertion, Line 13 Incorrect syntax near the keyword 'from'.
Please make sure that you post the real code you're using and the full error message too, otherwise people cannot help you.
Anyway, I ignored the code snippet and looked only at the procedure and as ABFORCE said, the problem is where you populate #result because your syntax is wrong. This procedure code parses without error in SQL Server 2008:
CREATE PROCEDURE insertion #id varchar(50), #brch varchar(50)
-- Add the parameters for the stored procedure here
AS
BEGIN
DECLARE #result int
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select #result = COUNT(*) from populate
if (#result > 1)
Begin
insert into populate (brch, terminal_id) values(#id, #brch)
end
END
GO
You might want to review the documentation for assigning values to variables and the SET keyword.

The problem, as it is said in the error message is that #branch and #atmid are not mentioned anywhere before their values are used.
You have declared #result and set it's value, so you need to do the same for #branch and #atmid as well, the system cannot divine the values for you.

Try this
select #result =COUNT(*) from populate

Related

Using LIKE with % and Parameter

CREATE PROCEDURE [dbo].[ModuleReferenceCount]
-- Add the parameters for the stored procedure here
#module nvarchar(255)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT COUNT([dbo].[Slots].[ObjectID])
FROM [Slots]
*WHERE [dbo].[Slots].[SlotValue] LIKE CONCAT(%%//, #module, %%)*
END
GO
This is what I have right now. The line in question is line 4 of the code portion, and is between ** (** not there in actual code). I have tried not using CONCAT and using multiple configurations with 'xyz', using = instead of like, etc. I don't think I am grasping the syntax properly, but if possible I want to check for (info)//(userdefined module name)(info) where info can be effectively anything, and (userdefined module name) is my parameter; so something like: abc//module1.xyz or lmn//module22//qrs
Thanks!
CREATE PROCEDURE [dbo].[ModuleReferenceCount]
-- Add the parameters for the stored procedure here
#module nvarchar(255)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
DECLARE #searchtext AS NVARCHAR(255)
SET #searchtext='%'+#module+'%'
SELECT COUNT([dbo].[Slots].[ObjectID])
FROM [Slots]
WHERE [dbo].[Slots].[SlotValue] LIKE #searchtext
END
GO

SQL Server / T-SQL : Raiserror cancels prior inserts

In a procedure, I want to make a test then Raiserror when it's actually the case. But before that, I want to log the error in a table. My code is like this
CREATE PROCEDURE proc
#val VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT OFF;
DECLARE #test VARCHAR(50)
SELECT #test = test
FROM test_table
WHERE ...
IF #test IS NULL
BEGIN
INSERT INTO log_table VALUES (#val);
RAISERROR ('Invalid value : %i', 16, 1, #val);
END
END
The code compiles. When executed with a bad value, the error is raised, but the insert is cancelled.
I tried turning xact_abort and nocount on and off but had no luck.
I tried encapsulating the insert request in BEGIN TRANSACTION/COMMIT but still get the same result.
What I noticed, my log_table which has an auto-increment id, gets incremented even when those inserts are being cancelled.
How can I raise and error but still persist the insert request?
Thanks
Consider using THROW instead:
CREATE TABLE dbo.log_table (val varchar(50));
GO
CREATE PROCEDURE dbo.[proc] #val varchar(50)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT OFF;
DECLARE #test varchar(50); --As i never set this, it'll go into the IF
IF (#test IS NULL)
BEGIN
INSERT INTO log_table
VALUES (#val);
THROW 51000, N'Invalid value.', 1;
END;
END;
GO
EXEC dbo.[proc] #val = 'Some Value';
GO
SELECT *
FROM dbo.log_table;
GO
DROP PROC dbo.[proc];
DROP TABLE dbo.log_table;
DB<>Fiddle
In order to write to a log table you have to rollback any pending transaction. Otherwise your log table INSERT may be rolled back by the calling code, or may fail because the transaction is doomed.
So something like:
CREATE Procedure myproc
#val varchar(50)
as
begin
set nocount on
set xact_abort on
begin transaction;
begin try
-- do stuff
commit transaction;
end try
begin catch
if ##trancount > 0 rollback;
declare #error_message varchar(max) = error_message()
INSERT INTO log_table values (#val);
throw;
end catch
end
So apparently, my procedure was working as expected in SQLServer side. The problem was that I was calling this procedure from Java/Spring native query method and had to be annotated with #Modifying and #Transactional since it's doing insertions. Thus when an exception is caught, it was automatically rolled back.
I didn't find a quick solution to bypass Spring's transaction. Now I think all I have to do is, catch the exception in App layer and log to the log_table in app layer too

Need a stored procedure that inserts a row and returns the ID

I tried to write a stored procedure that first inserts a new record into table and then returned the id of this new record. I am not sure if it is the correct way and the best way to achieve this.
ALTER PROCEDURE dbo.spAddAsset
(
#Name VARCHAR(500),
#URL VARCHAR(2000)
)
AS
BEGIN
Set NOCOUNT on;
Insert Into Assets (Name, URL) Values (#Name, #URL)
Declare #new_identity int;
SELECT #new_identity = SCOPE_IDENTITY()
return #new_identity;
END
To return a single scalar value to the caller you should use an OUTPUT parameter, not RETURN. RETURN is for error/status codes. Also the prefix sp is redundant and unnecessary.
CREATE PROCEDURE dbo.AddAsset
#Name VARCHAR(500),
#URL VARCHAR(2000),
#new_identity INT = NULL OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Assets(Name, URL) SELECT #Name, #URL;
SET #new_identity = SCOPE_IDENTITY();
END
GO
Then to call it:
DECLARE #new_identity INT;
EXEC dbo.AddAsset #Name = 'a', #URL = 'b', #new_identity = #new_identity OUTPUT;
PRINT #new_identity;
EDIT just adding a disclaimer that won't affect the asker in this specific scenario, but may help in other scenarios or for future readers. In SQL Server 2008 R2 and earlier, there is a potentially nasty bug with built-in functions such as SCOPE_IDENTITY when parallelism is used to derive the results to be inserted (think INSERT FROM othertable). This bug (here is the Connect item) is fixed in Cumulative Update #5 for SQL Server 2008 R2 SP1, but so far a fix has not appeared for 2008 R2 RTM, 2008 or 2005.
I can't see why it is necessary to place the returned row value into a new variable #new_identity. I would simply include SELECT SCOPE_IDENTITY(); at the end of the stored procedure like this:
CREATE PROCEDURE dbo.AddAsset
#Name VARCHAR(500),
#URL VARCHAR(2000)
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.Assets(Name, URL) SELECT #Name, #URL;
SELECT SCOPE_IDENTITY();
END
GO

What is wrong with this simple SQL? Fails when put in a stored procedure works otherwise

When I ran as is, it works perfectly fine but putting this exact code into a stored procedure in SQL 2005 fails.
I get this error
Msg 102, Level 15, State 1, Procedure GetCurrentLoadDate, Line 23.
Incorrect syntax near '#vardate'.
What is wrong with this call that it can work as a declaration and return the result set but fail if put in stored procedures?
declare #date datetime
declare #vardate varchar(10)
set #date = getDate()
set #vardate = CONVERT(varchar(10), #date ,101)
select tableloaded, insertdatetime, sourcesystemdatetime, FriendlyDescription
from dbo.tbl_loadSourcedates_dttm
where CONVERT(varchar(10), insertdatetime, 101) = #vardate
Thanks
Dhiren
You are probably missing the END at the end of the stored proc definition that you neglected to show us. I get the same error If I append
create proc foo
as
begin
to the beginning of your posted code.
Do you have exactly this?
CREATE PROCEDURE GetCurrentLoadDate
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #date datetime
declare #vardate varchar(10)
set #date=getDate()
set #vardate=CONVERT(varchar(10), #date ,101)
select tableloaded,insertdatetime,sourcesystemdatetime,FriendlyDescription
from dbo.tbl_loadSourcedates_dttm
where CONVERT(varchar(10), insertdatetime ,101)=#vardate
END
GO
Because it looks to me that you are missing something when you declare your proc since you are getting a syntax exception on the very first line.

SQL Server - Stored Procedure Question

For the application I work on... we're creating a custom logging system. The user can view logs and apply "Tags" to them (Just like how you can apply tags to questions here!)
In this example, I'm trying to get a list of all the Logs given a "Tag." I realize I can accomplish this by using joins... but this is also an exercise for me to learn Stored Procedures a little better :)
I have a stored procedure that looks something like this to select a log by the PK
ALTER PROCEDURE [dbo].[getLogByLogId]
-- Add the parameters for the stored procedure here
#ID int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT TOP 1
LOG_ID,
a.A,
a.B,
a.C
FROM dbo.LOG a
WHERE a.LOG_ID = #ID
Now I would like to call this Stored Procedure from another... something like this
ALTER PROCEDURE [dbo].[getLogsByTagName]
-- Add the parameters for the stored procedure here
#TAG nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT TOP 1000
LOG_ID --somehow store this and execute the dbo.getLogByLogId procedure here
FROM dbo.LOG_TAG a
WHERE a.TAG = #TAG
Thanks
If you have complex logic in your logbyid SP which you are trying to avoid reproducing in multiple places in your system (choice of columns, derived columns, etc), I would recommend turning that into an inline table-valued function instead (potentially without taking the ID parameter, in which case, you can actually use an ordinary view).
Then you can either join to that ITVF/view in your other stored proc (or also make another udf) which does the search or use the OUTER APPLY functionality (not as efficient).
Inline table-valued functions are basically parameterized views and can be optimized fairly easily by the optimizer.
If you want to call another sproc from within a sproc just use:
CREATE PROCEDURE myTestProc
AS
BEGIN
--Do some work in this procedure
SELECT blah FROM foo
--now call another sproc
EXEC nameOfSecondSproc
END
The only way you can achive what you are attempting is by using a CURSOR.
If this is for your learning only, then by all means, give this a go, but I would not recomend this for production.
It would go something like this
DECLARE #Table TABLE(
ID INT
)
INSERT INTO #Table SELECT 1
INSERT INTO #Table SELECT 2
INSERT INTO #Table SELECT 3
INSERT INTO #Table SELECT 4
INSERT INTO #Table SELECT 5
INSERT INTO #Table SELECT 6
DECLARE Cur CURSOR FOR
SELECT ID
FROM #Table
OPEN Cur
DECLARE #ID INT
FETCH NEXT FROM Cur INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #ID
FETCH NEXT FROM Cur INTO #ID
END
CLOSE Cur
DEALLOCATE Cur
By using the #ID retrieved in the WHILE loop, you can then execute the sp you wish and insert the values into a table variable.
INSERT INTO #Table EXEC sp_MySP #ID
You can call a stored procedure from another using the following syntax:
ALTER PROCEDURE [dbo].[getLogsByTagName]
-- Add the parameters for the stored procedure here
#TAG nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT TOP 1000
LOG_ID --somehow store this and execute the dbo.getLogByLogId procedure here
FROM dbo.LOG_TAG a
WHERE a.TAG = #TAG
-- Execute dbo.getLogByLogId stored procedure
DECLARE #logId INTEGER
SET #logId = <some value>
EXEC dbo.getLogByLogId #logId
END
However, the difficult part of your question is that your dbo.getLogByLogId procedure can only accept a single LogID parameter and therefore will only be able to return a single Log record. You need to return information for all Logs where the LogId has a corresponding record in the Tags table.
The correct way to do this would be to JOIN the Log and Tag tables together, like so:
SELECT *
FROM dbo.LOG_TAG a
INNER JOIN dbo.LOG b ON a.LOG_ID = b.LOG_ID
WHERE a.TAG = #TAG
If you are concerned about returning the same logId multiple times, you can use the DISTINCT keyword in the SELECT statement to filter out the duplicated logIds.
You may also be able to rewrite your dbo.getLogByLogId procedure as a user-defined function (UDF). UDFs can accept a table as a parameter and return a table result.
An introduction to user-defined functions can be found in this article.

Resources