Issue with splitting values and passing to a stored procedure - sql-server

Iam getting the below input parameter values in one of the stored procedure.
#DocKey1, #DocValue1,
#DocKey2, #DocValue2,
#DocKey3, #DocValue3,
#DocKey4, #DocValue4,
#DocKey5, #DocValue5
From this procedure iam calling another procedure to insert each pair of values.
Right now am calling the InsertDocValues stored procedure multiple times to insert each pair.
exec InsertDocValues #DocKey1, #DocValue1
exec InsertDocValues #DocKey2, #DocValue2
exec InsertDocValues #DocKey3, #DocValue3
exec InsertDocValues #DocKey4, #DocValue4
exec InsertDocValues #DocKey5, #DocValue5
Is there anyway i can pass the complete set of values to another procedure as below and then split each pair and insert
eg: #DocKey1, #DocValue1 and #DocKey2, #DocValue2 etc
#DocKey1, #DocValue1, #DocKey2, #DocValue2, #DocKey3, #DocValue3, #DocKey4, #DocValue4, #DocKey5, #DocValue5
Below is the procedure am using now to insert
Create PROCEDURE [dbo].[InsertDocValues]
(
#DocKey varchar(20),
#DocValue nvarchar(20)
)
AS
SET NOCOUNT ON;
BEGIN
INSERT INTO dbo.DocValues(
DocKey,
DocValue
)
VALUES(
#DocKey,
#DocValue
)
End
Please suggest

May be the below code would work for you.
Using user defined table type variable.
CREATE TYPE DocTable AS TABLE
(
DocKey int,
DocValue nvarchar(50)
);
GO
And then use this type to create required variable in first SP and pass the same to your second SP.
DECLARE #DocTable AS DocTable;
INSERT INTO #DocTable
SELECT #DocKey1, #DocValue1 UNION ALL
SELECT #DocKey2, #DocValue2 UNION ALL
SELECT #DocKey3, #DocValue3 UNION ALL
SELECT #DocKey4, #DocValue4 UNION ALL
SELECT #DocKey5, #DocValue5
You can create the above insert query dynamically also. There are so many ways to populate a table. So, use any one as you are getting output from your first SP.
And then call your Second SP.
EXEC [dbo].[InsertDocValues] #DocTable
Changes in second SP would be look like this.
Create PROCEDURE [dbo].[InsertDocValues]
(
#DocTable DocTable READONLY
)
AS
SET NOCOUNT ON;
BEGIN
INSERT INTO dbo.DocValues(
DocKey,
DocValue
)
SELECT
DocKey,
DocValue
FROM #DocTable
END

