Sql Server - pass array to procedure - sql-server

I need to pass set of int to sql procedure.
alter PROC PrCustomerServicesUpd(
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml NVARCHAR(1000),
#ServicesIdCount INT =1
)
AS
DECLARE #XmlDocHanle INT
EXEC sp_Xml_PrepareDocument #XmlDocHanle OUTPUT, #ServicesIdXml
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT)
EXEC sp_Xml_RemoveDocument #XmlDocHanle
go
PrCustomerServicesUpd '443c293e-fc78-4562-97f8-ee1f2b54f813'
,'<Services><ServiceId>12</ServiceId><ServiceId>156</ServiceId></Services>',22
This script returns one empty field named 'ServiceId' instead of 2 rows.

Assuming this is SQL Server 2000 (otherwise there is no sane reason to use OPENXML), you need to get the text() within the node, otherwise it tries to find the attribute "ServiceId" within the node "ServiceId". Also your parameter XML is completely out of sync with what the proc expects.
alter PROC PrCustomerServicesUpd(
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml NVARCHAR(1000),
#ServicesIdCount INT =1
)
AS
DECLARE #XmlDocHanle INT
EXEC sp_Xml_PrepareDocument #XmlDocHanle OUTPUT, #ServicesIdXml
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT 'text()')
EXEC sp_Xml_RemoveDocument #XmlDocHanle
GO
PrCustomerServicesUpd '443c293e-fc78-4562-97f8-ee1f2b54f813'
,'<ROOT><Services><ServicesId>12</ServicesId><ServicesId>156</ServicesId></Services></ROOT>',3
Using the XML data type
alter PROC PrCustomerServicesUpd
#CustomerId UNIQUEIDENTIFIER,
#ServicesIdXml xml,
#ServicesIdCount INT =1
AS
select service.id.value('.','int')
from #ServicesIdXml.nodes('/ROOT/Services/ServicesId') service(id)
GO

