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!
Related
I have a stored procedure A on server 1 that takes 2 parameters from the user, and then using a linked server (ew), pulls in the results (a table) from server 2.
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date OUTPUT,
#InvToDate date OUTPUT
AS
WITH CTE_Labor AS
(
SELECT blabla
FROM LinkedServer.Database.schema.table
<lots more ctes, etc.>
For performance, I'd like to instead have a stored procedure A still accept the 2 parameters, but then pass them on to stored procedure B that sits on Server 2, and return those results back to the user.
Say - I can put the stored procedure on server 2, and call it from Server 1
DECLARE #return_value int
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = '2022-10-01',
#InvToDate = '2022-10-31'
That works.
But I'm not clear on the syntax to do the above, but have those 2 parameters be entered by the user in stored procedure 1.
Clearly this attempt is wrong:
ALTER PROCEDURE dbo.StoredProc1
#InvFromDate DATE,
#InvToDate DATE
AS
BEGIN
DECLARE #return_value int;
EXEC #return_value = [LinkedServer].[DB].[Schema].[StoredProcB]
#InvFromDate = #InvFromDate,
#InvToDate = #InvToDate;
RETURN #return_value;
END
Edit: Maybe this attempt isn't wrong.
It works when I right click and run the stored procedure, returning both the desired table and Return Value = 0. It just doesn't work when I point our front-end GUI at it. But that might not be a question for here.
Since you are already using a linked server you could utilise this openquery approach Insert results of a stored procedure into a temporary table
Noting the following:
OPENQUERY/ linked servers are generally bad but I'm sure you're all over this
parameter string concatenation is bad
Your wrapper proc has output parameters but I don't see any reason for it... so I've removed them. See if it makes a difference.
--
ALTER PROCEDURE [DW].[StoredProcA]
#InvFromDate date,
#InvToDate date
AS
DECLARE #sql VARCHAR(4000)
SET #sql = 'EXEC [DB].[Schema].[StoredProcB] #InvFromDate = ''' + FORMAT(#InvFromDate + 'yyyy-MM-dd') + ''',#InvToDate = ''' + FORMAT(#InvToDate,'yyy-MM-dd') + ''''
PRINT(#sql) -- for degbugging cause this never works first time
SELECT *
INTO #tmpTable
FROM OPENQUERY([LinkedServer], #SQL)
SELECT * FROM #tmpTable
Got it.
1.) For this method, have to go into the Linked Server, and set [Enable Promotion of Distribution Transaction] = FALSE.
2.) Syntax
Alter proc [dbo].[999_Test]
#InvFromDate date
,#InvToDate date
as
IF OBJECT_ID('tempdb..#tmpbus') IS NOT NULL drop table #tmpbus;
CREATE TABLE #tmpBus
(
Column 1 (datatype),
Column 2 (datatype),
etc. )
INSERT INTO #tmpBus
EXEC [LinkedServer].[DB].Schema.[StoredProcInLinkedServerO]
#InvFromDate,
#InvToDate;
select *
from #tmpBus
GO
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.
Hello I want to concate two things one is string and other is int variable. Now, these thing I want to store in one variable and use that variable in select query as a into type to create a temptable in stored procedure using sql server.
Here is my query
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, I am talking about these line
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID;
In these line two things are concate one is string and other is int. And store in varchar variable.
And use in following select query i.e.
SELECT COUNT(appQueID)/#PerChapQue ChapwiseQue
,CASE WHEN COUNT(appQueID)>=#PerChapQue THEN COUNT(appQueID)/#PerChapQue ELSE 1 END ChapWiseQuePlusOne
,appQueChapID into #tempTable
FROM tblQuestion
WHERE appQueSubID=#SubjectID
GROUP BY appQueChapID
END
Now, in these query I want to create a temptable named #tempTable.
But, in these line it showing error i.e. Incorrect syntax near '#tempTable'.
Confuse that where is the syntax is wrong.
Thank You.
There are a number of things wrong with your code.
When concatenating an int to a string, you must first cast the int to varchar. Otherwise, SQL Server will try to implicitly convert the string to int, that will result with an error.
So this: DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + #UserID; should become this:
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR(11)); (you need 11 chars to be able to fit the minimum value of int: -2,147,483,648)
You can't use select...into with a table variable.
You can only use it for actual tables (temporary or regular).
your #tempTable isn't even a table variable (not that it will help with a select...into).
Even if you would use select...into the correct way, unless you are going to use a global temporary table (and that doesn't come without it's risks), Unless your stored procedure uses this temporary table later on, it will be useless, since temporary tables are bound to scope.
Taking all of that into consideration I'm not sure what output you are actually looking for. If you could edit your question to include the desired output of your stored procedure as well as some sample data as DDL+DML, it would be easier to help you write better code.
Hope this Dynamic Query helps you:
Try like this:
USE [FlightExamSoftware]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- For Storing Question in Temp table
-- EXEC [GetQuestionListPerSubjectRatioWise] 1,11
ALTER PROCEDURE [dbo].[GetQuestionListPerSubjectRatioWise]
#SubjectID INT,
#NumberOfQue INT,
#UserID int
AS
BEGIN
DECLARE #strQuery VARCHAR(MAX);
DECLARE #PerChapQue INT;
DECLARE #tempTable VARCHAR(MAX) = 'tempTestUser' + CAST(#UserID AS VARCHAR);
SELECT #PerChapQue = COUNT(appQueID)/#NumberOfQue FROM tblQuestion WHERE appQueSubID=#SubjectID
SET #strQuery='
SELECT COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ChapwiseQue
,CASE WHEN COUNT(appQueID)>='+CAST(#PerChapQue AS VARCHAR)+' THEN COUNT(appQueID)/'+CAST(#PerChapQue AS VARCHAR)+' ELSE 1 END ChapWiseQuePlusOne
,appQueChapID
INTO '+#tempTable+'
FROM tblQuestion
WHERE appQueSubID='+CAST(#SubjectID AS VARCHAR)+'
GROUP BY appQueChapID
/*.................................
And you have to use the temp table inside the String only
.................................*/
'
EXEC (#strQuery)
END
I have a database with different tables (all the same structure) where I'd like to run a stored procedure having a parameter that defines which table to query.
I can't seem to figure it out:
CREATE SCHEMA test;
GO
First I created a schema
CREATE TYPE DataType as TABLE (
[datetime] [datetime] NULL,
[testVar] [bigint] NULL)
GO
Then I created the table type
USE [TestDataFiles]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [test].[testing]
(
-- Add the parameters for the stored procedure here
#datetime datetime,
#t DataType READONLY
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
select top(10) *
from #t
where [datetime] > #datetime
END
GO
Then I created the stored procedure.
Exec test.testing #t = 'table.1', #datetime = '2017-01-01'
However when I call it I get the following error:
Msg 206, Level 16, State 2, Procedure test, Line 0 [Batch Start Line 0]
Operand type clash: varchar is incompatible with DataType
Same happens with:
Exec test.testing #t = [table.1], #datetime = '2017-01-01'
I have seen an example where in the procedure between the begin and select you put something like:
INSERT INTO table.1
( datetime, testVar)
But table.1 (or table.2 etc as I have a list of tables) has data and I don't want to change it.
Unless I'm meant to create a dummy table like I did the TYPE?
The examples I've found online havent been useful.
To do that you will need to use dynamic SQL
The basic procedure is to build up a string that will hold the statement you will execute, then execute it
declare #SQL nvarchar(1000)
declare #t as nvarchar (1000)
set #t = 'MyTable'
set #Sql = 'Select * from ' + #t
exec sp_executesql #sql
You have to pass parameter of type DataType. So, create variable of that type and pass it into stored procedure like
declare #table1 DataType
INSERT INTO #table1(datetime, testVar) values (..., ...)
Exec test.testing #datetime = '2017-01-01', #t = #table1
Here is my procedure:
CREATE PROCEDURE spDelManu(
#manuName VARCHAR
)
AS BEGIN
SELECT * FROM tbProducts WHERE itemManu = #manuName
END
GO
Here I try executing the procedure, but nothing shows up.
EXEC spDelManu #manuName='EVGA'
But, if I run this query it will work and I get results. Why doesn't it work with the variable created in the proc?
SELECT * FROM tbProducts WHERE itemManu = 'EVGA'
sigh, always declare explcitly the length of your varchar:
CREATE PROCEDURE spDelManu(
#manuName VARCHAR(10)
)
AS BEGIN
SELECT * FROM tbProducts WHERE itemManu = #manuName;
END
As it was, it defaulted to a length of 1
You need to set a size for varchar
CREATE PROCEDURE spDelManu(
#manuName VARCHAR
)
AS BEGIN
select #manuName
END
GO
EXEC spDelManu #manuName='EVGA'
returns: E
Bad habits to kick : declaring VARCHAR without (length) - Aaron Bertrand