Split on colons in SQL Server - sql

I have a column in SQL table which would have data like this:
"College: Queenstown College" or "University: University of Queensland"
Text before the ":" could be different. So, how can i select only the text before the ":" from the column and text after the ":(space)"?

You should probably consider putting your table into first normal form rather than storing 2 pieces of data in the same column...
;with yourtable as
(
select 'College: Queenstown College' as col UNION ALL
select 'University: University of Queensland'
)
select
left(col,charindex(': ',col)-1) AS InstitutionType,
substring(col, charindex(': ',col)+2, len(col)) AS InstitutionName
from yourtable

Using the charindex and substring functions:
substring(theField, 1, charindex(':', theField) - 1)

Related

Select chunked data with row number using T-SQL

I have a SQL Server table containing a long text (varchar(max)) column and several key columns. I need to load this data into another table, but break the long text into chunks (varchar(4000)), so each row in the source table may become multiple rows in the target table.
Is there a way using T-SQL which can do this in one select statement and also provide a row_number? Sort of like partition over chunk size, if this makes sense.
Recursive CTE to split the string into 4000 character chunks (as a variation on this comma splitting thread: Turning a Comma Separated string into individual rows)
;WITH cte(SomeID, RowNum, DataItem, String) AS
(
SELECT
SomeID,
1,
LEFT(String, 4000),
case when len(String) > 4000 then
RIGHT(String, LEN(String) - 4000)
else
''
end
FROM myTable
UNION all
SELECT
SomeID,
RowNum + 1,
LEFT(String, 4000),
case when len(String) > 4000 then
RIGHT(String, LEN(String) - 4000)
else
''
end
FROM cte
WHERE
String > ''
)
SELECT *
FROM cte
You can use a recursive subquery:
with cte as (
select left(longtext, 4000) as val, 1 as rn,
stuff(longtext, 1, 4000, '') as rest
from t
union all
select left(rest, 4000), rn + 1,
stuff(longtext, 1, 4000, '') as rest
from cte
where longtext > ''
)
select *
from cte;
You probably want to include other columns as well, but your question doesn't mention them.
Also, if your text is really long (say more than a handful of chunks per row), then this is not going to be the most efficient method. There are related methods using recursive CTEs to solve this.

Convert comma separated string into rows