You can pass set of int in varchar(1000) with comma separator
so int value passing as "1223,12,254,5545,8787,8787,787,78,45475,45,45"
And in store procedure you can get one by one id with fnSplit function (Tabular).
ALTER function [dbo].[fnSplit](
#String nvarchar (4000),
#Delimiter nvarchar (10)
)
returns #ValueTable table ([Value] nvarchar(4000))
begin
declare #NextString nvarchar(4000)
declare #Pos int
declare #NextPos int
declare #CommaCheck nvarchar(1)
--Initialize
set #NextString = ''
set #CommaCheck = right(#String,1)
--Check for trailing Comma, if not exists, INSERT
--if (#CommaCheck <> #Delimiter )
set #String = #String + #Delimiter
--Get position of first Comma
set #Pos = charindex(#Delimiter,#String)
set #NextPos = 1
--Loop while there is still a comma in the String of levels
while (#pos <> 0)
begin
set #NextString = substring(#String,1,#Pos - 1)
insert into #ValueTable ( [Value]) Values (#NextString)
set #String = substring(#String,#pos +1,len(#String))
set #NextPos = #Pos
set #pos = charindex(#Delimiter,#String)
end
return
end
so you can get the one by one value as
"Select value from dbo.fnsplit (#values,',')"

I think you mean ServiceId and not ServicesId.
In addition the third parameter of OPENXML should not be #ServicesIdCount, it should be a value describing what sort of output you want.
Don't think you specify a ROOT node in your XML, so remove that
SELECT * FROM OPENXML(#XmlDocHanle, '/ROOT/Services/ServicesId',#ServicesIdCount)
WITH (ServiceId INT)
should be
SELECT * FROM OPENXML(#XmlDocHanle, '/Services/ServiceId', 1)
WITH (ServiceId INT)

Related

Stored procedure only return the data from table 1 rather than 10 tables

ALTER PROCEDURE [dbo].[ProcessListSQL]
( --#CommaDelimitedList AS NVARCHAR(MAX),
#SQLtoExecute AS NVARCHAR(MAX),
#Result VARCHAR(MAX) OUTPUT)
AS
BEGIN
DECLARE #Statements TABLE
(PK INT IDENTITY(1,1) PRIMARY KEY,
SQLObject NVARCHAR (MAX)
)
SET #SQLtoExecute = REPLACE (#SQLtoExecute, '"', '''')
/*================*/
DECLARE #CommaDelimitedList AS NVARCHAR(MAX)
DECLARE #ddd NVARCHAR(MAX)
DECLARE #R1 NVARCHAR(MAX)
SET #ddd=''
SELECT #ddd = #ddd + organisation + ','
FROM dbo.Orgs;
SET #CommaDelimitedList = #ddd /*select all tables that need to be interrogated*/
/*================*/
INSERT INTO #Statements
SELECT PARAM
FROM [dbo].[fn_MVParam](#CommaDelimitedList,',')
DECLARE #i INT
SELECT #i = MIN(PK) FROM #Statements
DECLARE #max INT
SELECT #max = MAX(PK) FROM #Statements
DECLARE #SQL AS NVARCHAR(MAX) = NULL
DECLARE #Object AS NVARCHAR(MAX) = NULL
WHILE #i <= #max
BEGIN
SELECT #Object = SQLObject FROM #Statements WHERE PK = #i /*gets the table from the array table*/
SET #SQL = REPLACE(#SQLtoExecute, '{RP}', #Object) /*replaces RP with tablename */
-- Uncommend below to check the SQL
-- PRINT #SQL
DECLARE #returnstatus nvarchar(15); /*mh did this */
SET #returnstatus = NULL; /*mh did this */
EXECUTE sp_executesql #SQL,#R1=#R1
SET #Result = #Result + #R1
SELECT #Object = NULL
SELECT #SQL = NULL
SET #i = #i + 1
END
END
This works okay but only return the first table the tables collection come from function.
If I execute it in SQL Server Management Studio, I get the right answer - I need to transpose this so MVC code somehow....
USE [HOTFF]
GO
CREATE TABLE #Resultxx
(
organisation varchar(max),
Product varchar(max)
)
DECLARE #return_value int
DECLARE #Result NVARCHAR (MAX)
INSERT INTO #Resultxx
EXEC #return_value = [dbo].[ProcessListSQL]
#SQLtoExecute = N'SELECT organisation, product FROM [{rp}] WHERE category=''offers'' and Type=''free''',
#Result = '#Result OUTPUT'
SELECT * FROM #Resultxx
DROP TABLE #Resultxx
The best way I can do this is call procedure A from procedure B. In procedure B insert the result into a temp table and select the temp table this then is called from MVC c# as a standard stored procedure.

"Error converting data type nvarchar to bigint" when executing a stored procedure

I'm trying to execute a stored procedure which inputs 3 parameters selected from a query. The first 2 stored procedure parameters are supposed to be int or bigint, but sql doesn't accept it and tell me it cannot convert type nvarchar to bigint.
So I changed the parameter types to nvarchar but now I get this error when executing a query within the stored procedure. I tried to convert nvarchar to bigint but it doesn't work even though the parameter values are numeric.
Here's how I'm executing the stored procedure:
[dbo].[InsertMultiChoiceList] [PatientRiskAssessmentQuestionsID], NetworkRiskAssessmentQuestionsID, Answer
The parameters being passed on look like these:
230124| 118 |COPD (Chronic Obstructive Pulmonary Disease), Congestive Heart Failure (CHF), Sleep Apnea
Here the definition of my stored procedure:
ALTER PROCEDURE [dbo].[InsertMultiChoiceList]
#PatientRiskAssessmentQuestionsID nvarchar(100),
#NetworkRiskAssessmentQuestionsID nvarchar(100),
#answer varchar(max)
AS
BEGIN
DECLARE #XML AS XML
DECLARE #Delimiter AS CHAR(1) =','
SET #XML = CAST(('<X>'+REPLACE(#answer , #Delimiter ,'</X><X>')+'</X>') AS XML)
DECLARE #temp TABLE (Answer Varchar(max))
INSERT INTO #temp
SELECT N.value('.', 'Varchar(max)') AS Answer
FROM #XML.nodes('X') AS T(N)
INSERT INTO [dbo].[PatientRiskAssessmentQuestionsList](NetworkRiskAssessmentListID, PatientRiskAssessmentQuestionsID)
SELECT
[dbo].[fnc_GetNetworkRiskAssessmentList](LTRIM(RTRIM(q.Answer)), #NetworkRiskAssessmentQuestionsID, 'List') AS NetworkRiskAssessmentListID,
#PatientRiskAssessmentQuestionsID
FROM
(SELECT Answer FROM #temp) q
WHERE
NOT EXISTS (SELECT 1
FROM PatientRiskAssessmentQuestionsList x
WHERE x.NetworkRiskAssessmentListID = NetworkRiskAssessmentListID
AND x.PatientRiskAssessmentQuestionsID = #PatientRiskAssessmentQuestionsID);
END
Here's the structure of the PatientRiskAssessmentQuestionsList table
Here's the script for fnc_GetNetworkRiskAssessmentList
ALTER function [dbo].[fnc_GetNetworkRiskAssessmentList]
(#text varchar(max),
#networkriskquestionid bigint,
#type varchar(20)
)
RETURNS BIGINT
AS
BEGIN
declare #id bigint
declare #questionid bigint
declare #count int
set #id = null
set #questionid = null
set #count = 0
if(#type = 'List')
begin
select #count = Count(*)
from NetworkRiskAssessmentList mc
where mc.Answer = #text
and mc.NetworkRiskAssessmentQuestionsID = #networkriskquestionid
if #count > 0
begin
select top(1) #questionid = mc.NetworkRiskAssessmentListID
from NetworkRiskAssessmentList mc
where mc.Answer = #text
and mc.NetworkRiskAssessmentQuestionsID = #networkriskquestionid
set #id = #questionid
end
end
return #questionid
end
The issue is you are trying to push a string value into the column NetworkRiskAssessmentListID which is actually BIGINT thus SQL doesn't allow the conversion.
Just a sample code to show you the issue
CREATE TABLE #Test
(
Patient BIGINT,
Network BIGINT
)
GO
DECLARE #Patient NVARCHAR(100)
DECLARE #Network NVARCHAR(100)
SET #Patient = '1234'
SET #Network = 'List'
INSERT INTO #Test VALUES (#Patient,#Network)
Hope this helps, try changing the datatype of the table and give it a try.
maybe your data has Enter character or Tab character so use code like below :
DECLARE #XML AS XML
DECLARE #Delimiter AS CHAR(1) =','
SET #XML = CAST(('<X>'+REPLACE(#answer , #Delimiter ,'</X><X>')+'</X>') AS XML)
DECLARE #temp TABLE (Answer Varchar(max))
INSERT INTO #temp
SELECT N.value('.', 'Varchar(max)') AS Answer FROM #XML.nodes('X') AS T(N)
insert into [dbo].[PatientRiskAssessmentQuestionsList](NetworkRiskAssessmentListID, PatientRiskAssessmentQuestionsID)
select
[dbo].[fnc_GetNetworkRiskAssessmentList](LTRIM(RTRIM(q.Answer)), #NetworkRiskAssessmentQuestionsID, 'List') as NetworkRiskAssessmentListID,
#PatientRiskAssessmentQuestionsID
from
(select cast(replace(replace(Answer, char(13), ''), char(10), '') as bigint) as Answer from #temp) q
where not exists
(
select 1 from PatientRiskAssessmentQuestionsList x
where x.NetworkRiskAssessmentListID = NetworkRiskAssessmentListID and x.PatientRiskAssessmentQuestionsID = #PatientRiskAssessmentQuestionsID
);
You are passing PatientRiskAssessmentQuestionsID value to #PatientRiskAssessmentQuestionsID nvarchar(100) parameter
Then you are using it in next code
select 1 from PatientRiskAssessmentQuestionsList x
where x.NetworkRiskAssessmentListID = NetworkRiskAssessmentListID
and x.PatientRiskAssessmentQuestionsID = #PatientRiskAssessmentQuestionsID
so the issue in the AND condition, here
and x.PatientRiskAssessmentQuestionsID = 'PatientRiskAssessmentQuestionsID'
x.PatientRiskAssessmentQuestionsID is bigint
and #PatientRiskAssessmentQuestionsID is nvarchar (100)
its value
[PatientRiskAssessmentQuestionsID]
so fix this one, and everything will be Ok.

Conversion failed in cursor in stored procedure

Input like 111111 and 101,102,103,104
I want to check whether user has access on this requests or not...
I tried a cursor as shown, but I get this error:
Conversion failed when converting the varchar value '101,102,103,104' to data type int.
Code:
ALTER PROCEDURE [dbo].[ValidateRqstId]
#UserID VARCHAR(50),
#RsqtIDs VARCHAR(300)
AS
BEGIN
Declare #RqstId int
Declare #Result int
Declare #UserIDToCheck VARCHAR(50)
Declare #RqstUserVal cursor for
Select RequestId
from REQUEST_LIST
where RequestId in (#RsqtIDs)
BEGIN
OPEN RqstUserVal
FETCH NEXT from RqstUserVal into #RqstId
WHILE(##fetch_status <> -1)
BEGIN
SET #UserIDToCheck = (
select UserId from dbo.REQUEST_LIST where RequestId = #RqstId)
Print(#UserIDToCheck)
If(#UserIDToCheck != #UserID)
SET #Result = 99 ;
--Fetch the next row from the cursor
FETCH RqstUserVal into #RqstId
END
END
CLOSE RqstUserVal
Deallocate RqstUserVal
RETURN #Result
END
Thanks in advance
Depending on your SQL-Server Verion you can use a Table-Valued Function like in this short example
Select * from dbo.test1
Where ID in(
Select * from dbo.F_SplitAsIntTable('1,123,234,456'))
Function defined as
CREATE FUNCTION F_SplitAsIntTable
(
#txt varchar(max)
)
RETURNS
#tab TABLE
(
ID int
)
AS
BEGIN
declare #i int
declare #s varchar(20)
Set #i = CHARINDEX(',',#txt)
While #i>1
begin
set #s = LEFT(#txt,#i-1)
insert into #tab (id) values (#s)
Set #txt=RIGHT(#txt,Len(#txt)-#i)
Set #i = CHARINDEX(',',#txt)
end
insert into #tab (id) values (#txt)
RETURN
END
GO

passing a TSQL function database name

Is there any way to pass a tsql function a database name so it can perform selects on that database
ALTER function [dbo].[getemailjcp]
(
#DB_Name varchar(100)
)
Returns varchar(4000)
AS
BEGIN
DECLARE #out varchar (4000);
DECLARE #in varchar (1000);
Set #out =
(select substring
((select ';' + e.email from
(SELECT DISTINCT ISNULL(U.nvarchar4, 'NA') as email
FROM [#DB_Name].dbo.Lists ...
In order to create dynamic SQL statement you should store procedure. For example:
DECLARE #DynamicSQLStatement NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #FirstID BIGINT
SET #ParmDefinition = N'#FirstID BIGINT OUTPUT'
SET #DynamicSQLStatement=N' SELECT #FirstID=MAX(ID) FROM ['+#DatabaseName+'].[dbo].[SourceTable]'
EXECUTE sp_executesql #DynamicSQLStatement,#ParmDefinition,#FirstID=#FirstID OUTPUT
SELECT #FirstID
In this example:
#DatabaseName is the passed as parameter to your procedure.
#FirstID is output parameter - this value might be return from your procedure.
Here you can find more information about "sp_executesql":
http://msdn.microsoft.com/en-us/library/ms188001.aspx
a better solution might be to replace "#DatabaseName" (a char variable)with:
"DB_NAME(<#DBId>)".
You can then continue to pass in the db names, but 1st converting them to IDs in the fcn. Also kinda resolves the contradiction of building a SQL stmt w/ a char variable in it, if using "sp_executesql" to help guard against SQL injection ("DB_NAME()" isn't a variable/can't be substituted).
So you'd have this:
DECLARE #DynamicSQLStatement NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #FirstID BIGINT
DECLARE #DBId INT
SET #DBId = DB_ID(#Db_Name) --raise the proper security/robustness** concern if this doesn't resolve.
SET #ParmDefinition = N'#FirstID BIGINT OUTPUT'
SET #DynamicSQLStatement=N' SELECT #FirstID=MAX(ID) FROM ['+DB_NAME(#DBId)+'].[dbo].[SourceTable]'

How to use the result from a procedure in another procedure in SqlServer?

I'm trying to combine a result mixed with some SELECTs.
I wanted to set #result combined with the result of [proc_Get_Frame_CourseNum] procedure but It didn't work.
declare #str varchar(300)
declare #result varchar(200)
declare #temp varchar(20)
declare #i int
set #str='110,120,130,140'
set #result=''
set #temp=''
set #i=0
while #i<len(#str)/4+1
begin
set #temp=substring(#str,1,3)
set #str=substring(#str,2,len(#str))
set #result=#result+ exec [proc_Get_Frame_CourseNum] #temp
set #i=#i+1
end
select #temp
Personally, I'd make use of output variables
CREATE PROCEDURE proc_Get_Frame_CourseNum
#temp varchar(20),
#outValue varchar(50) OUTPUT
AS
BEGIN
--do stuff
--before you leave the method or do your final SELECT
SET #outValue = 'whatever your result is'
--more stuff
END
Then in your code, you just go:
DECLARE #outValue VARCHAR(20)
-- rest of your code
EXEC [proc_Get_Frame_CourseNum] #temp, #outValue OUT
SET #result = #result + #outValue
Alternatively, you could just dump the results of the SP into a temp table, then read from it into your #Result variable.
You can't interpolate the result of one procedure by appending it.
I am assuming now that [proc_Get_Frame_CourseNum] returns a scalar result.
So run exec [proc_Get_Frame_CourseNum] #temp in another line of batch (before set #result = #result + call)
Your query should look like,
declare #scalarResult = exec [proc_Get_Frame_CourseNum] #temp
set #result=#result+ #scalarResult

Resources