In SQL Server , I want to separate string from '~' - sql

I have problem. There are A~B~C~D values in my table.
I want separate this string like 'A' and 'B~C'.
And I could separate 'A' using this function
SELECT SUBSTRING(Item.Description, 0, CHARINDEX('~', Item.Description)) As Com
But after that, I can't separate 'B~C'.
Of course if I use SUBSTRING and CHARINDEX a lot, I can separate.
But it is very complicated.
So I wonder if I can use other ways.
Thx very much for reading

Here is a short SQL function that you can create in order to split your string:
CREATE FUNCTION dbo.Split (#sep char(1), #s varchar(8000))
RETURNS table
AS
RETURN (
WITH splitter_cte AS (
SELECT CHARINDEX(#sep, #s) as pos, 0 as lastPos
UNION ALL
SELECT CHARINDEX(#sep, #s, pos + 1), pos
FROM splitter_cte
WHERE pos > 0
)
SELECT SUBSTRING(#s, lastPos + 1,
case when pos = 0 then 80000
else pos - lastPos -1 end) as chunk
FROM splitter_cte
)
GO
And here is how you would use it:
SELECT * FROM dbo.Split('~', 'A~B~C~D')
OUTPUT:
chunk
-------------
A
B
C
D
Read more on how this sql split function works

Related

sql string split for defined number of char

i've a string like 'aabbcczx' and i need to split that string by 2 char.
The result expected is something like:
aabbcczx aa
aabbcczx bb
aabbcczx cc
aabbcczx zx
How can I do this?
consider also that the length of the string change row by row.
Thanks
If it's always 2 chars:
SELECT A.Val,
CA1.N,
SUBSTRING(A.Val,n,2)
FROM (
VALUES ('aabbcczx')
) AS A(Val)
CROSS
APPLY dbo.GetNums(1,LEN(A.Val)) AS CA1
WHERE CA1.n % 2 = 1;
GetNums is a number table/tally table generator you can find some several sources online.
It will provide the position of each character and we can use that in the substring start position. The where clause uses MOD to so we only show every other starting position
You can use a recursive query:
with cte as (
select convert(varchar(max), left(str, 2)) as val2, convert(varchar(max), stuff(str, 1, 2, '')) as rest, str
from (values ( 'aabbcczx' )) v(str)
union all
select left(rest, 2) as val2, stuff(rest, 1, 2, '') as rest, str
from cte
where rest <> ''
)
select str, val2
from cte;
You can use a recursive query to extract pairs of characters:
with instring as
( select 'aabbcczx' as s )
, splitter as
(
select s, substring(s, 1, 2) as rslt, 3 as next -- first two chars
from instring
union all
select s, substring(s, next, 2), next + 2 -- next two chars
from splitter
where len(s) >= next
)
select *
from splitter
See dbfiddle

Extract part of string in SQL that is between two character but there are multiple of same characters

I'm trying to extract part of a string that is between two characters, the string looks like -
EXAMPLE/EXMPL/BBASIC/EXAMPLE/EXAMPLE
The text I am trying to move to a separate column is the 4th section of text between the 3rd and 4th '/' (in bold)
Without knowing the DBMS, I'm not sure if there is a built-in split function or not. SQL Server 2008 R2 does not have a split function, so I do it this way:
declare #str varchar(max) = 'example/example/bbasic/eXaMpLe/example', #delim char(1) = '/'
;with vars(id, _start, _end) as
(
select 1, cast(1 as bigint), charindex(#delim, #str)
union all
select id + 1, _end + 1, charindex(#delim, #str, _end + 1)
from vars
where _end > 0
)
select id, cast(substring(#str, _start, case when _end > 0 then _end - _start else len(#str) - _start + 1 end) as varchar(max)) as value
from vars
where id = 4
option (MAXRECURSION 0)
Using where id = 4 means pull the 4th element after the 3rd / delimiter. This SQL returns:
id value
--- --------
4 eXaMpLe

Split the query string with repeatative special characters using SQL

This is my String
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
I want to extract the values of empid,empname,adminname,term,teamid,contactid,WP,Months,Dueday,StrDt,MemCatgmStrTm,PlnHrs,WrkDays and assign them to new variables
I have used
select ( SUBSTRING(#qstr,CHARINDEX('=',#qstr)+1,CHARINDEX('&',#qstr)-CHARINDEX('=',#qstr)-1)))
but only getting the 'empemail' , for the next occurance of special char '&' , not able to get the values of further terms , if i am using '&' in spite of '=' .
Help me to split the whole string
How about using XML to split the values into rows, and then splitting them into columns.
Something like
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
DECLARe #str VARCHAR(MAX) = SUBSTRING(#qstr,CHARINDEX('?',#qstr,0) + 1, LEN(#qstr)-CHARINDEX('?',#qstr,0))
DECLARE #xml XML
SELECT #xml = CAST('<d>' + REPLACE(#str, '&', '</d><d>') + '</d>' AS XML)
;WITH Vals AS (
SELECT T.split.value('.', 'nvarchar(max)') AS data
FROM #xml.nodes('/d') T(split)
)
SELECT LEFT(data,CHARINDEX('=',data,0) - 1),
RIGHT(data,LEN(data) - CHARINDEX('=',data,0))
FROM Vals
SQL Fiddle DEMO
CREATE FUNCTION dbo.SplitQueryString (#s varchar(8000))
RETURNS table
AS
RETURN (
WITH splitter_cte AS (
SELECT CHARINDEX('&', #s) as pos, 0 as lastPos
UNION ALL
SELECT CHARINDEX('&', #s, pos + 1), pos
FROM splitter_cte
WHERE pos > 0
),
pair_cte AS (
SELECT chunk,
CHARINDEX('=', chunk) as pos
FROM (
SELECT SUBSTRING(#s, lastPos + 1,
case when pos = 0 then 80000
else pos - lastPos -1 end) as chunk
FROM splitter_cte) as t1
)
SELECT substring(chunk, 0, pos) as keyName,
substring(chunk, pos+1, 8000) as keyValue
FROM pair_cte
)
GO
declare #queryString varchar(2048)
set #queryString = 'foo=bar&temp=baz&key=value';
SELECT *
FROM dbo.SplitQueryString(#queryString)
OPTION(MAXRECURSION 0);
when run produces the following output.
keyName keyValue
------- --------
foo bar
temp baz
key value
(3 row(s) affected)
I believe that this will do exactly what you are asking.
SQL FIDDLE DEMO
If the order of the values in the html string remains same i would suggest using the whole string name like
select ( SUBSTRING(#qstr,CHARINDEX('empemail=',#qstr)+1,CHARINDEX('&empid=',#qstr)-CHARINDEX('empemail=',#qstr)-1)))
If you are still looking for nth occurance then refer to this link
Declare #qstr as varchar(max)='hireteammember.aspx?empemail=kuldeep#asselsolutions.com&empid=376&empname=kuldeep&adminname=TMA1&term=5&teamid=161&contactid=614¥1&WP=100¥5¥Months&Amt=500&DueDay=5&StrDt=12/31/2013&MemCatg=Employees&StrTm=21:05&PlnHrs=5&WrkDays=true¥true¥true¥true¥true¥false¥false'
(select ( SUBSTRING(#qstr,CHARINDEX('&empname=',#qstr)+1,CHARINDEX('&adminname=',#qstr)-CHARINDEX('&empname=',#qstr)-1)))
(select ( SUBSTRING(#qstr,CHARINDEX('?empemail=',#qstr)+1,CHARINDEX('&empid=',#qstr)-CHARINDEX('?empemail=',#qstr)-1)))
like this i have splitted and updated The whole string. Thank you All for your answers, Your answers Helped me to solve this

SQL Count distinct values within the field

I have this weird scenario (at least it is for me) where I have a table (actually a result set, but I want to make it simpler) that looks like the following:
ID | Actions
------------------
1 | 10,12,15
2 | 11,12,13
3 | 15
4 | 14,15,16,17
And I want to count the different actions in the all the table. In this case, I want the result to be 8 (just counting 10, 11, ...., 17; and ignoring the repeated values).
In case it matters, I am using MS SQL 2008.
If it makes it any easier, the Actions were previously on XML that looks like
<root>
<actions>10,12,15</actions>
</root>
I doubt it makes it easier, but somebody might comeback with an xml function that I am not aware and just makes everything easier.
Let me know if there's something else I should say.
Using approach similar to http://codecorner.galanter.net/2012/04/25/t-sql-string-deaggregate-split-ungroup-in-sql-server/:
First you need a function that would split string, there're many examples on SO, here's one of them:
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
)
Using this you can run a simple query:
SELECT COUNT(DISTINCT S) FROM MyTable CROSS APPLY dbo.Split(',', Actions)
Here is the demo: http://sqlfiddle.com/#!3/5e706/3/0
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE Table1
([ID] int, [Actions] varchar(11))
;
INSERT INTO Table1
([ID], [Actions])
VALUES
(1, '10,12,15'),
(2, '11,12,13'),
(3, '15'),
(4, '14,15,16,17')
;
Query 1:
DECLARE #S varchar(255)
DECLARE #X xml
SET #S = (SELECT Actions + ',' FROM Table1 FOR XML PATH(''))
SELECT #X = CONVERT(xml,'<root><s>' + REPLACE(#S,',','</s><s>') + '</s></root>')
SELECT count(distinct [Value])
FROM (
SELECT [Value] = T.c.value('.','varchar(20)')
FROM #X.nodes('/root/s') T(c)) AS Result
WHERE [Value] > 0
Results:
| COLUMN_0 |
|----------|
| 8 |
EDIT :
I think this is exactly what you are looking for :
SQL Fiddle
MS SQL Server 2008 Schema Setup:
Query 1:
DECLARE #X xml
SELECT #X = CONVERT(xml,replace('
<root>
<actions>10,12,15</actions>
<actions>11,12,13</actions>
<actions>15</actions>
<actions>14,15,16,17</actions>
</root>
',',','</actions><actions>'))
SELECT count(distinct [Value])
FROM (
SELECT [Value] = T.c.value('.','varchar(20)')
FROM #X.nodes('/root/actions') T(c)) AS Result
Results:
| COLUMN_0 |
|----------|
| 8 |
A bit if a mess but here it is Create the function first and then call the lower code.
/* Helper Function */
CREATE FUNCTION dbo.Split (#sep char(1), #s varchar(8000))
RETURNS table
AS
RETURN (
WITH splitter_cte AS (
SELECT CHARINDEX(#sep, #s) as pos, 0 as lastPos
UNION ALL
SELECT CHARINDEX(#sep, #s, pos + 1), pos
FROM splitter_cte
WHERE pos > 0
)
SELECT SUBSTRING(#s, lastPos + 1,
case when pos = 0 then 80000
else pos - lastPos -1 end) as chunk
FROM splitter_cte
)
GO
---------------- End of Function
/* Function Call */
Declare #Actions varchar(1000)
SELECT #Actions = STUFF((SELECT ',' + actions
FROM tblActions
ORDER BY actions
FOR XML PATH('')), 1, 1, '')
SELECT Distinct *
FROM dbo.Split(',', #Actions)
OPTION(MAXRECURSION 0);
If you have a table of Actions with one row per possible action id, you can do this with a join:
select count(distinct a.ActionId)
from t join
Actions a
on ','+t.Actions+',' like '%,'+cast(a.ActionId as varchar(255))+',%';
You could also create a table of numbers (using a CTE) if you know the actions are within some range.

SQL: How to split a column of type varchar?

I have a table that has a column named 'languages', but it has the following types of values :
english; polish; portuguese;
.. etc.
I want to split so I can insert it in another table as:
english
polish
portugese
And go on.
I already searched in Google and find this split function:
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
)
I already tested it with this :
SELECT * FROM dbo.Split(' ', 'I hate bunnies')
So I tried to adapt this to my case :
INSERT INTO labbd11..language(language) SELECT s FROM dbo.Split(';', disciplinabd..movies.languages)
Then it gives me this exception:
The multi-part identifier "disciplinabd..movies.languages" could not be bound. Severity 16
Any ideas ?
Best regards,
Valter Henrique.
Use CROSS APPLY
INSERT INTO labbd11..language(language)
SELECT DISTINCT s.s
FROM disciplinabd..movies m
CROSS APPLY dbo.Split(';', m.languages) S
But if I read your query correctly, you are splitting the languages from ALL movies, and inserting the resultant languages from the movie into the language table (1 column only). Hope this is a test query, otherwise it has no business merit at all.