stored proc - executing a query with NOT IN where clause - sql

i have a stored procedure
Create PROCEDURE abc
#sRemovePreviouslySelectedWhereClause nvarchar(max)
AS
BEGIN
SELECT *
FROM table
WHERE nId NOT IN (#sRemovePreviouslySelectedWhereClause)
END;
The parameter #sRemovePreviouslySelectedWhereClause can have values like 0,1 . But this fails with error message:
Conversion failed when converting the nvarchar value ' 0,1 ' to data type int.
Is there any other way to achieve this other than dynamic queries?

First, create a split function which splits your delimited string into a table:
CREATE FUNCTION [dbo].[Split]
(
#String varchar(max)
,#Delimiter char
)
RETURNS #Results table
(
Ordinal int
,StringValue varchar(max)
)
as
begin
set #String = isnull(#String,'')
set #Delimiter = isnull(#Delimiter,'')
declare
#TempString varchar(max) = #String
,#Ordinal int = 0
,#CharIndex int = 0
set #CharIndex = charindex(#Delimiter, #TempString)
while #CharIndex != 0 begin
set #Ordinal += 1
insert #Results values
(
#Ordinal
,substring(#TempString, 0, #CharIndex)
)
set #TempString = substring(#TempString, #CharIndex + 1, len(#TempString) - #CharIndex)
set #CharIndex = charindex(#Delimiter, #TempString)
end
if #TempString != '' begin
set #Ordinal += 1
insert #Results values
(
#Ordinal
,#TempString
)
end
return
end
Then change your where clause as follows:
select
t.*
from [yourTable] t
where t.[ID] not in (select cast([StringValue] as int) from dbo.Split(#sRemovePreviouslySelectedWhereClause,','))

Create FUNCTION [dbo].[fn_Split] (
#List nvarchar(2000), #SplitOn nvarchar(5)
)
RETURNS #RtnValue table (
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
**********
Create PROCEDURE abc
#sRemovePreviouslySelectedWhereClause nvarchar(max)
AS
BEGIN
SELECT *
FROM Table
WHERE nId NOT IN (select * from dbo.fn_Split(#sRemovePreviouslySelectedWhereClause,','))
END;

You have to split the #sRemovePreviouslySelectedWhereClause parameter by ',' and place the resulting values in a temp table. Then your select would look like
select * from table where nId not in (select nId from #tempIds)

This approach you're trying doesn't work. But if you're on SQL Server 2008, you could make use of the new features called Table Valued Parameters.
Basically, you create a user-defined table type
CREATE TYPE dbo.nIdTable AS TABLE(nID INT)
and you can then pass in multiple values in that TVP from the outside (e.g. from ADO.NET or such):
CREATE PROCEDURE abc(#idValues dbo.nIdTable READONLY)
and use that table variable inside your stored proc:
SELECT *
FROM table
WHERE nId NOT IN (SELECT nID FROM #idValues)

You will need to use Dynamic sql for such kind of queries.
first construct the query and
SET #sql = 'select * from table
where nId not in (' + #sRemovePreviouslySelectedWhereClause+ ')'
then use EXEC(#sql) to run the query.

Related

How to fetch the code comments from a stored procedure / function and populate to a table?

How to fetch the code comments from a stored procedure / function and populate to a table?
/*
Author : Test
Comment : Test
*/
I am working on a user defined function by passing either a stored procedure or function as input parameter to read the code history comments and store it in a table. Having the detail in a table to maintain the version notes for the input.
Check this, there are different ways to get the definition, I prefer sp_helptext because it's already splitted in lines
DECLARE #Objects TABLE(name varchar(100))
DECLARE #Lines TABLE(id int identity, line varchar(maX))
INSERT #Objects
SELECT name FROM sys.objects WHERE Type in ('FN', 'IF', 'P', 'TR', 'TF')
DECLARE #ObjectName VARCHAR(100)
WHILE EXISTS (SELECT 1 FROM #Objects)
BEGIN
SELECT TOP 1 #ObjectName = name FROM #Objects
DELETE #Lines
INSERT #Lines (line)
exec sp_helptext #ObjectName
DECLARE #Linestart INT, #LineEnd INT
WHILE EXISTS(SELECT 1 FROM #Lines WHERE charindex('/*', line) > 0)
BEGIN
SELECT TOP 1 #Linestart = id
FROM #Lines WHERE charindex('/*', line) > 0
ORDER BY id
SELECT TOP 1 #LineEnd = id
FROM #Lines WHERE charindex('*/', line) > 0
ORDER BY id
DECLARE #comment VARCHAR(MAX) = ''
SELECT #Coment = #coment + char(13) + char(10) + line
FROM #Lines
WHERE id between #LineStart and #lineEnd
INSERT INTO yourtable (#objectName, #Comment)
DELETE #Lines WHERE id between #LineStart and #lineEnd
END
DELETE #Objects WHERE name = #ObjectName
END
You can create a function/stored procedure to achieve this:
CREATE FUNCTION InsertCommentIntoTable
(
#Param1 VARCHAR(200)
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE #str VARCHAR(max)
SELECT #str = definition
FROM sys.sql_modules
WHERE object_id = (OBJECT_ID(N'dbo.CustOrderHist'));
--parse #str string value and do your stuffs: #str has the function and stored procedure codes.
RETURN 0;
END
GO

SQL - parametrized procedure with multiple parameters as array

I have very simple procedure:
CREATE PROCEDURE [Report]
#statusValue varchar(200) = '%'
AS
BEGIN
SELECT * FROM SomeTable
WHERE Something LIKE UPPER(#statusValue)
END
I'd like to provide user set multiple statusValue. Because there is 6 levels of statusValue in my table, I'd like to provide user to define required statusValue into procedure parameters - something like array.
I don't know, how it exactly works - I'm very new in this area - but I'm supposing to have procedure like this one:
EXEC Report #statusValue = 'statusValue1|statusValue2|statusValue3'
Do you happen to know, how can I adjust my procedure to have required output. Many thanks in advance.
Use following user defined function to return values from delimited string (say pipe):
CREATE FUNCTION [dbo].[stringlist_to_table]
(#list varchar(8000),
#delimiter nchar(1) = N',')
RETURNS #tbl TABLE (value varchar(8000)) AS
BEGIN
DECLARE #pos int,
#tmpstr varchar(8000),
#tmpval varchar(8000);
SET #tmpstr = #list;
SET #pos = charindex(#delimiter , #tmpstr);
WHILE #pos > 0
BEGIN
SET #tmpval = ltrim(rtrim(left(#tmpstr, #pos - 1)))
INSERT #tbl (value) VALUES(#tmpval)
SET #tmpstr = substring(#tmpstr, #pos + 1, len(#tmpstr))
SET #pos = charindex(#delimiter, #tmpstr)
END
INSERT #tbl(value) VALUES (ltrim(rtrim(#tmpstr)));
RETURN
END
Now use the following procedure to get the required output:
CREATE PROCEDURE [Report]
#statusValue varchar(200) = '%'
AS
BEGIN
DECLARE #iterator INT = 1;
DECLARE #total INT = 1;
DECLARE #keyword VARCHAR(100) = '';
SELECT ROW_NUMBER() OVER (ORDER BY value) SNo, value keyword
INTO #temp
FROM dbo.stringlist_to_table(#statusValue, '|')
SELECT *
INTO #output
FROM SomeTable
WHERE 1 = 0;
SELECT #total = MAX(SNo), #iterator = MIN(Sno)
FROM #temp
WHILE (#iterator <= #total)
BEGIN
SELECT #keyword = '%' + keyword + '%'
FROM #temp
WHERE SNo = #iterator;
INSERT INTO #output
SELECT *
FROM SomeTable
WHERE Something LIKE #keyword
SET #iterator = #iterator + 1;
END
SELECT *
FROM #output;
DROP TABLE #output, #temp;
END
You need the split function in this case. As there is no way to handle what you need. Another approach to add many variables. But in your case it will be enough to create split function and use it to parse your string. Please find the split function below:
CREATE FUNCTION [dbo].[ufnSplitInlineStringToParameters] (
#list NVARCHAR(MAX)
,#delim NCHAR(1) = ','
)
RETURNS TABLE
AS
RETURN
WITH csvTbl(START, STOP) AS (
SELECT START = CONVERT(BIGINT, 1)
,STOP = CHARINDEX(#delim, #list + CONVERT(NVARCHAR(MAX), #delim))
UNION ALL
SELECT START = STOP + 1
,STOP = CHARINDEX(#delim, #list + CONVERT(NVARCHAR(MAX), #delim), STOP + 1)
FROM csvTbl
WHERE STOP > 0
)
SELECT LTRIM(RTRIM(CONVERT(NVARCHAR(4000), SUBSTRING(#list, START, CASE
WHEN STOP > 0
THEN STOP - START
ELSE 0
END)))) AS VALUE
FROM csvTbl
WHERE STOP > 0
GO
One of the simplest way to achieve this is using a custom type. Sample snippet as follows:
CREATE TYPE dbo.StatusList
AS TABLE
(
statusValue varchar(200)
);
GO
CREATE PROCEDURE [Report]
#statusValue AS dbo.StatusList READONLY
AS
BEGIN
SELECT * FROM SomeTable
WHERE Something IN (SELECT * FROM #statusValue)
END
GO
--EDIT---
If you are using SSMS, you can execute the procedure as follows:
DECLARE #status dbo.StatusList
INSERT INTO #status VALUES('Pending')
EXEC [Report] #status

How to split string on two characters or delimiters in sql

i'm trying to split this string "1,1_5,2_3,4" first on '_' and then split the sub string on ',' so it will be like "1,1_5,2_3,4" split-ed on '_' first so it will give this sub string "1,1" then this sub string split-ed on ',' and then insert the split-ed sub string "1 1" into temp table like this
INSERT INTO [dbo].[TEST] ([X],[Y])
VALUES (#X,#Y)
i did this with only split on one delimiter ',' like this
first i create a table Split function
ALTER FUNCTION [dbo].[Split]
(
-- Add the parameters for the function here
#RowData nvarchar(2000),
#SplitOn nvarchar(5)
)
RETURNS #RtnValue table
(
Id int identity(1,1),
Data nvarchar(100)
)
AS
BEGIN
-- Declare the return variable here
Declare #Cnt int
Set #cnt = 1
While(charindex(#SplitOn,#RowData) > 0)
Begin
Insert Into #RtnValue (data)
Select
Data = ltrim(RTRIM(SUBSTRING(#RowData,1,CHARINDEX(#SplitOn,#RowData)-1)))
set #RowData = SUBSTRING(#RowData,CHARINDEX(#SplitOn,#RowData)+1,len(#RowData))
set #Cnt = #Cnt + 1
End
insert into #RtnValue(data)
select Data = ltrim(RTRIM(#RowData))
RETURN
END
then i create this stored procedure
ALTER PROCEDURE [dbo].[uspTest]
-- Add the parameters for the stored procedure here
#StringOFXIDs nvarchar(2000)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #SOMETABLE TABLE(ID INT IDENTITY(1,1) UNIQUE, XID INT);
DECLARE #XCOUNT INT;
DECLARE #XCURRENT INT;
DECLARE #XCOUNTER INT = 1;
-- Insert statements for procedure here
INSERT INTO #SOMETABLE([XID])
SELECT [Data] FROM [dbo].[Split](#StringOFXIDs,',');
SELECT #XCOUNT = COUNT(1) FROM #SOMETABLE;
WHILE (#XCOUNTER <= #XCOUNT)
BEGIN
SELECT #XCOUNTER = [XID]
FROM #SOMETABLE
WHERE [ID] = #XCOUNTER
INSERT INTO [dbo].[TEST] ([X])
VALUES (#XCOUNTER)
SELECT #XCOUNTER +=1;
END
END
--EXEC [dbo].[uspTest] '1,2,3,4'
and then execute this stored procedure and every thing work but i can't figure out how to split the string on two characters or delimiters and then inserted to temp table thanks for any help in advance.
You can use XML functionality to split into rows, then split into columns:
DECLARE #string VARCHAR(100) = '1,1_5,2_3,4'
;WITH cte AS (SELECT RTRIM(LTRIM(Split.a.value('.', 'VARCHAR(100)'))) AS Txt
,ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS RN
FROM (SELECT CAST ('<M>' + REPLACE(#string, '_', '</M><M>') + '</M>' AS XML) AS DATA
) AS A
CROSS APPLY Data.nodes ('/M') AS Split(a)
)
,cte2 AS (SELECT CONVERT(XML,'<String><Section>'+ REPLACE(REPLACE(Txt ,'|',','),',', '</Section><Section>') + '</Section></String>') AS Txt
,RN
FROM cte
)
SELECT Txt.value('/String[1]/Section[1]','varchar(100)') AS Col1
,Txt.value('/String[1]/Section[2]','varchar(100)') AS Col2
FROM cte2
ORDER BY RN
Outputs:
Col1 Col2
---------------
1 1
5 2
3 4

convert string into int SQL Server

This is the scenario:
My app will have the following:
A listbox (The checkbox property enabled) that will display a list of Something.
The user will select from the listbox (multiselect) by using the checkbox.
I will loop into All the checked items and store the ID's into an array. I will store the ID's into something like this separating the ID with a comma (1,2,3,4) and then I will use length -1 to delete the last comma.
How can I convert the string 1,2,3,4 into an integer type of data if my stored procedure is like this?
Select * from tblSomething Where ID in (1,2,3,4)
You can use the following SQL function.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CommaSeparatedToString]
(
#psCSString VARCHAR(8000)
)
RETURNS #otTemp TABLE(sID VARCHAR(20))
AS
BEGIN
DECLARE #sTemp VARCHAR(50)
WHILE LEN(#psCSString) > 0
BEGIN
SET #sTemp = LEFT(#psCSString, ISNULL(NULLIF(CHARINDEX(',', #psCSString) - 1, -1),
LEN(#psCSString)))
SET #psCSString = SUBSTRING(#psCSString,ISNULL(NULLIF(CHARINDEX(',', #psCSString), 0),
LEN(#psCSString)) + 1, LEN(#psCSString))
INSERT INTO #otTemp VALUES (#sTemp)
END
RETURN
END
And call in your stored procedure like
Select * from tblSomething
Where ID in (SELECT * FROM CommaSeparatedToString('1,2,3,4'))
You can use the
SELECT CAST(MyVarcharCol AS INT) FROM Table
SELECT CONVERT(INT, MyVarcharCol) FROM Table
refer this link
http://msdn.microsoft.com/en-us/library/ms187928.aspx
You need to create dynamic query for this
e.g you are getting list of values in #values paramter so prepare and run the dynamic query like this
DECLARE #query NVARCHAR(500)
DECLARE #values VARCHAR(200)
SET #values='1,2'
SET #query =N'Select * from tblSomething Where ID in ( ' + #values + ')'
SELECT #query
EXEC #Query
Use this function to split the value:
CREATE FUNCTION [dbo].[udfSplitCSV]
(
#String varchar (max),
#Delimiter varchar (10) = ','
)
RETURNS #ValueTable TABLE ([Row] int IDENTITY(1,1), [Value] varchar(max), [Length] int, [Duplicate] int NULL)
BEGIN
DECLARE #NextString varchar(max)
DECLARE #Pos int
DECLARE #NextPos int
IF #String IS NULL RETURN
--Initialize
SET #NextString = ''
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
WHILE (#Pos <> 0)
BEGIN
SET #NextString = RTrim(LTrim(SubString(#String,1,#Pos - 1)))
INSERT INTO #ValueTable ([Value], [Length]) VALUES (#NextString, Len(#NextString))
SET #String = SubString(#String,#Pos+1,Len(#String))
SET #NextPos = #Pos
SET #Pos = CharIndex(#Delimiter,#String)
END
UPDATE #ValueTable
SET [Duplicate] = X.Duplicate
FROM #ValueTable VT
INNER JOIN (Select [Row], [Value], Row_Number() OVER (Partition By [Value] ORDER BY [Value], [Row]) as Duplicate FROM #ValueTable) X
ON X.[Row] = VT.[Row]
RETURN
END
-- Select * from dbo.udfSplitCSV('a , c b,c, a', ',')
When you are storing a bunch of IDs into the array, store with single quote.
so it will be ('1','2','3').
Then you no need to covert IDs into integer.

Insert multiple rows into temp table with one command in SQL2005

I've got some data in the following format:
-1,-1,-1,-1,701,-1,-1,-1,-1,-1,304,390,403,435,438,439,442,455
I need to insert it into a temp table like this:
CREATE TABLE #TEMP
(
Node int
)
So that I can use it in a comparison with data in another table.
The data above represents separate rows of the "Node" column.
Is there an easy way to insert this data, all in one command?
Also, the data will actually being coming in as seen, as a string... so I need to be able to just concat it into the SQL query string. I can obviously modify it first if needed.
Try something like
CREATE TABLE #TEMP
(
Node int
)
DECLARE #textXML XML
DECLARE #data NVARCHAR(MAX),
#delimiter NVARCHAR(5)
SELECT #data = '-1,-1,-1,-1,701,-1,-1,-1,-1,-1,304,390,403,435,438,439,442,455 ',
#delimiter = ','
SELECT #textXML = CAST('<d>' + REPLACE(#data, #delimiter, '</d><d>') + '</d>' AS XML)
INSERT INTO #TEMP
SELECT T.split.value('.', 'nvarchar(max)') AS data
FROM #textXML.nodes('/d') T(split)
SELECT * FROM #TEMP
DROP TABLE #TEMP
You can create a query dynamically like this:
declare #sql varchar(1000)
set #sql = 'insert into #TEMP select ' + replace(#values, ',', ' union all select ')
exec #sql
As always when creating queries dynamically, you have to be careful so that you only use trusted data.
I would create a function that would return a table variable and then join that function into the select
Use:
select * from myTable a
inner join dbo.buildTableFromCSV('1,2,3') on a.id = b.theData
Here is my function for doing this
CREATE FUNCTION [dbo].[buildTableFromCSV] ( #csvString varchar(8000) ) RETURNS #myTable TABLE (ID int identity (1,1), theData varchar(100))
AS BEGIN
DECLARE #startPos Int -- position to chop next block of chars from
DECLARE #currentPos Int -- position to current character we're examining
DECLARE #strLen Int
DECLARE #c char(1) -- current subString
-- variable initalization
-- -------------------------------------------------------------------------------------------------------------------------------------------------
SELECT #csvString = #csvString + ','
SELECT #startPos = 1
SELECT #currentPos = 1
SELECT #strLen = Len(#csvString)
-- loop over string and build temp table
-- -------------------------------------------------------------------------------------------------------------------------------------------------
WHILE #currentPos <= #strLen BEGIN
SET #c = SUBSTRING(#csvString, #currentPos, 1 )
IF ( #c = ',' ) BEGIN
IF ( #currentPos - #startPos > 0 ) BEGIN
INSERT
INTO #myTable ( theData )
VALUES ( CAST( SUBSTRING ( #csvString, #startPos, #currentPos - #startPos) AS varchar ) )
END
ELSE
begin
INSERT
INTO #myTable ( theData )
VALUES ( null )
end
SELECT #startPos = #currentPos + 1
END
SET #currentPos = #currentPos + 1
END
delete from #myTable where theData is null
return
END