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.
Related
I have 800+ functions in my database. I would need to modify their source databases dynamically and create snapshots.
example of the function:
create function [schema1].[funTest1] (#param1 varchar(50))
returns table as
return
(
select * from [curr_database1].[schema1].[funTest1](#param1)
union
select * from [curr_database2].[schema1].[funTest1](#param1)
)
I want to change the script as:
create or alter function [schema1].[funTest1] (#param1 varchar(50))
returns table as return
(
select * from [new_database2].[schema1].[funTest1](#param1)
union
select * from [new_database3].[schema1].[funTest1](#param1)
)
basically, I got all the functions script using the sys.syscomments. I'm looking for an option to find and replace the database dynamically to create the snapshots.
How can I get it? Thank you!
Here is the sample code that I have developed for sharing. All the database in the functions starts with the same text(for ex. "curr"). Please share your thoughts. Thanks in advance!
create or alter proc test_proc as
begin
set nocount on
-- this piece of code has the new databases
if object_id('tempdb..#dbNames') is not null drop table #dbNames
create table #dbNames (dbName varchar(1000), id int)
insert into #dbNames(dbName, id) values ('new_database2', 1),('new_database3', 2)
insert into #dbNames(dbName, id) values ('new_database8', 3),('new_database9', 4)
-- this one has the sample functions
if object_id('tempdb..#dbFunctions') is not null drop table #dbFunctions
create table #dbFunctions (funText nvarchar(max))
insert into #dbFunctions (funText) values('create function [schema1].[funTest1] (#param1 varchar(50))
returns table as
return
(
select * from [curr_database1].[schema1].[funTest1](#param1)
union
select * from [curr_database2].[schema1].[funTest1](#param1)
)'),
('create function [schema2].[funTest2] (#param1 varchar(50), #param2 varchar(100))
returns table as
return
(
select * from [curr_database4].[schema2].[funTest2](#param1, #param2)
union
select * from [curr_database5].[schema2].[funTest2](#param1, #param2)
)')
-- declare variables and assign value for #frmStr variable (for testing purposes)
declare #str nvarchar(max)
declare #dbName varchar(100)
declare #frmStr varchar(100) = '[curr_database1]'
-- get the total count of the databases and the functions to iterate and replace the string
declare #dbCnt int = (select count(id) from #dbNames)
declare #fnCnt int = (select count(*) from #dbFunctions)
while #dbCnt > 0
begin
set #dbname = (select dbname from #dbnames where id = #dbcnt)
while #fnCnt > 0
begin
-- this is where I would need to replace the code
select #str = replace(funText, #frmStr, #dbName) from #dbFunctions
select #str
set #fnCnt = #fnCnt - 1
end
set #dbCnt = #dbCnt - 1
end
end
Your actual goal isn't clear, but to answer the question you asked, you can use REPLACE functions in the query to syscomments that you used to get the code in the first place:
REPLACE(
REPLACE([FunctionTextColumn],'curr_database1','new_database2')
,'curr_database2','new_database3'
)
How to achieve below requirement in SQL Server.
Data what I have:
and Expected output is:
Thanks,
Lawrance A
Assuming of your given data value:
'Message:"A",Level:"0",type:"log"'
'Message:"B",Level:"1",type:"log"'
select substring(ColumnA,10,1) Message,
replace(dbo.udf_GetNumeric(replace(replace(substring(ColumnA,20,5),'"',''),',','')),' ','')[type],
replace(replace(substring(ColumnA,29,250),'"',''),',','')[Log] from YourTable
GetNumeric here
I have created two function to achieve your desired output.
use below query by creating two function split and getVal
select
dbo.getVal(columnA,'Message') Message,
dbo.getVal(columnA,'Level') [Level],
dbo.getVal(columnA,'type') [type]
from TableA
Query for creating split and getVal function
Create function split(#s varchar(500),#splitWith varchar(20))
returns #RetTable Table(id int identity(1,1), Value varchar(200))
as
begin
if(CHARINDEX(#splitWith,#s)>0)
begin
set #s=#s+#splitWith
declare #len int =len(#s)
while charindex(#splitWith,#s)>0
begin
insert #RetTable values(SUBSTRING(#s,1,charindex(#splitWith,#s)-1))
set #s=SUBSTRING(#s,charindex(#splitWith,#s,1)+1,#len)
end
end
return
end
Create function getVal(#str varchar(500),#column varchar(200))
returns varchar(200)
as
begin
declare #ret varchar(200)
select #ret=value From dbo.split((select value From dbo.split('Message:"A",Level:"0",type:"log"',',') where value like +#column+'%'),':') where id=2
return replace(#ret,'"','')
end
I've created the following stored procedure:
ALTER PROCEDURE [dbo].[CountInJunction]
#Mod as nvarchar(10),
#Junction as nvarchar(10),
#PJ as nvarchar(10),
**#case as varchar(10)**,
#Date as varchar(20)
as
begin
declare #result as int
select #result = count(distinct CONCAT ([UCID],[CALLSEGMENT]))
from IVR_LINES
where MODULE = #Mod and DATE = #date
and EVENT_NAME = #Junction and **EVENT_VALUE in (#case)**
insert into [dbo].[MainJuncTable] values(#Mod,#PJ,#Junction,#case,#result,null,null,#date)
return #result
end
I would like to pass ('0','5') as #case.
for some reason, I get 0 as a result, which is not correct. Its seems that the SP doesn't interpret ('0','5') correctly.
I've been trying multiple combinations such as:
'0','5'
'0'+','+5''
'0,5'
etc..
nothing works.
Is there any way I can pass these chars correctly?
Thanks.
Send the values as a single string like ('0,5')
Then in where condition u need to split and select the values like,
where EVENT_VALUE in (select val from Split(#case,','))
Split is user defined function,you need to create before using it.
CREATE FUNCTION [dbo].[Split]
(
#delimited nvarchar(max),
#delimiter nvarchar(100)
) RETURNS #t TABLE
(
-- Id column can be commented out, not required for sql splitting string
id int identity(1,1), -- I use this column for numbering splitted parts
val nvarchar(max)
)
AS
BEGIN
declare #xml xml
set #xml = N'<root><r>' + replace(#delimited,#delimiter,'</r><r>') + '</r></root>'
insert into #t(val)
select
r.value('.','varchar(max)') as item
from #xml.nodes('//root/r') as records(r)
RETURN
END
GO
In every case, use this as your parameter value: '0,5'
But how to use it depends on the version of sql server you're using.
If you've got 2016, there's STRING_SPLIT. https://msdn.microsoft.com/en-us/library/mt684588.aspx
If you don't have it, you can create a function. See related stackoverflow posts: How to split a comma-separated value to columns
Or if you want rows: SQL query to split column data into rows
(See the higher rated recommendations in both of those.)
I need to call a stored procedure like this:
exec myProcedure '(5, 15, 45)'
And inside the procedure I need to use the int-set within an in-Clasue
like this:
SELECT ... FROM table WHERE (days in #intSet)
This always bring a syntax Error in the WHERE-Clause.
(SqlServer evidently does not allow to simply replace a part of the statement by a string)
I plan a solution like this:
I can easily split the integer values of the string into several integers using
CHARINDEX, SUBSTRING, RTRIM, LTRIM, CONVERT - this is not an issue - it works fine.
But I still cannot figure out into what kind of variable could I then put those integers in order to later use it with the IN-Clause ?
any ideas are greatly appreciated
Gerald
You will need to create a split function inside you database,
Definition Of Split Function
CREATE FUNCTION [dbo].[split]
(
#delimited NVARCHAR(MAX),
#delimiter NVARCHAR(100)
)
RETURNS #t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
DECLARE #xml XML
SET #xml = N'<t>' + REPLACE(#delimited,#delimiter,'</t><t>') + '</t>'
INSERT INTO #t(val)
SELECT r.value('.','varchar(MAX)') as item
FROM #xml.nodes('/t') as records(r)
RETURN
END
Stored Procedure
Then you would use this split function insdie your Procedure to split the values to be used with In operator.
CREATE PROCEDURE GetData
#intSet VARCHAR(1000) = NULL
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM TableName
WHERE days IN (SELECT Val FROM dbo.split(#intSet ))
END
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