SQL/Sybase database not returning results - sql

I am passing a variable to the database that contains a list of companies... the var is passing but the database is not returning a result. How do I pass the list? and what kind of Where statement would I use?

If we are passing a comma seperated list to a stored procedure to retrieve a number of records that have one of these strings as a value in a field we use a SQL function. This function returns a table wich can be used to filter the data.
This is our function (you should execute the create before using it)
CREATE FUNCTION [dbo].[GetTableFromString]
(
#string NVARCHAR(4000),
#separator CHAR
)
RETURNS #resultTable TABLE (string NVARCHAR(255))
AS
BEGIN
DECLARE #myString NVARCHAR(255)
IF (LEN(#string) > 0)
BEGIN
DECLARE #start INT,
#charIndex INT
SET #start = 1
SET #charIndex = CHARINDEX(#separator, #string, #start) -- Get the position of the first seperator
WHILE ( #charIndex >= 0 )
BEGIN
IF #charIndex = 0 -- No seperator found, take the whole string and insert it in the result table
BEGIN
SELECT #myString = SUBSTRING(#string, #start, LEN(#string) - #start + 1)
SET #charIndex = -1
END
ELSE
BEGIN
SELECT #myString = SUBSTRING(#string, #start, CHARINDEX(#separator, #string, #start) - #start)
SET #start = CHARINDEX(#separator, #string, #start) + 1 -- Set the start position of the char after the seperator
SET #charIndex = CHARINDEX(#separator, #string, #start) -- Get the position of the next seperator
END
INSERT INTO #ResultTable (string) VALUES (#myString)
END
END
RETURN
END
This is how the function then can be used:
SELECT YourField1,
YourField2,
...
FROM YourTableName
WHERE YourFieldx In ( SELECT string
FROM dbo.GetTableFromString('IBM,WalMart,KMart', ','))

I think you need to post what you're doing.
It sounds almost as if you had a VARCHAR variable containing a comma separated list to a stored procedure, in which case the SP would need to use dynamic sql, but I can't tell.

Related

Split string by two delimiters into two columns

I have a string value which has numeric values separated by comma and then by a pipe. I want to split them into a table with two columns. I could split the string by one delimiter but unfortunately couldn't find a way to split by two. Please help.
DECLARE #list NVARCHAR(MAX) = '1,101|2,202|3,303';
The result should be like below.
1 101
2 202
3 303
Thanks in advance.
If you're using SQL Server 2016 or Azure, you have access to the new SPLIT_STRING function. If not I recommend using Jeff Moden's DelimitedSplit8K function, which is widely regarded as the fastest, most efficient SQL based string splitter available...
DECLARE #list NVARCHAR(MAX) = '1,101|2,202|3,303';
SELECT
Col1 = LEFT(dsk.Item, sl.SplitLocation - 1),
Col2 = SUBSTRING(dsk.Item, sl.SplitLocation + 1, LEN(dsk.Item))
FROM
dbo.DelimitedSplit8K(#list, '|') dsk -- code for DelimitedSplit8K can be found here... http://www.sqlservercentral.com/articles/Tally+Table/72993/
CROSS APPLY ( VALUES (ISNULL(NULLIF(CHARINDEX(',', dsk.Item, 1), 0), 1)) ) sl (SplitLocation);
CREATE FUNCTION [dbo].[fn_Split_char](#text nvarchar(max), #delimiter varchar(20) = ' ')
RETURNS #Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value nvarchar(max)
)
AS
BEGIN
DECLARE #index int
SET #index = -1
WHILE (LEN(#text) > 0)
BEGIN
SET #index = CHARINDEX(#delimiter , #text)
IF (#index = 0) AND (LEN(#text) > 0)
BEGIN
INSERT INTO #Strings VALUES (#text)
BREAK
END
IF (#index > 1)
BEGIN
INSERT INTO #Strings VALUES (LEFT(#text, #index - 1))
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
ELSE
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
RETURN
END
Select LEFT(value, Charindex(',', value) - 1) ,
RIGHT(value, Charindex(',', Reverse(value)) - 1) ,
* from [fn_Split_char] ('1,101|2,202|3,303', '|')
Use xml path and cross apply to create multiple rows for a single row based on the pipe separator and then use substring w.r.t the commas to derive two desired columns
Create table #temp(list nvarchar(max))
Insert into #temp values('1,101|2,202|3,303')
SELECT
Substring(Tbl.Col.value('./text()[1]','varchar(50)'),1,1)as col1,
Substring(Tbl.Col.value('./text()[1]','varchar(50)'),charindex(',',Tbl.Col.value('./text()[1]','varchar(50)'),1)+1,len(Tbl.Col.value('./text()[1]','varchar(50)')))
FROM
(Select cast('<a>'+ replace((SELECT list As [*] FOR XML PATH ('')), '|', '</a><a>') + '</a>' as xml)as t
from #temp) tl
Cross apply
tl.t.nodes('/a') AS Tbl(Col)
Try using this Table-valued Function, embed this SP to your main SP
ALTER FUNCTION [dbo].[delimiter]
(
#PARAM_IDS AS VARCHAR(MAX)
#PARAM_DELIMITER AS CHAR(1)
)
RETURNS
#NEW_TABLE TABLE
(
NUM INT NOT NULL IDENTITY,
ID INT NOT NULL
)
AS
BEGIN
DECLARE #NEXTSTRING AS NVARCHAR(MAX);
DECLARE #POS AS INT;
DECLARE #STRING AS NVARCHAR(MAX);
DECLARE #DELIMITER AS NVARCHAR(MAX);
SET #STRING = #PARAM_IDS;
SET #DELIMITER = #PARAM_DELIMITER;
SET #STRING = #STRING + #DELIMITER;
SET #POS = CHARINDEX(#DELIMITER,#STRING);
WHILE (#POS <> 0)
BEGIN
SET #NEXTSTRING = SUBSTRING(#STRING,1,#POS - 1);
INSERT #NEW_TABLE (ID) VALUES (#NEXTSTRING);
SET #STRING = SUBSTRING(#STRING,#POS+1,len(#STRING));
SET #POS = CHARINDEX(#DELIMITER,#STRING);
END
RETURN
END
then example of use
SET #DETAILS_COUNT = (SELECT COUNT(*) FROM delimiter(#PARAM_MS_UNIT_ID, #DELIMITER));

SSRS Report: get parameter data value and store it into variable in dataset

I have multi-valued parameter in my Report named #Animal which has ('Cat', 'Dog', 'Mouse').
inside dataset i need to get 'Cat', Dog', 'Mouse' and store it into #AnimalName table variable.
"Hard-Coded" way would be:
DECLARE #AnimalName TABLE (Name nvarchar (10))
INSERT INTO #AnimalName SELECT ('Cat');
INSERT INTO #AnimalName SELECT ('Dog');
INSERT INTO #AnimalName SELECT ('Mouse');
I know that I can use #Animal directly inside my dataset, the reason I'm doing this is because I'm trying to improve my report's performance. Many multi-valued parameters will make the report runs forever.
Does any one know how(the syntax) to get #Animal data values and stored it into a table variables #AnimalName inside dataset?
Thanks heaps!
Pass the comma delimited string into your stored procedure and in your stored proc use a table valued function to convert you multi-valued parameter into a table.
CREATE PROC GetAllAnimals
#AnimalList nvarchar(max)
AS
DECLARE #Animals TABLE (Animal nvarchar(10))
INSERT INTO #Animals SELECT * FROM dbo.fnGetValueListFromMultiSelect(#AnimalList)
and then use the #Animals table to inner join in your query
Functions declared below.
For Integer (or ID) values
CREATE FUNCTION [dbo].[fnGetIdListFromMultiSelect](#String nvarchar(MAX))
RETURNS #Results TABLE ([Id] int)
AS
BEGIN
DECLARE #Delimiter CHAR(1)
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
IF #String IS NULL RETURN
SET #Delimiter = ','
SET #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
BEGIN
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
END
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results([Id]) VALUES(CAST(#SLICE AS INT))
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END
For string values
CREATE FUNCTION [dbo].[fnGetValueListFromMultiSelect](#String nvarchar(MAX))
RETURNS #Results TABLE ([Item] nvarchar(128) Primary Key)
AS
BEGIN
DECLARE #Delimiter CHAR(1)
DECLARE #INDEX INT
DECLARE #SLICE nvarchar(4000)
SET #Delimiter = ','
SET #INDEX = 1
WHILE #INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT #INDEX = CHARINDEX(#Delimiter,#STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF #INDEX !=0
BEGIN
SELECT #SLICE = LEFT(#STRING,#INDEX - 1)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT #STRING = RIGHT(#STRING,LEN(#STRING) - #INDEX)
END
ELSE
SELECT #SLICE = #STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO #Results([Item]) VALUES(#SLICE)
-- BREAK OUT IF WE ARE DONE
IF LEN(#STRING) = 0 BREAK
END
RETURN
END

Select * from table where column = (any value from a comma delimited string)

The user selects various words from a drop down list and these values get added into a comma delimited string. When passing the string to a stored procedure I want it to select * from a table where that word exists.
Table
id----word
1-----cat
2-----dog
3-----mouse
4-----dog
string that is passed into the stored procedure is cat, dog so returning columns 1, 2 and 4.
Is there a way of doing this in sql server?
Use IN:
SELECT *
FROM your_table
WHERE word IN ('cat', 'dog')
you first need to make a function SplitCSV :
CREATE FUNCTION [dbo].[SplitCSV] (#CSVString VARCHAR(8000), #Delimiter CHAR(1))
RETURNS #temptable TABLE (items VARCHAR(8000))
AS
BEGIN
DECLARE #pos INT;
DECLARE #slice VARCHAR(8000);
SELECT #pos = 1;
IF LEN(#CSVString) < 1 OR #CSVString IS NULL RETURN;
WHILE #pos!= 0
BEGIN
SET #pos = CHARINDEX(#Delimiter,#CSVString);
IF #pos != 0
SET #slice = LEFT(#CSVString, #pos - 1);
ELSE
SET #slice = #CSVString;
IF( LEN(#slice) > 0)
INSERT INTO #temptable(Items) VALUES (#slice);
SET #CSVString = RIGHT(#CSVString, LEN(#CSVString) - #pos);
IF LEN(#CSVString) = 0 BREAK;
END
RETURN
END
GO
then you can use it like :
SELECT *
FROM myTable
WHERE ID IN (
SELECT items FROM [dbo].[SplitCSV]('1,2,3,4,5', ',')
)
SELECT *
FROM Table
WHERE '%,' + Word + ',%' LIKE ',' + #your_csv_param + ','
Extra commas at the begin and end of parameter and column are to prevent search to match cat with catfish for example.
If you want select all animal except mouse , you can use NOT IN
SELECT * FROM
TABLE
WHERE Word Not IN('Mouse')
So you can avoid type many type of animal
CREATE FUNCTION
ALTER FUNCTION [dbo].[fn_Split](#text varchar(8000), #delimiter varchar(20) = ' ')
RETURNS #Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value varchar(8000)
)
AS
BEGIN
DECLARE #index int
SET #index = -1
WHILE (LEN(#text) > 0)
BEGIN
SET #index = CHARINDEX(#delimiter , #text)
IF (#index = 0) AND (LEN(#text) > 0)
BEGIN
INSERT INTO #Strings VALUES (#text)
BREAK
END
IF (#index > 1)
BEGIN
INSERT INTO #Strings VALUES (LEFT(#text, #index - 1))
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
ELSE
SET #text = RIGHT(#text, (LEN(#text) - #index))
END
RETURN
END
----
select * from yourtable where column in ( select value from fn_Split(#para1,',')

HOW to convert CSV to record set inside T-SQL?

In my stored procedure I am passing a filter (using "WHERE Column IN" clause) as a parameter. The value of the parameter is given as CSV. What is the best method to convert this CSV in to a record set.
Example:-
SELECT *
FROM Employee
WHERE Name IN ('John','Joe','Jerry','James')
and I need to pass the names as a parameter which is a CSV string like
"John,Joe,Jerry,James"
.
Take a look at Erland Sommarskog's articles. He has in-depth information on the different ways of doing this kind of thing:
Arrays and Lists in SQL Server
Create a split string function
CREATE FUNCTION [dbo].[SplitString]
(
#String VARCHAR(MAX) ,
#Delimiter VARCHAR(10)
)
RETURNS #RetTable TABLE(
String varchar(MAX)
)
AS
BEGIN
DECLARE #i INT ,
#j INT
SELECT #i = 1
WHILE #i <= LEN(#String)
BEGIN
SELECT #j = CHARINDEX(#Delimiter, #String, #i)
IF #j = 0
BEGIN
SELECT #j = LEN(#String) + 1
END
INSERT #RetTable SELECT SUBSTRING(#String, #i, #j - #i)
SELECT #i = #j + LEN(#Delimiter)
END
RETURN
END

How can I get the almost last substring from "/" delimited string in T-SQL?

If I've got a string that consists of other strings delimited with "/" character (xxx...xxx/xxx/xxxx) how can I get the last and the almost last (the one before last) part with t-sql? It should probably be some combination of charindex() and right().
declare #s varchar(50);
set #s = 'aaaaa/bbbbb/ccccc/ddddd/eeeee'
/* last one: */
select
RIGHT(#s, CHARINDEX('/', REVERSE(#s)) - 1)
/* penultimate one */
select
RIGHT(
LEFT(#s, LEN(#s) - CHARINDEX('/', REVERSE(#s))),
CHARINDEX('/', REVERSE(
LEFT(#s, LEN(#s) - CHARINDEX('/', REVERSE(#s)))
)) - 1
)
The "last one" is pretty straightforward, no explanation needed.
The "penultimate one" is essentially equal to the "last one", with all occurrences of #s replaced with:
LEFT(#s, LEN(#s) - CHARINDEX('/', REVERSE(#s)))
which produces 'aaaaa/bbbbb/ccccc/ddddd'
To check whether there are enough slashes in the string for this expression to succeed, you could do
CASE WHEN LEN(#s) - LEN(REPLACE(#s, '/', '')) >= 2
THEN /* expression here */
ELSE /* error value here */
END
You could replace the '/' with a '.' and use PARSENAME.
Here's a SO answer using it: Split String in SQL
Parsename is only good when you have 4 or less delimited pieces....here is my solution:
CREATE FUNCTION Piece(#string as varchar(1000),#delimiter as char(1),#piece as int)
RETURNS varchar(1000)
AS
BEGIN
declare #Items table (Piece int,Item varchar(8000) NOT NULL)
declare #return varchar(1000)
DECLARE #Item As varchar(1000), #Pos As int
DECLARE #piecenum AS int
SET #piecenum=1
WHILE DATALENGTH(#string)>0
BEGIN
SET #Pos = CHARINDEX(#delimiter,#string)
IF #Pos = 0 SET #Pos = DATALENGTH(#string)+1
SET #Item = LTRIM(RTRIM(LEFT(#string,#Pos-1)))
IF #Item<>'' INSERT INTO #Items SELECT #piecenum, #Item
SET #piecenum=#piecenum+1
SET #string=SUBSTRING(#string,#Pos+DATALENGTH(#delimiter),1000)
END
SELECT #return=Item FROM #Items WHERE Piece=#piece
RETURN #return
END
so:
select dbo.Piece('a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q',',',10)
results in 'j'