I have a stored procedure which contains a null comparison of
--cutting the declaration of various variables
SELECT #val = id FROM dbo.example_table
WHERE type=#type AND date=#date
if #val = null
insert record
When this is executed in the stored procedure with an empty table, this will insert the record, however when this is executed as a block of code outside the stored proc, it will not perform the insert. There are also other SQL servers on which the insert will never be made, whether inside or outside the stored proc.
Is there some explanation for why his can work in some situations but not in others? I know the correct way to perform the comparison is #val IS NULL, but i was curious to to whether #val = null was documented anywhere for completeness.
Check the setting for ANSI_NULLS.
This would return a false:
declare #var varchar(10) = null;
SET ANSI_NULLS ON
if (#var = null) select 'true';
else select 'false';
This would return a true:
declare #var varchar(10) = null;
SET ANSI_NULLS OFF
if (#var = null) select 'true';
else select 'false';
Related
I am sure the solution is something super simple that I am missing but I keep getting a
SqlException: Procedure or function expects parameter which was not supplied
error. I am not a SQL wizard but to me the parameter looks okay. I did change the parameter and was not receiving this error but then when I consistently started receiving it I restored the stored procedure to the original version that I knew for a fact was fine but still receive it.
I tried executing the stored procedure like this
EXECUTE [dbo].[BHS_CloseCnt_Print_PackList] #palletid = '562992'
with a variable filled in. This stored procedure calls a function that determines the status of an order, if the variable I plug in and check with this method meets the criteria for the function I get an expected return.
If the container does not yet meet the function criteria, I get a null which I believe is okay.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[BHS_CloseCnt_Print_PackList]
(#PalletId numeric)
AS
BEGIN
Declare #PO as nvarchar(50)
Declare #Internal_Shipment_Num as numeric
Declare #Internal_Shipment_Line_Num as numeric
select top 1
#Internal_Shipment_Num = sc.INTERNAL_SHIPMENT_NUM,
#Internal_Shipment_Line_Num = sc.INTERNAL_SHIPMENT_LINE_NUM
from
SHIPPING_CONTAINER sc
where
INTERNAL_CONTAINER_NUM = #PalletId
or PARENT = #PalletId
and INTERNAL_SHIPMENT_LINE_NUM is not null
select #PO = dbo.fn_BHS_AllPOPLTS_CLOSED(#PalletId, #Internal_Shipment_Num, #Internal_Shipment_Line_Num)
print #PO
if #PO is not null
Begin
select #PalletId 'INTERNAL_CONTAINER_NUM', '60' 'DOCUMENT_TYPE'
End
End
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[fn_BHS_AllPOPLTS_CLOSED]
(#palletId numeric,
#Internal_Shipment_Num numeric,
#Internal_Shipment_Line_Num numeric)
RETURNS nvarchar(50)
AS
BEGIN
Declare #PO nvarchar(50)
Declare #OPENPO nvarchar(50)
Declare #IntShip as numeric
select #PO = isnull(sd.CUSTOMER_PO, 'FEIT')
from SHIPMENT_DETAIL sd
where sd.INTERNAL_SHIPMENT_LINE_NUM = #Internal_Shipment_Line_Num
and sd.internal_shipment_num = #Internal_Shipment_Num
select #OPENPO = isnull(sd.CUSTOMER_PO, '')
from shipping_container sc
join SHIPMENT_DETAIL sd on sd.INTERNAL_SHIPMENT_LINE_NUM = sc.INTERNAL_SHIPMENT_LINE_NUM
where sd.CUSTOMER_PO = #PO and sc.INTERNAL_SHIPMENT_NUM = #Internal_Shipment_Num
and sc.status < 600
if(isnull(#OPENPO, '') != '')
Begin
set #PO = null
End
return #PO
End
The stored procedure looks to have stored the cache from the previous edit I did although a known working version was restored.
Resolution for this was to run DBCC FREEPROCCACHE to clear the stored procedure cache and I was able to execute as expected.
Thanks Nemanja Perovic!
I need help to create an insert stored procedure with parameters, if pass the value for that parameter, then it has to insert or update in database, else it should use a default of zero.
My problem is that when I execute the code below using a SampleID = 0, it works... any other SampleID does nothing.
Thanks in advance
Execution of the stored procedure:
SET NOCOUNT OFF
EXEC SP_Samples '0', '3' ,'Pink'
GO
Stored procedure code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_Samples]
(#SamplesID int,
#SamplesCategoriesID int,
#SamplesName nvarchar(50)
)
AS
BEGIN
SET NOCOUNT ON;
IF (#SamplesID = 0)
BEGIN
INSERT INTO tblSamples ([SamplesName], [SamplesCategoriesID])
VALUES (#SamplesName, #SamplesCategoriesID)
END
ELSE
BEGIN
UPDATE [tblSamples]
SET SamplesCategoriesID = #SamplesCategoriesID,
SamplesName = #SamplesName
WHERE SamplesID = #SamplesID
END
END
First, you have to learn how to debug a stored procedure.
Just temporarily insert following code into your procedure:
SELECT #SamplesID, #SamplesCategoriesID, #SamplesName;
That is how you will make sure values passed correctly.
Second, for Non-zero cases add following statement:
SELECT COUNT(*) FROM tblSamples WHERE SamplesID = #SamplesID;
That statement should not return zero.
Third, to be 500% sure you are doing it right, pass parameters by name like this:
EXEC SP_Samples #SamplesID = 0, #SamplesCategoriesID = 3, #SamplesName = 'Pink';
GO
EXEC SP_Samples #SamplesID = 1, #SamplesCategoriesID = 4, #SamplesName = 'Blue';
GO
Whilst the below related to a child stored procedure I believe the issue to be something to do with passing a value within the same procedure..
Issue:
I want to return a value from a user defined function I call from stored procedure.
If I hardcode the line
SELECT #SiteImage = ImageName FROM TblImages WHERE SITEID = #SiteIDOriginal to be
SELECT #SiteImage = ImageName FROM TblImages WHERE SITEID = 'HARDCODED_SITE_ID'then it passes back what I want.
I believe I am passing the correct variable though before but need some guidance as to where it 'drops' the value.
In the 'Parent' stored procedure I request:
dbo.GetPropertyImage(UPPER(#SITEID)) as SitePhoto
Then I do as follows and want to return the value #SiteImage to this line, the passback works as I mentioned I've tested this via hard coding.
USE [cording]
GO
/****** Object: UserDefinedFunction [dbo].[GetPropertyImage] Script Date: 05/18/2015 09:17:14 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[GetPropertyImage]
(
-- Add the parameters for the function here
#SiteID varchar(100)
)
RETURNS varchar(100)
AS
BEGIN
-- Declare the return variable here
DECLARE #SiteImage varchar(100)
DECLARE #SiteIDOriginal varchar(100)
-- Add the T-SQL statements to compute the return value here
SELECT #SiteIDOriginal=PemcoShortCode FROM iBasePropertyDetails WHERE PemcoShortCode=#SiteID
SELECT #SiteImage = ImageName FROM TblImages WHERE SITEID = #SiteIDOriginal
--SiteID = #SiteIDOriginal
-- Return the result of the function
RETURN #SiteImage
END
USE [Database]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[GetImage]
(
-- Add the parameters for the function here
#SiteID varchar(100)
)
RETURNS varchar(100)
AS
BEGIN
-- Declare the return variable here
DECLARE #SiteImage varchar(100)
DECLARE #SiteIDOriginal varchar(100)
-- Add the T-SQL statements to compute the return value here
SELECT [#SiteIDOriginal] = ID FROM iBasePropertyDetails WHERE PemcoShortCode=[#SiteID]
SELECT #SiteImage = ImageName FROM TblImages WHERE SITEID = #SiteIDOriginal
-- Return the result of the function
RETURN #SiteImage
END
I'm new to SQL Server. Currently I'm working on an existing source code and I have some unclear point the stored procedure
For examples:
My_Stored_Procedure_1
CREATE PROC [dbo].[My_Stored_Procedure_1]
#ID INT,
#DATE DATETIME
AS
BEGIN
UPDATE query...
PRINT 'ID is ' + CAST(#ID AS VARCHAR(10))
END
My_Stored_Procedure_2
CREATE PROC [dbo].[My_Stored_Procedure_2]
#RESULT INT
AS
BEGIN
EXEC #RESULT = My_Stored_Procedure_1 // Unclear point
END
My question is that, I don't see any return value from the My_Stored_Procedure_1, so what will be returned to #RESULT variable? Maybe a default returned value of the executed stored procedure?
Thank you very much.
#Result will have default value that was passed while executing the Stored Procedure My_Stored_Procedure_2.
The statement EXEC #RESULT = My_Stored_Procedure_1 will execute with error and terminate the execution of My_Stored_Procedure_2 because you have not passing two input parameter to My_Stored_Procedure_1 sp while calling this.
The default value of a stored procedure is dependent on whether or not the statements in that procedure executed successfully. For example, if your UPDATE statement failed due to a constraint error, #RESULT would be set to -6. If it runs successfully with no error, it would normally be 0. See the following:
CREATE TABLE #testTable (Value INT, CHECK (Value > 5));
INSERT #testTable VALUES (6);
GO
CREATE PROCEDURE #testProc AS
UPDATE #testTable SET Value = 2;
GO
DECLARE #ret INT;
EXEC #ret = #testProc;
PRINT #ret; -- “-6”
DROP PROCEDURE #testProc;
DROP TABLE #testTable;
GO
Note that you never make an attempt to observe the value of #RESULT. Since #RESULT is not an OUTPUT parameter, the caller of "dbo"."My_Stored_Procedure_2" will not see the return value of "dbo"."My_Stored_Procedure_1". It looks like you are ignoring the return value. If you could alter your example to show how you are consuming the return value, that can help us understand your question and provide better advice.
Be gentle, I'm a SQL newbie. I have a table named autonumber_settings like this:
Prefix | AutoNumber
SO | 112320
CA | 3542
A whenever a new sales line is created, a stored procedure is called that reads the current autonumber value from the 'SO' row, then increments the number, updates that same row, and return the number back from the stored procedure. The stored procedure is below:
ALTER PROCEDURE [dbo].[GetAutoNumber]
(
#type nvarchar(50) ,
#out nvarchar(50) = '' OUTPUT
)
as
set nocount on
declare #currentvalue nvarchar(50)
declare #prefix nvarchar(10)
if exists (select * from autonumber_settings where lower(autonumber_type) = lower(#type))
begin
select #prefix = isnull(autonumber_prefix,''),#currentvalue=autonumber_currentvalue
from autonumber_settings
where lower(autonumber_type) = lower(#type)
set #currentvalue = #currentvalue + 1
update dbo.autonumber_settings set autonumber_currentvalue = #currentvalue where lower(autonumber_type) = lower(#type)
set #out = cast(#prefix as nvarchar(10)) + cast(#currentvalue as nvarchar(50))
select #out as value
end
else
select '' as value
Now, there is another procedure that accesses the same table that duplicates orders, copying both the header and the lines. On occasion, the duplication results in duplicate line numbers. Here is a piece of that procedure:
BEGIN TRAN
IF exists
(
SELECT *
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
)
BEGIN
SELECT
#prefix = ISNULL(autonumber_prefix,'')
,#current_value=CAST (autonumber_currentvalue AS INTEGER)
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
SET #new_auto_number = #current_value + #number_of_lines
UPDATE dbo.autonumber_settings
SET autonumber_currentvalue = #new_auto_number
WHERE autonumber_type = 'SalesOrderDetail'
END
COMMIT TRAN
Any ideas on why the two procedures don't seem to play well together, occasionally giving the same line numbers created from scratch as lines created by duplication.
This is a race condition or your autonumber assignment. Two executions have the potential to read out the same value before a new one is written back to the database.
The best way to fix this is to use an identity column and let SQL server handle the autonumber assignments.
Barring that you could use sp_getapplock to serialize your access to autonumber_settings.
You could use repeatable read on the selects. That will lock the row and block the other procedure's select until you update the value and commit.
Insert WITH (REPEATABLEREAD,ROWLOCK) after the from clause for each select.