I have a comma separated string.
Now I'd like to separate this string value into each row.
Input:
1,2,3,4,5
Required output:
value
----------
1
2
3
4
5
How can I achieve this in sql?
Thanks in advance.
Use the STRING_SPLIT function if you are on SQL Server
SELECT value
FROM STRING_SPLIT('1,2,3,4,5', ',')
Else you can loop on the SUBSTRING_INDEX() function and insert every string in a temporary table.
If you are using Postgres, you can use string_to_array and unnest:
select *
from unnest(string_to_array('1,2,3,4,5',',') as t(value);
In Postgres, you can also use the 'regexp_split_to_table()' function.
If you're using MariaDB or MySQL you can use a recursive CTE such as:
with recursive itemtable as (
select
trim(substring_index(data, ',', 1)) as value,
right(data, length(data) - locate(',', data, 1)) as data
from (select '1,2,3,4,5' as data) as input
union
select
trim(substring_index(data, ',', 1)) as value,
right(data, length(data) - locate(',', data, 1)) as data
from itemtable
)

Regex pattern inside REPLACE function

SELECT REPLACE('ABCTemplate1', 'Template\d+', '');
SELECT REPLACE('ABC_XYZTemplate21', 'Template\d+', '');
I am trying to remove the part Template followed by n digits from a string. The result should be
ABC
ABC_XYZ
However REPLACE is not able to read regex. I am using SQLSERVER 2008. Am I doing something wrong here? Any suggestions?
SELECT SUBSTRING('ABCTemplate1', 1, CHARINDEX('Template','ABCTemplate1')-1)
or
SELECT SUBSTRING('ABC_XYZTemplate21',1,PATINDEX('%Template[0-9]%','ABC_XYZTemplate21')-1)
More generally,
SELECT SUBSTRING(column_name,1,PATINDEX('%Template[0-9]%',column_name)-1)
FROM sometable
WHERE PATINDEX('%Template[0-9]%',column_name) > 0
You can use substring with charindex or patindex if the pattern being looked for is fixed.
select SUBSTRING('ABCTemplate1',1, CHARINDEX ( 'Template' ,'ABCTemplate1')-1)
My answer expects that "Template" is enough to determine where to cut the string:
select LEFT('ABCTemplate1', CHARINDEX('Template', 'ABCTemplate1') - 1)
Using numbers table..
;with cte
as
(select 'ABCTemplate1' as string--this can simulate your table column
)
select * from cte c
cross apply
(
select replace('ABCTemplate1','template'+cast(n as varchar(2)),'') as rplcd
from
numbers
where n<=9
)
b
where c.string<>b.rplcd
Using Recursive CTE..
;with cte
as
(
select cast(replace('ABCTemplate21','template','') as varchar(100)) as string,0 as num
union all
select cast(replace(string,cast(num as varchar(2)),'') as varchar(100)),num+1
from cte
where num<=9
)
select top 1 string from cte
order by num desc

using charindex in a substring to trim a string

There is a column name from which I want to use to make a new column.
example:
name
asd_abceur1mz_a
asd_fxasdrasdusd3mz_a
asd_abceur10yz_a
asd_fxasdrasdusd15yz_a
The length of the column is not fixed so I assumed i have to use charindex to have a reference point from which I could trim.
What i want: at the end there is always z_a, and i need to place in a separate column the left part from z_a like this:
nameNew
eur1m
usd3m
eur10y
usd15y
The problem is that the number (in this example 1, 3, 10, 15) has 1 or two digits. I need to extract the information from name to nameNew.
After that i was thinking to make it easier to read and to output it like this:
eur_1m
usd_3m
eur_10y
usd_15y
I tried using a combination of substring and charindex, but so far without success.
SELECT *
, SUBSTRING(name, 1, ( CHARINDEX('z_a', NAME) - 1 )) AS nameNew
FROM myTable
This is for the first step, trimming the string, for the 2nd step (making it easier to read) I don't know how to target the digit and place an _.
Any help would be appreciated. Using sql server 2012
edit:
First of all thank you for your time and solutions. But your queries more or less even if they are working for 1 or 2 digits have the same problem. Consider this situation:
name
ab_dertEUR03EUR10YZ_A
if eur is two times in the string, then how can I eliminate this? Sorry for not includding this in my original post but i forgot that situation is possible and now that's a problem.
edit:
test your queries here, on this example:
http://www.sqlfiddle.com/#!3/21610/1
Please note that at the end it can be any combination of 1 or 2 digits and the letter y or m.
Ex: ab_rtgtEUR03EUR2YZ_A , ab_rtgtEUR03EUR2mZ_A, ab_rtgtEUR03EUR20YZ_A, ab_rtgtEUR03EUR20mZ_A
Some values for testing:
('ex_CHFCHF01CHF10YZ_A'), ('ab_rtgtEUR03EUR2YZ_A'), ('RON_asdRON2MZ_A'),
('tg_USDUSD04USD5YZ_A');
My understanding of your queries is that they perform something simillar to this (or at least they should)
ex_CHFCHF01CHF10YZ_A -> ex_CHFCHF01CHF10Y -> Y01FHC10FHCFHC -> Y01FHC -> CHF01Y -> CHF_01Y
RON_asdRON2MZ_A -> RON_asdRON2M -> M2NORdsa_ron -> M2NOR -> RON2M -> RON_2M
This works for one or two digits:
stuff(case
when name like '%[0-9][0-9]_z[_]a'
then left(right(name, 9), 6)
when name like '%[0-9]_z[_]a'
then left(right(name, 8), 5)
end, 4, 0, '_')
You can use a combination of substring , reverse and charindex.
SQL Fiddle
select substring(namenew,1,3) + '_' + substring(namenew, 4, len(namenew))
from (
select
case when name like '%[0-9][0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 6))
when name like '%[0-9]_z[_]a' then
reverse(substring(reverse(name), charindex('a_z',reverse(name)) + 3, 5))
end as namenew
from myTable
) t
Try it like this:
declare #tbl TABLE(name VARCHAR(100));
insert into #tbl VALUES
('asd_abceur1mz_a')
,('asd_fxasdrasdusd3mz_a')
,('asd_abceur10yz_a')
,('asd_fxasdrasdusd15yz_a')
,('ab_dertEUR03EUR10YZ_A');
WITH CutOfThreeAtTheEnd AS
(
SELECT LEFT(name,LEN(name)-3) AS nameNew
FROM #tbl
)
,Max6CharsFromEnd AS
(
SELECT RIGHT(nameNew,6) AS nameNew
FROM CutOfThreeAtTheEnd
)
SELECT nameNew
,FirstNumber.Position
,Parts.*
,Parts.FrontPart + '_' + Parts.BackPart AS FinalString
FROM Max6CharsFromEnd
CROSS APPLY
(
SELECT MIN(x)
FROM
(
SELECT CHARINDEX('0',nameNew,1) AS x
UNION SELECT CHARINDEX('1',nameNew,1)
UNION SELECT CHARINDEX('2',nameNew,1)
UNION SELECT CHARINDEX('3',nameNew,1)
UNION SELECT CHARINDEX('4',nameNew,1)
UNION SELECT CHARINDEX('5',nameNew,1)
UNION SELECT CHARINDEX('6',nameNew,1)
UNION SELECT CHARINDEX('7',nameNew,1)
UNION SELECT CHARINDEX('8',nameNew,1)
UNION SELECT CHARINDEX('9',nameNew,1)
) AS tbl
WHERE x>0
) AS FirstNumber(Position)
CROSS APPLY(SELECT SUBSTRING(nameNew,FirstNumber.Position,1000) AS BackPart
,SUBSTRING(nameNew,FirstNumber.Position-3,3) AS FrontPart) AS Parts
this is the result:
nameNew Position BackPart FrontPart FinalString
ceur1m 5 1m eur eur_1m
dusd3m 5 3m usd usd_3m
eur10y 4 10y eur eur_10y
usd15y 4 15y usd usd_15y
EUR10Y 4 10Y EUR EUR_10Y

T-SQL function to split string with two delimiters as column separators into table

I'm looking for a t-sql function to get a string like:
a:b,c:d,e:f
and convert it to a table like
ID Value
a b
c d
e f
Anything I found in Internet incorporated single column parsing (e.g. XMLSplit function variations) but none of them letting me describe my string with two delimiters, one for column separation & the other for row separation.
Can you please guiding me regarding the issue? I have a very limited t-sql knowledge and cannot fork those read-made functions to get two column solution?
You can find a split() function on the web. Then, you can do string logic:
select left(val, charindex(':', val)) as col1,
substring(val, charindex(':', val) + 1, len(val)) as col2
from dbo.split(#str, ';') s(val);
You can use a custom SQL Split function in order to separate data-value columns
Here is a sql split function that you can use on a development system
It returns an ID value that can be helpful to keep id and value together
You need to split twice, first using "," then a second split using ";" character
declare #str nvarchar(100) = 'a:b,c:d,e:f'
select
id = max(id),
value = max(value)
from (
select
rowid,
id = case when id = 1 then val else null end,
value = case when id = 2 then val else null end
from (
select
s.id rowid, t.id, t.val
from (
select * from dbo.Split(#str, ',')
) s
cross apply dbo.Split(s.val, ':') t
) k
) m group by rowid