Sql substring using "/" as indicator where to cut - sql

Hi I want to cut a string in sql at 2 points with the "/" as an indicator where to cut. The string looks like this: "test1/test2/test3/test4/test5/test6" and I need the parts of test 2 and test 5 but they are not static, so I have to use the "/" befor and after them to set the points where to cut, any suggestions?

You could achieve this by using XML:
DECLARE #x NVARCHAR(100) = 'test1/test2/test3/test4/test5/test6';
DECLARE #xml XML = cast(('<X>'+replace(#x,'/' ,'</X><X>')+'</X>') as xml);
WITH cte AS(
SELECT N.value('.', 'varchar(10)') as value, ROW_NUMBER() OVER (ORDER BY (SELECT(0))) AS rn
FROM #xml.nodes('X') as T(N)
)
SELECT *
FROM cte
WHERE rn IN (1, 5)

You can use the function CHARINDEX()
For example this query will work for you
declare #text varchar(100)='test1/test2/test3/test4/test5/test6'
select
SUBSTRING (#text,CHARINDEX('/',#text)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1),
SUBSTRING (#text,CHARINDEX('/',#text,CHARINDEX('/',#text,CHARINDEX('/',#text,CHARINDEX('/',#text)+1)+1)+1)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1)
Just incase you want to substring something else, I'm sharing the code below and then you can work on it
declare #text varchar(100)='test1/test2/test3/test4/test5/test6'
select
SUBSTRING (#text,CHARINDEX('/',#text)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1) --test2
,SUBSTRING (#text,CHARINDEX('/',#text,CHARINDEX('/',#text)+1)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1) --test3
,SUBSTRING (#text,CHARINDEX('/',#text,CHARINDEX('/',#text,CHARINDEX('/',#text)+1)+1)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1) --test4
,SUBSTRING (#text,CHARINDEX('/',#text,CHARINDEX('/',#text,CHARINDEX('/',#text,CHARINDEX('/',#text)+1)+1)+1)+1,CHARINDEX('/',#text,(CHARINDEX('/',#text)+1))-CHARINDEX('/',#text)-1) --test5

If the items that you want are always the second and the second to last you can use CHARINDEX to find the first and second '/' and SUBSTRING to pull that value. Then REVERSE the string to get the second last. e.g.
DECLARE #data varchar(128) = 'test1/test2/test3/test4/test5/test6';
SELECT substring(#data,charindex('/',#data,1)+1,charindex('/',#data,charindex('/',#data,1)+1)-(charindex('/',#data,1)+1)),
reverse(substring(reverse(#data),charindex('/',reverse(#data),1)+1,charindex('/',reverse(#data),charindex('/',reverse(#data),1)+1)-(charindex('/',reverse(#data),1)+1)))

Related

Fetching data between 2 underscore

I have this query:
Declare #t nvarchar(300) ='83082351_10_P00004'
select SUBSTRING(
#t,
charindex('_',#t)+1,
CHARINDEX('_', #t, (CHARINDEX('_', #t)+1))
)
I want the output as 10 which is between the two _ characters, I don't know what I am doing wrong in my query.
Can someone please help me in this.
As Larnu pointed out, you are asking for too many characters. You need to also subtract the position of the initial underscore to return just the middle characters:
declare #t nvarchar(300) ='83082351_10_P00004'
select substring(#t
,charindex('_',#t)+1
,charindex('_'
,#t
,charindex('_', #t)+1
)
- (charindex('_',#t)+1)
)

Substring after a dot in SQL Server

I have a field which holds data like this
Product.Company.Price.Item
I want to substring any string after the last dot. so it will look like this
Item
I know there is a substring.index function in MySQL. How can I implement this in SQL Server?
select reverse(substring(reverse(fieldName),1,charindex('.',reverse(fieldname))-1))
This will do what you want, but I wouldn't use it as part of a where expression
declare #x varchar(50) = 'Product.Company.Price.Item'
select substring(#x,len(#x)-charindex('.',reverse(#x))+2,99)
Hope this Query works fine for your Case:
DECLARE #VAR VARCHAR(MAX)='Product.Company.Price.Item'
SELECT RIGHT(#VAR, CHARINDEX('.', REVERSE(#VAR) + '.') - 1) AS VARL
If it's always 4 parts then you could use parsename() as
select parsename('Product.Company.Price.Item', 1)
or use right() and charindex() as
select right(str, p)
from
(
values ('Product.Company.Price.Item'), ('Other.row')
) t(str) cross apply
(
values (charindex('.', reverse(str))-1)
) tt(p)
You can try this using functions like Reverse(), Left(), and the CHARINDEX().
DECLARE #Sentence VARCHAR(100) = 'Product.Company.Price.Item';
SELECT REVERSE(LEFT(REVERSE(#Sentence),
CHARINDEX('.',REVERSE(#Sentence))- 1)) AS [Last_Word]

select and concatenate everything before and after a certain character

I've got a string like AAAA.BBB.CCCC.DDDD.01.A and I'm looking to manipulate this and end up with AAAA-BBB
I've achieved this by writing this debatable piece of code
declare #string varchar(100) = 'AAAA.BBB.CCCC.DDDD.01.A'
select replace(substring(#string,0,charindex('.',#string)) + substring(#string,charindex('.',#string,CHARINDEX('.',#string)),charindex('.',#string,CHARINDEX('.',#string)+1)-charindex('.',#string)),'.','-')
Is there any other way to achieve this which is more elegant and readable ?
I was looking at some string_split operations, but can't wrap my head around it.
If you are open to some JSON transformations, the following approach is an option. You need to transform the text into a valid JSON array (AAAA.BBB.CCCC.DDDD.01.A is transformed into ["AAAA","BBB","CCCC","DDDD","01","A"]) and get the required items from this array using JSON_VALUE():
Statement:
DECLARE #string varchar(100) = 'AAAA.BBB.CCCC.DDDD.01.A'
SET #string = CONCAT('["', REPLACE(#string, '.', '","'), '"]')
SELECT CONCAT(JSON_VALUE(#string, '$[0]'), '-', JSON_VALUE(#string, '$[1]'))
Result:
AAAA-BBB
Notes: With this approach you can easily access all parts from the input string by index (0-based).
I think this is a little cleaner:
declare #string varchar(100) = 'AAAA.BBB.CCCC.DDDD.01.A'
select
replace( -- replace '.' with '-' (A)
substring(#string, 1 -- in the substring of #string starting at 1
,charindex('.', #string -- and going through 1 before the index of '.'(B)
,charindex('.',#string)+1) -- that is after the first index of the first '.'
-1) -- (B)
,'.','-') -- (A)
Depending on what is in your string you might be able to abuse PARSENAME into doing it. Intended for breaking up names like adventureworks.dbo.mytable.mycolumn it works like this:
DECLARE #x as VARCHAR(100) = 'aaaa.bbb.cccc.ddddd'
SELECT CONCAT( PARSENAME(#x,4), '-', PARSENAME(#x,3) )
You could also look at a mix of STUFF to delete the first '.' and replace with '-' then LEFT the result by the index of the next '.' but it's unlikely to be neater than this or Kevin's proposal
Using string split would likely be as unwieldy:
SELECT CONCAT(MAX(CASE WHEN rn = 1 THEN v END), '-', MAX(CASE WHEN rn = 2 THEN v END))
FROM (
SELECT row_number () over (order by (select 0)) rn, value as v
FROM string_split(#x,'.')
) y WHERE rn IN (1,2)
Because the string is split to rows which then need to be numbered in order to filter and pull the parts you want. This also relies on the strings coming out of string split in the order they were in the original string, which MS do not guarantee will be the case

Remove characters before and after string SQL

I would like to remove all characters before and after a string in the select statement.
In the example below I would like to remove everything before and including /Supply> and after and including >/
Note the remaining part will be a fixed number of characters.
Any help would be much appreciated
Eg.
abs/Supply>hhfhjgglldppprrr>/llllllldsfsjhfhhhfdhudfhfhdhdfhfsd
Would become:
hhfhjgglldppprrr
If your input always has exactly two instances of ">" you could use PARSENAME.
declare #SomeValue varchar(100) = 'abs/Supply>hhfhjgglldppprrr>/llllllldsfsjhfhhhfdhudfhfhdhdfhfsd'
select PARSENAME(replace(#SomeValue, '>', '.'), 2)
This will not work correctly if your data also contains any periods (.). We can deal with that if needed with a couple of replace statements. Still very simple and easy to maintain with the same caveat of exactly 2 >.
declare #SomeOtherValue varchar(100) = 'abs/Supply>hhfhjgg.lldppprrr>/llllllldsfsjhfhhhfdhudfhfhdhdfhfsd'
select replace(PARSENAME(replace(replace(#SomeOtherValue, '.', '~!##'), '>', '.'), 2), '~!##', '.')
You can use PATINDEX() to identify the position of the patterns you are looking for (/Supply> and >/) then remove them based on the length of the string:
SELECT LEFT(RIGHT(col,LEN(col) - PATINDEX('%/Supply>%',col) -7), PATINDEX('%>/%', RIGHT(col,LEN(col) - PATINDEX('%Supply>%',col) -7))-1)
Simply replace col in the above with your column name.
Example below with test string abs/Supply>keep>/remove
First remove everything before and including /Supply>:
SELECT RIGHT('abs/Supply>keep>/remove',LEN('abs/Supply>keep>/remove') - PATINDEX('%/Supply>%','abs/Supply>keep>/remove') -7)
This will give keep>/remove
Then remove everything after and including >/:
SELECT LEFT('keep>/remove',PATINDEX('%>/%','keep>/remove') - 1)
This will give keep, the part of the string you want.
Here is the combined version, same as above, just includes the test string instead of col so you can run it easily:
SELECT LEFT(RIGHT('abs/Supply>keep>/remove',LEN('abs/Supply>keep>/remove') - PATINDEX('%/Supply>%','abs/Supply>keep>/remove') -7), PATINDEX('%>/%', RIGHT('abs/Supply>keep>/remove',LEN('abs/Supply>keep>/remove') - PATINDEX('%/Supply>%','abs/Supply>keep>/remove') -7))-1)
This will give keep. You can also replace the string above with the one in your question, I just used a different test string because it is shorter and makes the code more readable.
try this:
DECLARE #inputStr VARCHAR(max)= 'abs/Supply>hhfhjgglldppprrr>/llllllldsfsjhfhhhfdhudfhfhdhdfhfsd'
DECLARE #startString VARCHAR(100)='/Supply>'
DECLARE #EndString VARCHAR(100)='>/'
DECLARE #LenStartString INT = LEN(#startString)
DECLARe #TempInputString VARCHAR(max)='';
DECLARE #StartIndex INT
DECLARE #EndIndex INT
SELECT #StartIndex = CHARINDEX(#startString,#inputStr)+#LenStartString
SELECT #TempInputString = STUFF(#inputStr, 1, #StartIndex, '')
SELECT SUBSTRING(#TempInputString,0,CHARINDEX(#EndString,#TempInputString))
In Single Line
DECLARE #inputStr VARCHAR(max)= 'abs/Supply>hhfhjgglldppprrr>/llllllldsfsjhfhhhfdhudfhfhdhdfhfsd'
DECLARE #startString VARCHAR(100)='/Supply>'
DECLARE #EndString VARCHAR(100)='>/'
SELECT SUBSTRING(STUFF(#inputStr, 1, CHARINDEX(#startString,#inputStr)+LEN(#startString), ''),0,CHARINDEX(#EndString,STUFF(#inputStr, 1,CHARINDEX(#startString,#inputStr)+LEN(#startString), '')))

A SQL Problem. Check condition with in a comma seperated value

I have a vairable
DECLARE #AssignOn nvarchar(20)='0,2,5'
I want to check a condition like this
DECLARE #index int
SET DATEFIRST 7
SELECT #index=DATEPART(DW, GETDATE())-1
IF(CONVERT(nvarchar(2),#index) IN #AssignOn)
IN cannot be used here . Any other methods to do this INLINE
You can use CharIndex to find if you have a match. It returns a non zero value if the first string appears in the second.
IF(CHARINDEX(CONVERT(nvarchar(2),#index), #AssignOn) > 0)
The easiest way to do this is to search for the substring ',needle,' in the csv list string. However, this doesn't work correctly for the first and last elements. This can be overcome by concatenating a comma onto each side of the csv list string.
An example in SQL might be:
SELECT
CHARINDEX(','+ NEEDLE +',', ','+ HAYSTACK +',')
FROM table;
Or using LIKE:
SELECT *
FROM table
WHERE ','+ HAYSTACK +',' LIKE '%,'+ NEEDLE +',';
IF CHARINDEX(','+CONVERT(nvarchar(2),#index)+',', ','+#AssignOn+',') <> 0
As you actually define the values in the code you could instead;
DECLARE #AssignOn TABLE (value int)
INSERT #AssignOn VALUES (0),(2),(5)
... #index IN (SELECT value FROM #AssignOn)