I'm getting the sense you have a string of pairs (key,value). Perhaps something like this:
Example
Declare #List varchar(max) = 'Key1:Value1,Key2:Value2'
Insert Into dbo.DocValues(DocKey,DocValue )
Select DocKey = left(RetVal,charindex(':',RetVal+':')-1)
,DocVal = stuff(RetVal,1,charindex(':',RetVal+':'),'')
From (
Select RetSeq = row_number() over (Order By (Select null))
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(#List,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) A
The Data Inserted would be
DocKey DocVal
Key1 Value1
Key2 Value2

Related

SQL stored proc using where in statement

I am trying to inserting data from a table to another table. But I need using multiple specific IDs in where clause. And, I need to define these IDs while running the proc. The query is below,
CREATE PROCEDURE insert_hh
#id int
AS
BEGIN
SET IDENTITY_INSERT test_HH ON
INSERT INTO test_HH
(ID,Beneficiary_Name,Family_Members,
[M_50_yrs],
[F_50_yrs],
[M_50_18],
[F_50_18],
[M_18_15],
[F_18_15],
[M_15_5],
[F_15_5],
[M_5_2],
[F_5_2],
[M_2],
[F_2],
Beneficiary_Status,
Reason_of_Rejection)
SELECT ID,Beneficiary_Name,Family_Members,
[M_50_yrs],
[F_50_yrs],
[M_50_18],
[F_50_18],
[M_18_15],
[F_18_15],
[M_15_5],
[F_15_5],
[M_5_2],
[F_5_2],
[M_2],
[F_2],
Beneficiary_Status,
Reason_of_Rejection
FROM HH
WHERE ID IN ((#id))
SET IDENTITY_INSERT test_HH OFF
END
For now, I can insert only one ID for each time. Can you help me to insert multiple IDs in the same proc?
Thanks.
For multiple value change #Id parameter of stored procedure to VARCHAR with desired length.
CREATE PROCEDURE insert_hh
#id varchar(max)
AS
SET #Id = '1,10,20,30'
-- temp table
DECLARE #Id_tbl TABLE ( Id INT )
INSERT INTO #Id_tbl
SELECT
LTRIM(RTRIM(split.a.value('.', 'NVARCHAR(MAX)'))) AS fqdn
FROM
(SELECT
CAST ('<M>' + REPLACE(#Id, ',', '</M><M>') + '</M>' AS XML) AS data ) AS a
CROSS APPLY data.nodes ('/M') AS split(a)
-- INSERT STATEMENT
SELECT <Fields> FROM
<Your Table>
WHERE
ID IN (SELECT Id FROM #Id_tbl)
END
GO
CREATE PROCEDURE insert_hh
#id NVARCHAR(MAX)
AS
BEGIN
SET IDENTITY_INSERT test_HH ON
INSERT INTO test_HH
(ID,Beneficiary_Name,Family_Members,[M_50_yrs],[F_50_yrs],[M_50_18],[F_50_18],
[M_18_15],[F_18_15],[M_15_5],[F_15_5],[M_5_2],[F_5_2],[M_2],[F_2],
Beneficiary_Status,Reason_of_Rejection)
SELECT ID,Beneficiary_Name,Family_Members,[M_50_yrs],[F_50_yrs],[M_50_18],
[F_50_18],[M_18_15],[F_18_15],[M_15_5],[F_15_5],[M_5_2],[F_5_2],[M_2],[F_2],
Beneficiary_Status,Reason_of_Rejection
FROM HH
CROSS APPLY STRING_SPLIT(#id, ',')
WHERE HH.ID = value
SET IDENTITY_INSERT test_HH OFF
END
modelling fiddle
Pay attention - the parameter datatype is changed.

How to pass an array of integer values from a table to a stored procedure?

I have a stored proc using dynamic sql that updates a few columns based on the value passed to it. I am trying to test it out for multiple values without having to enter those manually. These values are to be taken from a table. Is there a way to pass all these values in the table and have it go through the proc? Just like in your regular programming language where you would run through an array. I am doing this in sql server 2012.
Code is something like this
CREATE PROCEDURE sp1 #enteredvalue int
AS
BEGIN
UPDATE table1
SET column1 = 'some var char value',
column2 = 'some integer values'
WHERE xid = #enteredvalue
END
I want to enter the values for that integer parameter (#enteredvalue) from a table that has different values.
Perhaps a little more dynamic SQL will do the trick (along with a parser)
Declare #String varchar(max) = '1,25,659'
Declare #SQL varchar(max) = ''
Select #SQL = #SQL + concat('Exec [dbo].[sp1] ',Key_Value,';',char(13))
From (Select * from [dbo].[udf-Str-Parse-8K](#String,',')) A
Select #SQL
--Exec(#SQL)
Returns
Exec [dbo].[sp1] 1;
Exec [dbo].[sp1] 25;
Exec [dbo].[sp1] 659;
The UDF if needed (super fast!)
CREATE FUNCTION [dbo].[udf-Str-Parse-8K](#String varchar(8000), #Delimiter varchar(50))
Returns Table
As
--Usage: Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
-- Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
-- Select * from [dbo].[udf-Str-Parse-8K]('The quick brown fox',' ')
Return (
with cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (IsNull(DataLength(#String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a, cte1 b, cte1 c, cte1 d) A ),
cte3(N) As (Select 1 Union All Select t.N+DataLength(#Delimiter) From cte2 t Where Substring(#String,t.N,DataLength(#Delimiter)) = #Delimiter),
cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(#Delimiter,#String,s.N),0)-S.N,8000) From cte3 S)
Select Key_PS = Row_Number() over (Order By A.N)
,Key_Value = Substring(#String, A.N, A.L)
,Key_Pos = A.N
From cte4 A
)
Another approach is (without Dynamic SQL):
1) Create a new SP where input parameter is a table
https://msdn.microsoft.com/en-us/library/bb510489.aspx
2) In that procedure, create a WHILE loop to go through each row and execute your existing SP for each individual row value
Example of WHILE loop is here:
SQL Call Stored Procedure for each Row without using a cursor
To pass a table into an SP, consider creating a User-Defined Table type. Example:
create type ArrayOfInt as table (IntVal int)
go
create proc SumArray(#IntArray ArrayOfInt readonly)
as
select sum(IntVal) from #IntArray
go
declare #IntArray ArrayOfInt
insert #IntArray values (1), (2), (3)
select * from #IntArray
exec SumArray #IntArray
drop proc SumArray
drop type ArrayOfInt

jdbc sql error: statement did not return a result set

I have two stored procedures as follows:
create stored procedure p1
as
select * from table1 where datediff(day, table1.[date], getdate())
create stored procedure p2
as
declare #t1 table(
ref varchar(20)
)
insert into #t1 select * from table1 where ref = 'some ref'
declare #t2 table(
fname varchar(20),
lname varchar(20),
email varchar(1000)
)
declare #len int = (select count(ref) from #t1)
while #len > 0
begin
declare #value varchar(20) = (select top 1 ref from #t1)
insert into #t2 select * from table2 where ref = #ref
delete from #t1
where ref = #value
set #len = (select count(ref) from #t1)
end
select * from #t2
Java code
....
String query = "Execute [p2]";
try(CallableStatement cstmt = conn.prepareCall(query);
ResultSet rs = cstmt.executeQuery()){
... some code
}
The table variable #t1 hold select result from a table 'table1'
The variable #len hold the number of rows in #t1
Using #len > 0 as condition in while loop, I want to select records from another table 'table2' the table variable #t2 hold the select records from 'table2'
The delete statement removes value from #t1
#len set to new number of rows in #t1
the last statement return all the records store in #t2
The first procedure works fine, but the second procedure works only in SQL Server.
I get this an error message in my java application
statement did not return a resultset
I want this to return a result set with the select statement I have at the
end of the query.
Please is there a way around this?
Your [p2] stored procedure needs to include SET NOCOUNT ON right at the beginning to suppress the "n rows affected" counts so JDBC doesn't get confused as to what it should put into the ResultSet:
CREATE PROCEDURE p2
AS
SET NOCOUNT ON;
declare #t1 table(
ref varchar(20)
)
-- ... and so on
For more information on SET NOCOUNT see
SET NOCOUNT (Transact-SQL)
For more information on precisely what gets returned from a stored procedure call, see
How to get everything back from a stored procedure using JDBC
use method "execute" instead of "executeQuery".

how to pass multiple values in single parameter and how to convert varchar value into integers

CREATE TABLE students
( id INT,
NAME varchar(20)
)
INSERT INTO students(id,name)VALUES(1,'Danny')
INSERT INTO students(id,name)VALUES(2,'Dave')
INSERT INTO students(id,name)VALUES(3,'Sue')
INSERT INTO students(id,name)VALUES(4,'Jack')
INSERT INTO students(id,name)VALUES(5,'Rita')
INSERT INTO students(id,name)VALUES(6,'Sarah')
This is my stored procedure
alter PROCEDURE emp_sp
(
#std_id as VARCHAR(500),
#std_name as varchar(500)
)
AS
begin
SELECT *FROM Students s
WHERE s.id IN(convert(INT,#std_id) ,',')
AND
s.NAME IN(#std_name)
END
GO
Here I execute it manually
EXEC dbo.emp_sp #std_id='1,2,3', #std_name='"Danny","Dave","Sue"'
but I get this error:
Msg 245, Level 16, State 1, Procedure emp_sp, Line 8
Conversion failed when converting the varchar value ',' to data type int.
Anyone can guide me.
To get your current approach working, you will need to use Dynamic Sql, which will be incredibly fragile and prone to Sql Injection attacks. Example of this Here
The better way to do this is through Table Valued Parameters:
CREATE TYPE ttStudentIDs AS TABLE
(
ID INT
);
GO
CREATE TYPE ttStudentNames AS TABLE
(
Name VARCHAR(20)
);
GO
CREATE PROCEDURE dbo.emp_sp
(
#stdIds ttStudentIDs READONLY,
#stdNames ttStudentNames READONLY
)
AS
begin
SELECT s.ID, s.Name
FROM Students s
INNER JOIN #stdIds si
ON s.ID = si.ID
UNION
SELECT s.ID, s.Name
FROM Students s
INNER JOIN #stdNames sn
ON s.Name = sn.Name;
END
GO
And called like so:
DECLARE #Ids AS ttStudentIDs;
DECLARE #Names AS ttStudentNames;
INSERT INTO #Ids VALUES (1),(2),(3);
INSERT INTO #Names VALUES ('Danny'),('Dave'),('Sue');
EXEC dbo.emp_sp #Ids, #Names;
SqlFiddle here

SQL Server query with list parameter

I am using SQL Server and in a stored procedure I want to execute a query with a list parameter something like this:
select * from table where type in #list_types
Is it possible to make this? Or must I use temporary tables?
You could use table-valued parameters. For example:
-- A table valued parameter must have a type.
-- This command creates the type.
create type YourType as table (type varchar(50))
go
create procedure dbo.YourStoredProcedure(
#types YourType readonly)
as
select *
from YourTable
where type in (select type from #types)
go
You can invoke the stored procedure like this:
declare #types YourType
insert #types (type) values ('Type1'), ('Type2')
exec dbo.YourStoredProcedure #types
ADO.NET supports passing a DataTable as a table-valued parameter.
Try this one -
DECLARE #temp TABLE
(
[type] INT
, name NVARCHAR(50)
)
INSERT INTO #temp ([type], name)
VALUES
(1, '1'),
(2, '2')
DECLARE #list_types VARCHAR(30)
SELECT #list_types = '1,3,4,5'
;WITH cte AS
(
SELECT [type] = p.value('(./s)[1]', 'INT')
FROM (
SELECT field = CAST('<r><s>' + REPLACE(#list_types, ',', '</s></r><r><s>') + '</s></r>' AS XML)
) d
CROSS APPLY field.nodes('/r') t(p)
)
SELECT *
FROM #temp
WHERE [type] IN (SELECT [type] FROM cte)

Resources