SqlParameter calling a user defined function in an Insert Query - prepared-statement

Im trying to execute a scalar valued function in an insert query. Im using sql parameter collection but still stuck with it.
Query
Insert into PackageProducts values (#id, #name, #prodId, #prodCode)
// I want to call a scalar valued function to get value for the #prodCode when this query excecutes
Function
create function getProdCodeById(#id uniqueidentifier) returns varchar(15)
begin
declare #code varchar(15)
select #code=ProductCode from Products where ID=#id
return #code
end
What I'm trying to do
//create command, connection etc.. after than
DbParameter param = createParameter() ; // returns an empty parameter
param.Name = "#prodCode";
param.Value = String.Format("getProdCodeById('{0}')", 5);
when I execute , it takes the parameter value as a string.. the function never gets executed. Can you tell me what am I doing wrong here ?

Use a select statement for your function
SELECT [dbo].[getProdCodeById] (#id)
You can assign this to a variable before using it, as in
DECLARE #parameter varchar(15)
SET #parameter = (SELECT [dbo].[getProdCodeById] (#id))
You can now use #parameter anywhere in your code

Related

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.

Run A Loop in SQL Server

I want to run a stored procedure on each ID return by a SELECT query. Is there a simple way to do something like:
FOREACH (SELECT ID FROM myTABLE WHERE myName='bob') AS id
BEGIN
EXEC #return_value = [dbo].[spMYPROC]
#PARAM1 = id
#PARAM2 = 0
END
Since I just happened to answer a very similar question yesterday, I have this code handy. As others have stated, it may not be the best approach, but still it's nice to learn how to use a while loop anyway.
Assuming a table named "Customer"
declare #Id int
select #Id = MIN(Id)
from Customer c
while(select COUNT(1)
from Customer c
where c.Id >= #Id) > 0
begin
--run your sproc right here
select #Id = MIN(Id)
from Customer c
where c.Id > #Id
end
DECLARE #ID INT, #return_value INT
DECLARE c CURSOR FOR
SELECT
ID
FROM myTABLE
WHERE myName = 'bob'
OPEN c; FETCH NEXT FROM c INTO #ID
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC #return_value = [dbo].[spMYPROC]
#PARAM1 = #ID,
#PARAM2 = 0
FETCH NEXT FROM c INTO #ID
END
CLOSE c; DEALLOCATE c;
You have two option here
Option 1 Using Split Function
Pass a comma deliminated list of IDs and use a Split function Inside your Procedure to make split these values and do whatever you want to do with it.
To
Make it work you will need two thing
1) Create a Function which
accepts a Comma Deliminated string and split them.
2) Modify you
Store Procedure and add this function in there in a way that passed
parameter is passed to the function inside that store procedure and
that function split the values before passing it onto your store
Procedure .
Create this function 1st
Function Definition
CREATE FUNCTION [dbo].[FnSplit]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table (Id int identity(1,1), Value nvarchar(100))
AS
BEGIN
WHILE(Charindex(#SplitOn,#List)>0)
BEGIN
INSERT INTO #RtnValue (value)
SELECT VALUE = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
SET #List = SUBSTRING(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
END
INSERT INTO #RtnValue (Value)
SELECT VALUE = ltrim(rtrim(#List))
RETURN
END
Modify you strored Procedure something like this
Stored Procedure
ALTER Procedure [dbo].[spMYPROC] (#Param1 VARCHAR(1000)= NULL)
AS
BEGIN
SELECT * FROM TableName
where ColumnNAME IN (SELECT Value FROM dbo.FnSplit(#Param1,','))
END
GO
Option 2 Table Type Parameter
Create a Table Type and alter your proc to accept a Table Type Parameter and do whatever you want to do with them values inside your proc.
TABLE TYPE
CREATE TYPE dbo.TYPENAME AS TABLE
(
Value int
)
GO
Stored Procedure to Accept That Type Param
ALTER PROCEDURE [dbo].[spMYPROC]
#TableParam TYPENAME READONLY
AS
BEGIN
SET NOCOUNT ON;
--Temp table to store passed Id values
declare #tmp_values table (value INT );
--Insert passed values to a table variable inside the proc
INSERT INTO #tmp_values (value)
SELECT Value FROM #TableParam
/* Do your stuff here whatever you want to do with Ids */
END
EXECUTE PROC
Declare a variable of that type and populate it with your values.
DECLARE #Table TYPENAME --<-- Variable of this TYPE
INSERT INTO #Table --<-- Populating the variable
SELECT ID FROM myTABLE WHERE myName='bob'
EXECUTE [dbo].[spMYPROC] #Table --<-- Stored Procedure Executed

Multiple variables in SQL Server stored procedure

I'm stuck on assigned variable values in this stored procedure.
#EntityID int,
#Title1 varchar(10) OUTPUT,
#Title2 varchar(10) OUTPUT
AS
Declare #T1 varchar(10)
Declare #T2 varchar(10)
BEGIN
SELECT
dbo.Entity.EntityID, dbo.Types.TypeName AS Title1, Types_1.TypeName AS Title2
FROM
dbo.Entity
LEFT OUTER JOIN
dbo.Types AS Types_1 ON dbo.Entity.Title2 = Types_1.TypeID
AND dbo.Entity.Title2 = Types_1.TypeID
LEFT OUTER JOIN
dbo.Types ON dbo.Entity.Title1 = dbo.Types.TypeID
WHERE
(dbo.Entity.EntityID = #EntityID)
END
I'm trying to return the values of Title1 and Title2. The query works, and returns values, but I need to use them elsewhere.
You need to do two things:
First, set the values of those parameters somewhere in the PROC, using SELECT or SET. As #Andomar mentioned this can be done by changing your SELECT statement like this (in your existing code you are returning the values in a column with the same name but that won't actually set the parameters):
SELECT #Title1 = dbo.Types.TypeName, #Title2 = Types_1.TypeName
Then you need to capture those values in your calling program. I'm not sure whether you're calling this stored proc from another bit of SQL code or from code such as ADO.NET. If from SQL, you'll need to first declare the output parameters and then call the proc like this:
DECLARE #Title1 VARCHAR(10), #Title2 VARCHAR(10)
EXEC MyProc #Title1=#Title1 OUTPUT, #Title2=#Title2 OUTPUT
If you're calling from ADO.NET, you need to set the ParameterDirection as Output or InputOutput, call the proc with the parameter, and then read the value of the parameter afterwards.
SELECT #Title1 = dbo.Types.TypeName
, #Title2 = Types_1.TypeName
...

'Where in' T-SQL implementation

I have a stored procedure that take many input parameters including an #userID.
Now, in the core of the SP I select from a view using the following Where close :
Where userID = #userID
This works fine. Now I want to pass multiple users to be able wo query it like this :
where userID in (1,2,...)
How can I pass the value 1,2 from one input parameter ?
Thanks
Create a function split:
create FUNCTION [dbo].[Split]
(
#List nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Value nvarchar(2000)
)
AS
BEGIN
While (Charindex(#SplitOn,#List)>0)
Begin
Insert Into #RtnValue (value)
Select Value = ltrim(rtrim(Substring(#List,1,Charindex(#SplitOn,#List)-1)))
Set #List = Substring(#List,Charindex(#SplitOn,#List)+len(#SplitOn),len(#List))
End
Insert Into #RtnValue (Value)
Select Value = ltrim(rtrim(#List))
Return
--select Value from dbo.Split('item1, item2, item3',',')
END
GO
And call the function with #PASS and use it inside a cursor.
Arrays and Lists in SQL Server
Create an input parameter which is a table varaible and send in the array as a table that you join to instead of using in. Read about this in BOL as it can be a little tricky to set up.

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