T-SQL - remove chars from string beginning from specific character - sql

from table I retrieves values, for example,
7752652:1,7752653:2,7752654:3,7752655:4
or
7752941:1,7752942:2
i.e. string may contain any quantity of substrings.
What I need: remove all occurrences of characters from char ':' to a comma char.
For example,
7752652:1,7752653:2,7752654:3,7752655:4
should be
7752652,7752653,7752654,7752655
How do it?

Replace : with start tag <X>.
Replace , with end tag </X> and an extra comma.
Add an extra end tag to the end </X>.
That will give you a string that look like 7752941<X>1</X>,7752942<X>2</X>.
Cast to XML and use query(text()) to get the root text values.
Cast the result back to string.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table T
(
C varchar(100)
)
insert into T values
('7752652:1,7752653:2,7752654:3,7752655:4'),
('7752941:1,7752942:2')
Query 1:
select cast(cast(replace(replace(T.C, ':', '<X>'), ',', '</X>,')+'</X>' as xml).query('text()') as varchar(100)) as C
from T
Results:
| C |
|---------------------------------|
| 7752652,7752653,7752654,7752655 |
| 7752941,7752942 |

declare #query varchar(8000)
select #query= 'select '+ replace (
replace('7752652:1,7752653:2,7752654:3,7752655:4',',',' t union all select ')
,':',' t1 , ')
exec(';with cte as ( '+#query+' ) select cast(t1 as varchar)+'','' from cte for xml path('''')')

Try this:
DECLARE #Data VARCHAR(100) = '7752652:1,7752653:2,7752654:3,7752655:4'
DECLARE #Output VARCHAR(100) = ''
WHILE CHARINDEX(':', #Data) > 0
BEGIN
IF LEN(#Output) > 0 SET #Output = #Output + ','
SET #Output = #Output + LEFT(#Data, CHARINDEX(':', #Data)-1)
SET #Data = STUFF(#Data,
1,
(CASE CHARINDEX(',', #Data)
WHEN 0 THEN LEN(#Data)
ELSE CHARINDEX(',', #Data)
END) - CHARINDEX(':', #Data),
'')
END
SELECT #Output AS Result -- 7752652,7752653,7752654,7752655

Hope this will help.
I borrowed the Splitter function from here. You could use any delimiter parser you may already be using.
Parse the string to table values
Used Substring function to remove values after ':'
Use For xml to re-generate CSV
Test Data:'
IF OBJECT_ID(N'tempdb..#temp')>0
DROP TABLE #temp
CREATE TABLE #temp (id int, StringCSV VARCHAR(500))
INSERT INTO #temp VALUES ('1','7752652:1,7752653:2,7752654:3,7752655:4')
INSERT INTO #temp VALUES ('2','7752656:1,7752657:3,7752658:4')
INSERT INTO #temp VALUES ('3','7752659:1,7752660:2')
SELECT * FROM #temp t
Main Query:
;WITH cte_Remove(ID, REMOVE) AS
(
SELECT y.id AS ID,
SUBSTRING(fn.string, 1, CHARINDEX(':', fn.string) -1) AS Removed
FROM #temp AS y
CROSS APPLY dbo.fnParseStringTSQL(y.StringCSV, ',') AS fn
)
SELECT DISTINCT ID,
STUFF(
(
SELECT ',' + REMOVE
FROM cte_Remove AS t2
WHERE t2.ID = t1.ID
FOR XML PATH('')
),1,1,'') AS col2
FROM cte_Remove AS t1
Cleanup Test Data:
IF OBJECT_ID(N'tempdb..#temp') > 0
DROP TABLE #temp

I solved this problem with CLR function. It is more quickly and function can be used in complex queries
public static SqlString fnRemoveSuffics(SqlString source)
{
string pattern = #":(\d+)";
string replacement = "";
string result = Regex.Replace(source.Value, pattern, replacement);
return new SqlString(result);
}

Related

Transform a SELECT * query to string

I have a query that returns a row
SELECT *
FROM table
WHERE id = 1;
I want to save the result into a nvarchar sql variable. I have seen similar questions Convert SQL Server result set into string but they only use select with the name of the columns, never with *.
select *
from table
where id = 1
for xml path ('')
However the answer is <column1>value1</column1> <column2>value2</column2> and I just want it to be value1, value2
Is there a way to achieve this? thank you!
If open to a helper function.
This will convert virtually any row, table or query to a string (delimited or not).
In the following examples I selected a PIPE delimiter with a CRLF line terminator.
Please note the usage and placement of _RN when a line terminator is required. Also note the ,ELEMENTS XSINIL ... this will included null values as empty string. If you want to exclude null values, simply omit the ,ELEMENTS XSINIL
Example as Entire Table or dbFiddle
Declare #YourTable Table (id int,[col_1] varchar(50),[col_2] varchar(50),[col_3] varchar(50),[col_n] varchar(50)) Insert Into #YourTable Values
(1,'data1','data2','data3','data4')
,(2,'data5','data6','data7','data8')
-- Entire Table
Declare #XML xml = (Select *,_RN=Row_Number() over (Order By (Select null)) From #YourTable for XML RAW,ELEMENTS XSINIL )
Select [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),#XML)
Returns
1|data1|data2|data3|data4
2|data5|data6|data7|data8
Example as Row Based
Select A.ID
,AsAString = [dbo].[svf-str-Data-To-Delimited]('|',char(13)+char(10),B.XMLData)
From #YourTable A
Cross Apply ( values ( (select a.* for xml RAW,ELEMENTS XSINIL )) )B(XMLData)
Returns
ID AsAString
1 1|data1|data2|data3|data4
2 2|data5|data6|data7|data8
The Function if Interested
CREATE Function [dbo].[svf-str-Data-To-Delimited] (#Delim varchar(50),#EOL varchar(50),#XML xml)
Returns varchar(max)
Begin
Return(
Select convert(nvarchar(max),(
Select case when Item='_RN' then ''
else case when nullif(lead(Item,1) over (Order by Seq),'_RN') is not null
then concat(Value,#Delim)
else concat(Value,#EOL)
end
end
From (
Select Seq = row_number() over(order by (select null))
,Item = xAttr.value('local-name(.)', 'nvarchar(100)')
,Value = xAttr.value('.','nvarchar(max)')
From #XML.nodes('/row/*') xNode(xAttr)
) A
Order By Seq
For XML Path (''),TYPE).value('.', 'nvarchar(max)') )
)
End
You can easily store the result as an XML string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for xml path ('');
Or as a JSON string:
select *
from (values (1, 'x', getdate())) v(id, a, b)
where id = 1
for json auto;
If you don't mind Using dynamic SQL (and INFORMATION_SCHEMA dictionary), for example, for SQL Server this works:
DECLARE #sql nvarchar(max) = '',
#result nvarchar(max),
#id int = 1
SELECT #sql += '+'',''+convert(nvarchar,' + QUOTENAME(column_name) +')' from INFORMATION_SCHEMA.columns where table_name = 'Student'
SET #sql = 'select #result=' + stuff(#sql,1,5,'') + ' from student where id = ' + CAST(#id as nvarchar)
EXECUTE sp_executesql #sql, N'#result nvarchar(max) OUTPUT', #result=#result OUTPUT
SELECT #result as MyOutput

How to separate a string and insert into table?

My question is that I have a string like this
Red,House|White,Car|Blue,Table
and I want insert this elements in different rows like this
- Col1 Col2
- -----------
- Red House
- White Car
- Blue Table
How can I do it?
maybe this is what are you looking for.
SELECT Substring(value, 1,Charindex(',', value)-1) as col1
, Substring(value, Charindex(',', value)+1, LEN(value)) as col2
FROM STRING_SPLIT('Red,House|White,Car|Blue,Table', '|')
works since SQL Server 2016
You can try this query.
DECLARE #str VARCHAR(500) = 'Red,House|White,Car|Blue,Table'
CREATE TABLE #Temp (tDay VARCHAR(100))
WHILE LEN(#str) > 0
BEGIN
DECLARE #TDay VARCHAR(100)
IF CHARINDEX('|',#str) > 0
SET #TDay = SUBSTRING(#str,0,CHARINDEX('|',#str))
ELSE
BEGIN
SET #TDay = #str
SET #str = ''
END
INSERT INTO #Temp VALUES (#TDay)
SET #str = REPLACE(#str,#TDay + '|' , '')
END
SELECT *
FROM #temp
SELECT tday,
PARSENAME(REPLACE(tday,',','.'),2) 'Col1' ,
PARSENAME(REPLACE(tday,',','.'),1) 'Col2'
FROM #temp
You can check the live demo Here.
I go with using string_split() or a similar string splitter function which you can add to your database. However, I would phrase the final extract logic as:
select left(s.value, v.split - 1),
stuff(s.value, 1, v.split, '')
from string_split('Red,House|White,Car|Blue,Table', '|') s cross apply
(values (charindex(',', s.value))) v(split);

Function which takes a column values and convert it into a comma separated values

I want an SQL function which takes a result of a select statement as parameter and return a string of comma separated values for the result. If there is a NULL value then it should leave a space and continue with the result.
I tried using the COALESCE() expression, but this takes out the NULL values and returns only valid values.
declare #str varchar(MAX)
SELECT #str= coalesce(#str + ',', '')+ a.D8_BOOK_YEAR_END
FROM (select D8_BOOK_YEAR_END from CUST_PRODUCT_ACCOUNTS
WHERE CUST_PRODUCT_ID=1) a
print #str
For example: In the image, I need to pass the column NAME into the function and it should return me the values as Mango, ,Apple,Grape.
I want an SQL function which takes a result of a select statement as parameter and return a string of comma separated values for the result. If there is a null value then it should leave a space and continue with the result.
You can do that as
--Create a table (just for test)
CREATE TABLE T(
Str VARCHAR(45)
);
INSERT INTO T VALUES
('One'),
(NULL),
('Two'),
('Three');
-- Create a type
CREATE TYPE MyData AS TABLE (Str NVARCHAR(300));
-- Create the function
CREATE FUNCTION dbo.MyFunc(
#Data MyData READONLY
)
RETURNS NVARCHAR(300)
AS
BEGIN
DECLARE #Result NVARCHAR(300) = N'';
SELECT #Result = STUFF(
(
SELECT ',' + ISNULL(Str, '') --Or ' ' as you like
FROM #Data
FOR XML PATH('')
), 1, 1, ''
);
RETURN (#Result);
END
-- Finally, use it
DECLARE #Test MyData;
INSERT INTO #Test SELECT * FROM T;
SELECT dbo.MyFunc(#Test);
Returns:
+------------------+
| (No column name) |
+------------------+
| One,,Two,Three |
+------------------+
And here is a live demo
DECLARE #TABLE TABLE (
ID INT
,Info VARCHAR(MAX)
)
INSERT INTO #TABLE
VALUES (1,'mango')
INSERT INTO #TABLE
VALUES (1,'apple')
INSERT INTO #TABLE
VALUES (1,null)
INSERT INTO #TABLE
VALUES (1,'grape')
INSERT INTO #TABLE
VALUES (2,'mango1')
INSERT INTO #TABLE
VALUES (2,null)
INSERT INTO #TABLE
VALUES (2,null)
INSERT INTO #TABLE
VALUES (2,'grape1')
SELECT ID
,STUFF((
SELECT ',' + isnull(info, '')
FROM #TABLE T1
WHERE T1.id = T2.ID
FOR XML PATH('')
), 1, 1, '')
FROM #TABLE T2
GROUP BY ID
Use ISNULL(field,' ') somewhere to avoid the NULL value behavior.
You can use SQL Concatenation using XML PATH() method as illustrated with following sample query
SELECT
STUFF(
(
SELECT
',' + [user]
FROM dbo.UserCategoryValues
FOR XML PATH(''),TYPE
).value('.','VARCHAR(MAX)'
), 1, 1, ''
) As concatenated_string
This will take care of NULL values. Those NULLs will not be concatenated in to the list
But you can not wrap this code into a function as dynamic SQL that will take the field name and table name and build a SQL statement dynamically. SQL engine will throw an exception in that case

Different SQL Select query

I need to write SQL query in order to extract some data.
i have this data in my table:
ID Store Value
1 9921 NOK
2 9921 NOK1
3 9921 OK3
what i need is to get data from select query like this form:
9921 NOK,NOK1,OK3
Any help please ?
You can use STUFF:
SELECT DISTINCT Store,
STUFF((SELECT ',' + Value
FROM Your_Table
WHERE Store = 9921
FOR XML PATH('')), 1, 1, '')
FROM Your_Table
Try to accomplish your excepted output by using COALESCE;
Create a sample table for testing purpose
CREATE TABLE SampleData (id INT ,store INT ,value NVARCHAR(50))
INSERT INTO SampleData VALUES (1 ,9921 ,'NOK')
INSERT INTO SampleData VALUES (2 ,9921 ,'NOK1')
INSERT INTO SampleData VALUES (3 ,9921 ,'NOK2')
Create a Scalar-Valued Function
Alter FUNCTION fun_GetCombinedData
(
#store int
)
RETURNS nvarchar(max)
AS
BEGIN
-- Declare the return variable here
DECLARE #CombineValue nvarchar(max)
SELECT #CombineValue = COALESCE(#CombineValue + ', ', '') + value
FROM SampleData where store=#store
RETURN #CombineValue
END
GO
Final Query,
SELECT store
,dbo.fun_GetCombinedData(store) AS value
FROM SampleData
GROUP BY store
Expected Output:
store | value
------------------------
9921 | NOK,NOK1,NOK2
This is one of the way to simplify your select query.
Using T-SQL we can do it this way:
declare #store int = 9921, #values varchar(max) = ''
select #values = #values
+ case
when #values = '' then ''
else ','
end + value
from table_name
where store = #store
order by id
select #store, #values
Go through this below example
Demo: [SQLFiddle]
The SQL I used is as below,
SELECT
store,
STUFF(
(SELECT DISTINCT ',' + value
FROM SampleData
WHERE store = a.store
FOR XML PATH (''))
, 1, 1, '') AS CombineValues
FROM SampleData AS a
GROUP BY store
you will see your expected result as "CombineValues"
store CombineValues
9921 NOK,NOK1,NOK2

Inserting multiple value in table with String input

I am passing one string to store procedure : 1:20,2:30,4:50
It contains id and appropriate value for it.
how can I add value as shown in below table in database.
ID Value
1 20
2 30
4 50
I have already "stringSplit" function which works perfectly and gives out put in row value some think like this :
1:20
2:30
4:50
can anyone please help me to insert data into table with any solution.
i already try this solution
insert <table> (colname)
select y.item
from dbo.SplitString(#testString, ':') x
cross apply
dbo.SplitString(x.item, ',') y
but this will return duplicate value as more as id value.
my store procedure is
CREATE PROCEDURE [dbo].[temp_result_insert]
#dataString varchar(max)
AS
insert into tempTable(id,marks)
select x.Item,y.Item
from dbo.SplitStringVarcahr(#dataString, ':') x
cross apply
dbo.SplitStringVarcahr(x.Item,',') y
RETURN 0
As you already splitted into rows and you want insert into some table by splliting into two columns may be this works
CREATE TABLE #Test(ID INT,Val INT)
declare #t table (val varchar(50))
insert into #t (val)values ('1:20,2:30,4:50')
declare #str varchar(max)
;with cte as (
SELECT
Split.a.value('.', 'VARCHAR(100)') AS String
FROM (SELECT
CAST ('<M>' + REPLACE([val], ',', '</M><M>') + '</M>' AS XML) AS String
FROM #t) AS A CROSS APPLY String.nodes ('/M') AS Split(a))
INSERT INTO #Test
select SUBSTRING(String,0,CHARINDEX(':',String)),REVERSE(SUBSTRING(reverse(String),0,CHARINDEX(':',reverse(String)))) from cte
select * from #test
You can also try XML.nodes() and string functions to spit the data. Something like this
DECLARE #var VARCHAR(100) = '1:20,2:30,4:50'
DECLARE #xml xml = CONVERT(xml, '<r>' + REPLACE(#var,',','</r><r>') + '</r>')
SELECT LEFT(val,cindex - 1) c1,RIGHT(val,LEN(val) - cindex) c2
FROM
(
SELECT CHARINDEX(':',c.value('text()[1]','VARCHAR(100)')) cindex,c.value('text()[1]','VARCHAR(100)') val
FROM #xml.nodes('r') as t(c))c
Use substring and Charindex:
SELECT Substring(col, 0, Charindex(col, ':') - 1) AS id,
Substring(col, Charindex(col, ':') + 1, Len(col)-Charindex(col, ':')) AS value
FROM splittedtable