how to select using multiple LIKE clauses that are constructed dynamically in MSSQL - sql

I have a Table Family like the following
Family_Name | Family_Members_Age
Johnson | 45,60,56
Ken | 78,67,40
David | 40
Here is a proc I have
CREATE PROCEDURE getFamilyRowsByAge #Age nvarchar(30)
AS
SELECT *
FROM Family
WHERE Family_members_age LIKE FILL_IN -- need to get this fill_in dynamically
The #Age param is supplied with comma separated String like 45,67.
FILL_IN would be something like this for input String of "45,67" LIKE '%45%' OR LIKE '%67%'. I want this to be dynamically created by splitting input String for comma and joining with LIKE OR. Is there a way in MSSQL to do this?
Output:
Johnson | 45,60,56
Ken | 78,67,40
Here is another input and output:
input : 40, 67, 69
Output:
Johnson | 45,60,56
Ken | 78,67,40
David | 40

Based on those comments, try this:
USE tempdb;
GO
DROP TABLE IF EXISTS dbo.Family;
GO
CREATE TABLE dbo.Family
(
FamilyID int IDENTITY(1,1)
CONSTRAINT PK_dbo_Family PRIMARY KEY,
Family_Name varchar(100),
Family_Members_Age varchar(max)
);
GO
INSERT dbo.Family (Family_Name, Family_Members_Age)
VALUES ('Johnson', '45,60,56'),
('Ken', '78,67,40'),
('David', '40');
GO
CREATE PROCEDURE dbo.GetFamilyRowsByAge
#RequiredAges varchar(100)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
WITH FamilyAges
AS
(
SELECT f.Family_Name, fma.Age
FROM dbo.Family AS f
CROSS APPLY (SELECT value AS Age FROM STRING_SPLIT(f.Family_Members_Age,',')) AS fma
)
SELECT fa.Family_Name, fa.Age
FROM FamilyAges AS fa
WHERE fa.Age IN (SELECT value FROM STRING_SPLIT(#RequiredAges, ','));
END;
GO
EXEC dbo.GetFamilyRowsByAge '45,67,40';
GO

You can achieve it by this simple way, Live demo here
strSplit
CREATE FUNCTION [dbo].[strSplit] ( #string nvarchar( MAX), #splitter CHAR( 1) )
RETURNS #res TABLE (id INT PRIMARY KEY, rank INT, val nvarchar( MAX) )
AS
BEGIN
IF SUBSTRING ( #string, len ( #string), 1)<>#splitter
SET #string= #string+#splitter
DECLARE #start INT, #word nvarchar(MAX), #charindex INT, #i INT
SET #i=1
SET #start=1
SET #charindex= CHARINDEX( #splitter, #string, #start)
WHILE (#charindex <> 0)BEGIN
SET #word= SUBSTRING( #string, #start, #charindex - #start)
SET #start= #charindex +1
SET #charindex= CHARINDEX( #splitter, #string, #start)
INSERT INTO #res VALUES ( #start, #i, #word)
SET #i=#i+1
END
RETURN
END
ContainString
CREATE FUNCTION [dbo].[ContainString] (#string1 nvarchar( MAX), #string2 nvarchar( MAX))
RETURNS BIT
AS
BEGIN
IF(EXISTS(SELECT TOP 1 a.val From strSplit(#string1, ',') a
INNER JOIN strSplit(#string2, ',') b on a.val = b.val ))
BEGIN
RETURN 1
END
RETURN 0
END
Select result
SELECT * FROM Family WHERE [dbo].ContainString(Family_Members_Age, '45,67') = 1
SELECT * FROM Family WHERE [dbo].ContainString(Family_Members_Age, '40,67,69') = 1

The whole query within the proc will need to be dynamic. Then you can use something like STRING_SPLIT (2016 or later) to pull apart the comma-delimited value and build the string.
However, I'm unconvinced that's what you need. If you use LIKE, how are you going to avoid %9% matching a value like 91 ?
You might want to consider normalizing the table correctly instead. Why are there 3 ages within a single column? Why not just store it as 3 rows?

Probably you need something like this .
SELECT 'Johnson'Family_Name,'45,60,56' Family_Members_Age
into #YourTable
union all select 'Ken','78,67,40'
union all select 'David','40'
DECLARE #WhereQuery varchar(250)='40, 67, 69', #Query nvarchar(250)
select #Query = 'select * from #YourTable'
SET #WhereQuery = ' WHERE Family_Members_Age LIKE ''%'+ REPLACE (#WhereQuery,',','%'' OR Family_Members_Age LIKE ''%') + '%'''
SET #Query = #Query + #WhereQuery
EXEC SP_EXECUTESQL #Query

Related

split one value to multiple value

I have a variable I want split it into two different column on the basis of ~ tild and after split I want Again split with , Comma
Like Below
declare #Remarks varchar(100) = 'Product1~2,Product2~1'
I have split function After using Split function
select value from fn_split(#Remarks,',')
My result is
value
Product1~2
Product2~1
But I want result Like
value Qty
Product1 2
Product2 1
Disclaimer: You can use the fn_split function, I am just not using it because of my version of SQL.
I know of no way to split into separate columns or than manually, so you can use a couple substring functions to accomplish what you are trying to do.
#Remarks varchar(100) = 'Product1~2,Product2~1', #Delimiter VARCHAR(1) = ','
DECLARE #Products TABLE(Product VARCHAR(MAX))
;WITH Split_CTE (startPostion, endPosition)
AS (
SELECT CAST(0 AS INT) AS startPostion
,CHARINDEX(#Delimiter, #Remarks) AS endPosition
UNION ALL
SELECT endPosition + 1
,CHARINDEX(#Delimiter, #Remarks, endPosition + 1)
FROM Split_CTE
WHERE endPosition > 0
)
INSERT INTO #Products
SELECT SUBSTRING(#Remarks,startPostion, COALESCE(NULLIF(endPosition,0),LEN(#Remarks) + 1) - startPostion) AS [Data]
FROM Split_CTE
SELECT SUBSTRING([Product], CHARINDEX('~', [Product]) + 1, LEN([Product])) AS Id
,SUBSTRING([Product], 0, CHARINDEX('~', [Product])) AS Product
FROM #Products
There's also a way to do this using XML that you might find interesting:
DECLARE #Remarks varchar(100) = 'Product1~2,Product2~1'
-- set up some variables for customizing the delimiters and parsing into XML
DECLARE #xml as xml
,#str as varchar(100)
,#str2 as varchar(100)
,#delimiter as varchar(10)
,#delimiter2 as varchar(10)
-- initialize using the values you provided
SET #delimiter ='~'
SET #delimiter2 =','
SET #str = #Remarks
-- convert your string to XML
SET #str2 = ('<val>'+replace(#str,#delimiter ,'</val><qty>')+'</qty>')
SET #xml = cast(('<rec>'+replace(#str2,#delimiter2 ,'</qty></rec><rec><val>')+'</rec>') as xml)
-- SQL using XQuery
SELECT
ref.value('val[1]', 'varchar(10)') AS value,
ref.value('qty[1]', 'varchar(10)') AS quantity
FROM #xml.nodes('/rec')
xmlData( ref )
And the result:
value quantity
---------- ----------
Product1 2
Product2 1
(2 row(s) affected)

SQL - Replacing all "ASCII/special characters" in a string

Edit: I have about 80 characters that are causing problems in my application so I don't want to hard code a REPLACE for every single character. I think it would be easier to create a separate table with two columns,"special characters" and "replacement characters", and I will remove those columns from the original table which contains the column "StringTest". My goal will be figuring out how to use the characters table to replace characters in the string table.
I am trying to replace all "special characters" (ie À, Æ, Ç) with "MappedCharacters" (A, AE, C) in SQL Server. I have tried two different techniques, one using a cursor, one without a cursor, to search through a string and replace all special characters with mapped characters. Each of my methods only replaces characters they are in the same row as the string.
Example before:
num SpecialCharacter MappedCharacter StringTest
1 À A StringÀÆ
2 Æ AE ÆStringÆ
3 Ç C StrÇÀing
Example after:
num SpecialCharacter MappedCharacter StringTest
1 À A StringAÆ
2 Æ AE AEStringAE
3 Ç C StrCÀing
Preferred Output:
num SpecialCharacter MappedCharacter StringTest
1 À A StringAAE
2 Æ AE AEStringAE
3 Ç C StrCAing
So you can see that I want to replace all "special characters" in StringTest but only characters that are in the same row are getting replaced.
I haven't quite figured out how to do that just yet.
Here are the two SQL code that I have been trying to modify (I only need one to work)
First Method:
DECLARE #cASCIINum INT;
DECLARE #cSpecialChar VARCHAR(50);
DECLARE #cMappedChar VARCHAR(50);
DECLARE #cStringTest VARCHAR(50);
DECLARE #mapCursor as CURSOR;
SET #mapCursor = CURSOR FOR
SELECT [ASCIINum]
,[SpecialChar]
,[MappedChar]
,[StringTest]
FROM [intranet].[dbo].[CharMapTestTab];
OPEN #mapCursor;
FETCH NEXT FROM #mapCursor INTO #cASCIINum,
#cSpecialChar,
#cMappedChar,
#cStringTest;
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE [intranet].[dbo].[CharMapTestTab]
SET StringTest = REPLACE(StringTest, SpecialChar, MappedChar)
WHERE SpecialChar <> MappedChar
END
CLOSE #mapCursor;
DEALLOCATE #mapCursor;
Second Method:
DECLARE #ASCIINum INT = 0
WHILE (1 = 1)
BEGIN
SELECT #ASCIINum = ASCIINum
FROM [intranet].[dbo].[CharMapTestTab]
WHERE ASCIINum > #ASCIINum
ORDER BY ASCIINum
IF ##ROWCOUNT = 0 BREAK;
UPDATE [intranet].[dbo].[CharMapTestTab]
SET StringTest = REPLACE(StringTest, SpecialChar, MappedChar)
WHERE SpecialChar <> MappedChar
SELECT TOP 1000 [ASCIINum]
,[SpecialChar]
,[MappedChar]
,[StringTest]
FROM [intranet].[dbo].[CharMapTestTab]
END
Try this, it works better than looping because there is only 1 update:
-- create test table vc
create table vc(StringTest varchar(20))
insert vc values('StringÀÆ'), ('ÆStringÆ')
go
-- create test table CharacterMapping
create table CharacterMapping(SpecialCharacter char(1), MappedCharacter varchar(2))
insert CharacterMapping values('À', 'A'),('Æ', 'AE'), ('Ç', 'C')
go
--build the varchar for updating
declare #x varchar(max) = 'StringTest'
select #x = 'replace('+#x+', ''' + SpecialCharacter + ''','''+MappedCharacter+''')'
from CharacterMapping
set #x = 'update vc set StringTest=' + #x +' from vc'
exec (#x)
select * from vc
Result:
StringAAE
AEStringAE
I would make a separate mapping table which contains the bad character and its corresponding good character, one set per row. Then loop over that table and do a replace for each character set.
DECLARE #map TABLE (
id INT,
badChar CHAR,
goodChar CHAR
)
DECLARE #strings TABLE (
searchString VARCHAR(50)
)
INSERT INTO #map
VALUES
(1, 'y', 'a'),
(2, 'z', 'b')
DECLARE #curRow INT, #totalRows INT
SET #curRow = 1
SELECT #totalRows = COUNT(*) FROM #map
INSERT INTO #strings
VALUES
('zcccyccz'),
('cccyccz')
WHILE #curRow <= #totalRows
BEGIN
UPDATE #strings
SET searchString = REPLACE(searchString, badChar, goodChar)
FROM #map
WHERE id = #curRow
SET #curRow = #curRow + 1
END
SELECT * FROM #strings
--Output
--bcccaccb
--cccaccb
It would be helpful to know how many rows are in your table and how many you estimate to have "special characters". Also, are there only 3 special characters? if you have 40 or less special characters, it may look ridiculous, but I'd just nest as many REPLACE() calls as you have special characters, like:
UPDATE YourTable SET YourColumn = REPLACE(
REPLACE(
REPLACE(YourColumn,'Ç','C')
,'Æ','AE')
,'À','A')
if most rows have special characters, I'd skip any WHERE. if only a few rows have special characters, I'd use a CTE to identify them:
;WITH AllSpecialRows AS
(
SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%À%'
UNION
SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%Æ%'
UNION
SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%Ç%'
)
UPDATE y
SET YourColumn = REPLACE(
REPLACE(
REPLACE(YourColumn,'Ç','C')
,'Æ','AE')
,'À','A')
FROM YourTable y
INNER JOIN AllSpecialRows s ON y.PrimaryKey =s.PrimaryKey
update table
set column = REPLACE(column,'À','A')
where column like ('%À%')
update table
set column = REPLACE(column,'Æ','AE')
where column like ('%Æ%')
I will leave the 3rd to you
Or this might be more efficient
update table
set column = REPLACE(REPLACE(column,'À','A'),'Æ','AE')
where column like ('%À%')
or column like ('%Æ%')
If you really want to process a list of mapped characters then this is not a proper answer
#t-clausen.dk answer with Table variables and temp tables, just to avoid people mess up their dev databases with additional tables.
TABLE Variables:
-- Create test table variable #CharacterMapping
DECLARE #CharacterMapping TABLE (SpecialCharacter char(1), MappedCharacter varchar(2))
INSERT #CharacterMapping VALUES('À', 'A'), ('Æ', 'AE'), ('Ç', 'C')
--Build the varchar for updating
DECLARE #x varchar(max) = 'StringTest'
SELECT #x = 'replace('+#x+', ''' + SpecialCharacter + ''',''' + MappedCharacter + ''')'
FROM #CharacterMapping
SET #x = 'DECLARE #vc TABLE(StringTest varchar(20));'
+ ' insert #vc values(''StringÀÆ''), (''ÆStringÆ'');'
+ 'update #vc set StringTest=' + #x +' from #vc;'
+ 'SELECT * FROM #vc;'
Exec (#x)
GO
With Temp table:
-- Create test temp table #vc
CREATE TABLE #vc(StringTest varchar(20))
INSERT #vc VALUES('StringÀÆ'), ('ÆStringÆ')
-- Create test table CharacterMapping
DECLARE #CharacterMapping TABLE (SpecialCharacter char(1), MappedCharacter varchar(2))
INSERT #CharacterMapping VALUES('À', 'A'), ('Æ', 'AE'), ('Ç', 'C')
--Build the varchar for updating
DECLARE #x varchar(max) = 'StringTest'
SELECT #x = 'replace('+#x+', ''' + SpecialCharacter + ''',''' + MappedCharacter + ''')'
FROM #CharacterMapping
SET #x = 'update #vc set StringTest=' + #x +' from #vc'
-- Execute
EXEC (#x)
-- Select the results
SELECT * FROM #vc;
-- Drop temp table
DROP TABLE #vc;
GO

Dynamically Create tables and Insert into it from another table with CSV values

Have a Table with the CSV Values in the columns as below
ID Name text
1 SID,DOB 123,12/01/1990
2 City,State,Zip NewYork,NewYork,01234
3 SID,DOB 456,12/21/1990
What is need to get is 2 tables in this scenario as out put with the corresponding values
ID SID DOB
1 123 12/01/1990
3 456 12/21/1990
ID City State Zip
2 NewYork NewYork 01234
Is there any way of achieving it using a Cursor or any other method in SQL server?
There are several ways that this can be done. One way that I would suggest would be to split the data from the comma separated list into multiple rows.
Since you are using SQL Server, you could implement a recursive CTE to split the data, then apply a PIVOT function to create the columns that you want.
;with cte (id, NameItem, Name, textItem, text) as
(
select id,
cast(left(Name, charindex(',',Name+',')-1) as varchar(50)) NameItem,
stuff(Name, 1, charindex(',',Name+','), '') Name,
cast(left(text, charindex(',',text+',')-1) as varchar(50)) textItem,
stuff(text, 1, charindex(',',text+','), '') text
from yt
union all
select id,
cast(left(Name, charindex(',',Name+',')-1) as varchar(50)) NameItem,
stuff(Name, 1, charindex(',',Name+','), '') Name,
cast(left(text, charindex(',',text+',')-1) as varchar(50)) textItem,
stuff(text, 1, charindex(',',text+','), '') text
from cte
where Name > ''
and text > ''
)
select id, SID, DOB
into table1
from
(
select id, nameitem, textitem
from cte
where nameitem in ('SID', 'DOB')
) d
pivot
(
max(textitem)
for nameitem in (SID, DOB)
) piv;
See SQL Fiddle with Demo. The recursive version will work great but if you have a large dataset, you could have some performance issues so you could also use a user defined function to split the data:
create FUNCTION [dbo].[Split](#String1 varchar(MAX), #String2 varchar(MAX), #Delimiter char(1))
returns #temptable TABLE (colName varchar(MAX), colValue varchar(max))
as
begin
declare #idx1 int
declare #slice1 varchar(8000)
declare #idx2 int
declare #slice2 varchar(8000)
select #idx1 = 1
if len(#String1)<1 or #String1 is null return
while #idx1 != 0
begin
set #idx1 = charindex(#Delimiter,#String1)
set #idx2 = charindex(#Delimiter,#String2)
if #idx1 !=0
begin
set #slice1 = left(#String1,#idx1 - 1)
set #slice2 = left(#String2,#idx2 - 1)
end
else
begin
set #slice1 = #String1
set #slice2 = #String2
end
if(len(#slice1)>0)
insert into #temptable(colName, colValue) values(#slice1, #slice2)
set #String1 = right(#String1,len(#String1) - #idx1)
set #String2 = right(#String2,len(#String2) - #idx2)
if len(#String1) = 0 break
end
return
end;
Then you can use a CROSS APPLY to get the result for each row:
select id, SID, DOB
into table1
from
(
select t.id,
c.colname,
c.colvalue
from yt t
cross apply dbo.split(t.name, t.text, ',') c
where c.colname in ('SID', 'DOB')
) src
pivot
(
max(colvalue)
for colname in (SID, DOB)
) piv;
See SQL Fiddle with Demo
You'd need to approach this as a multi-step ETL project. I'd probably start with exporting the two types of rows into a couple staging tables. So, for example:
select * from yourtable /* rows that start with a number */
where substring(text,1,1) in
('0','1','2','3','4','5','6','7','8','9')
select * from yourtable /* rows that don't start with a number */
where substring(text,1,1)
not in ('0','1','2','3','4','5','6','7','8','9')
/* or simply this to follow your example explicitly */
select * from yourtable where name like 'sid%'
select * from yourtable where name like 'city%'
Once you get the two types separated then you can split them out with one of the already written split functions found readily out on the interweb.
Aaron Bertrand (who is on here often) has written up a great post on the variety of ways to split comma delimted strings using SQL. Each of the methods are compared and contrasted here.
http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings
If your row count is minimal (under 50k let's say) and it's going to be a one time operation than pick the easiest way and don't worry too much about all the performance numbers.
If you have a ton of rows or this is an ETL process that will run all the time then you'll really want to pay attention to that stuff.
A simple solution using cursors to build temporary tables. This has the limitation of making all columns VARCHAR and would be slow for large amounts of data.
--** Set up example data
DECLARE #Source TABLE (ID INT, Name VARCHAR(50), [text] VARCHAR(200));
INSERT INTO #Source
(ID, Name, [text])
VALUES (1, 'SID,DOB', '123,12/01/1990')
, (2, 'City,State,Zip', 'NewYork,NewYork,01234')
, (3, 'SID,DOB', '456,12/21/1990');
--** Declare variables
DECLARE #Name VARCHAR(200) = '';
DECLARE #Text VARCHAR(1000) = '';
DECLARE #SQL VARCHAR(MAX);
--** Set up cursor for the tables
DECLARE cursor_table CURSOR FAST_FORWARD READ_ONLY FOR
SELECT s.Name
FROM #Source AS s
GROUP BY Name;
OPEN cursor_table
FETCH NEXT FROM cursor_table INTO #Name;
WHILE ##FETCH_STATUS = 0
BEGIN
--** Dynamically create a temp table with the specified columns
SET #SQL = 'CREATE TABLE ##Table (' + REPLACE(#Name, ',', ' VARCHAR(50),') + ' VARCHAR(50));';
EXEC(#SQL);
--** Set up cursor to insert the rows
DECLARE row_cursor CURSOR FAST_FORWARD READ_ONLY FOR
SELECT s.Text
FROM #Source AS s
WHERE Name = #Name;
OPEN row_cursor;
FETCH NEXT FROM row_cursor INTO #Text;
WHILE ##FETCH_STATUS = 0
BEGIN
--** Dynamically insert the row
SELECT #SQL = 'INSERT INTO ##Table VALUES (''' + REPLACE(#Text, ',', ''',''') + ''');';
EXEC(#SQL);
FETCH NEXT FROM row_cursor INTO #Text;
END
--** Display the table
SELECT *
FROM ##Table;
--** Housekeeping
CLOSE row_cursor;
DEALLOCATE row_cursor;
DROP TABLE ##Table;
FETCH NEXT FROM cursor_table INTO #Name;
END
CLOSE cursor_table;
DEALLOCATE cursor_table;

sql search from csv string

im doing a search page where i have to search multiple fields with a single textbox.
so i will get the search text as a CSV string in my stored procedure
My table is as below
ID Name age
5 bob 23
6 bod.harry 34
7 charles 44
i need a sql query something like this
declare #searchtext='bob,harry,charley'
select * from employee where name like (#searchtext)
this query should return both this records (id 5 and 6)
You can use this way in Stored Procedure,
declare #searchtext varchar(1000)
set searchtext ='bob,harry,charley'
declare #filter varchar(2000)
set #filter = '(name LIKE ''%' + replace('bob,harry,charley',',','%'' OR name LIKE ''%') + '%'')'
exec
('
select *
from mytab
where ' + #filter + '
'
)
Use (or adapt) this splitting function:
ALTER FUNCTION [dbo].CsvToList(#SplitOn char(1), #List varchar(8000))
RETURNS TABLE
AS
RETURN
(
SELECT
ROW_NUMBER() OVER(ORDER BY number) AS RowNumber
,LTRIM(RTRIM(SUBSTRING(ListValue, number+1, CHARINDEX(#SplitOn, ListValue, number+1)-number - 1))) AS ListValue
FROM (
SELECT #SplitOn + #List + #SplitOn AS ListValue
) AS InnerQuery
INNER JOIN master.dbo.spt_values n ON n.Number < LEN(InnerQuery.ListValue)
WHERE SUBSTRING(ListValue, number, 1) = #SplitOn
AND n.type = 'P'
);
GO
usage
declare #searchtext='bob,harry,charley'
select DISTINCT * from employee e
JOIN dbo.csvToList(',', #searchtext) f
ON f.ListValue = e.name
You'll need to break #searchtext into multiple strings, one for each name. It's doable in TSQL but may be easier in your application code. You can then compare those with your Name field.
If I'm not mistaken Sql-Server doesn't support Regex. You can use table valued parameters. If you are using Entity framework the you could do so.
var dc = new MyContext();
var result = dc.employees.Where(x => new [] { "bob", "harry", "charley" }.Contains(x.name));
and finally you might construct the following
select * from employee where name in (#Param1, #Param2, #Param3, #Param4)
EDIT
I highly discourage you to use CSV because of the performance drop (you have to parse your csv) and possibility of errors (consider this csv Foo,Bar,"Foo with, comma","comma, "" and quote")
P.S. If you use table valued parameter when you assign the value use DataTable as source.
The above version of [dbo].CsvToList does not work with long input string with a lot of separators. Table spt_values where type='P' has limited number of records. In my case the function returned 16 rows instead of 66. Some advise to create your own table with numbers. I used a different version of this function I copied from other place:
CREATE FUNCTION [dbo].[fngCsvToList](#SplitOn char(1), #List varchar(8000))
RETURNS #Result TABLE (ListValue varchar(100))
AS
BEGIN
DECLARE #str VARCHAR(20)
DECLARE #ind Int
IF(#List is not null)
BEGIN
SET #List = REPLACE(REPLACE(REPLACE(LTRIM(RTRIM(#List)), CHAR(10), ''), CHAR(13), ''), CHAR(9), '')
SET #ind = CharIndex(#SplitOn, #List)
WHILE #ind > 0
BEGIN
SET #str = SUBSTRING(#List, 1, #ind-1)
SET #List = SUBSTRING(#List, #ind+1, LEN(#List)-#ind)
INSERT INTO #Result values (LTRIM(RTRIM(#str)))
SET #ind = CharIndex(',',#List)
END
SET #str = #List
INSERT INTO #Result values (LTRIM(RTRIM(#str) ))
END
RETURN
END

Split string and return data in multiple columns

First of all many thanks to the site creator and most importantly helping guru's on this site.
I have the same problem splitting string from a field and displaying it in multiple columns example my table has got three columns
dbo.tests
Fname ID wTest Loc
ABC 1 "XYZ,PTO,LKMD,HGGFFD," R1
BCE 2 "PTO,XYZ,LKMD,," R1
LKJ 3 "XYZ" R3
JKL 4 "XYZ,PTO,LKMD,HGGFFD,PKL" R2
The output for the select statement should display the data as follows: (Dynamically generate number of columns based on maximum columns required from wTest string and fill the empty columsn with null or some value.
Returns:
Fname ID Loc wTest wTest1 wTest2,wTest3,Wtest4...
ABC 1 R1 XYZ PTO LKMD HGGFFD Null
BCE 2 R1 PTO XYZ LKMD Null Null
LKJ 3 R3 XYZ Null Null Null Null
JKL 4 R2 XYZ PTO LKMD HGGFFD PKL
Two close function I came accross are as follows:
CREATE FUNCTION dbo.Split (#sep char(1), #s varchar(512))
RETURNS table AS RETURN
(
WITH Pieces (pn, start, stop) AS
(
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1,
CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0 )
SELECT pn, SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s FROM Pieces )
with testTable AS
( SELECT 1 AS Id, N'how now brown cow' AS txt
UNION ALL
SELECT 2, N'she sells sea shells upon the sea shore' UNION ALL
SELECT 3, N'red lorry yellow lorry' UNION ALL
SELECT 4, N'the quick brown fox jumped over the lazy dog' )
SELECT display_term, COUNT(*) As Cnt
FROM testTable CROSS APPLY sys.dm_fts_parser('"' + txt + '"', 1033, 0,0)
GROUP BY display_term
HAVING COUNT(*) > 1 ORDER BY Cnt DESC
Any help in this regard is highly appreciated.
Zain...
zainali2006#hotmail.co.uk
Someone suggested this, but I am having difficulties applying for my purpose....
Returns #Tbl_IDs
Table (Id int identity(1,1),
Data Varchar(500)) As
Begin
--Remove the leading delimiter if any
while (substring(#IDs,1,1) =#Delimiter)
set #IDs = substring(#IDs, 2,len(#IDs)-1)
-- Append comma
--Set #IDs = #IDs + #Delimiter
set #IDs = REPLACE(RTRIM(LTRIM(REPLACE(#IDs,#Delimiter,' '))),' ',#Delimiter)
-- Indexes to keep the position of searching
Declare #Pos1 Int
Declare #pos2 Int
Declare #RowNum Int
-- Start from first character
Set #Pos1=1
Set #Pos2=1
While #Pos1>0
Begin
Set #Pos1 = CharIndex(#Delimiter,#IDs,#Pos1)
Insert #Tbl_IDs Values (Substring(#IDs,#Pos2,#Pos1-#Pos2))
-- Go to next non comma character
Set #Pos2=#Pos1+1
-- Search from the next charcater
Set #Pos1 = #Pos1+1
End
Return
End
Another one I came across quite interesting and simple but not sure how to use in my select statement:
DECLARE #NextString NVARCHAR(40)
DECLARE #Pos INT
DECLARE #NextPos INT
DECLARE #String NVARCHAR(40)
DECLARE #Delimiter NVARCHAR(40)
SET #String ='SQL,TUTORIALS,,TCF'
SET #Delimiter = ','
SET #String = #String + #Delimiter
SET #Pos = charindex(#Delimiter,#String)
WHILE (#pos <> 0)
BEGIN
SET #NextString = substring(#String,1,#Pos - 1)
SELECT #NextString -- Show Results
SET #String = substring(#String,#pos+1,len(#String))
SET #pos = charindex(#Delimiter,#String)
END