Extract substring from a string in SQL Server - sql

I need to extract a part of substring from string which follows as per below.
YY_12.Yellow
ABC_WSA.Thisone_A
SS_4MON.DHHE_A_A
I need to extract the string as per below
Yellow
Thisone
DHHE

You could use something like this:
declare #tbl table (col nvarchar(100));
insert #tbl values ('YY_12.Yellow'), ('ABC_WSA.Thisone_A'), ('SS_4MON.DHHE_A_A')
select *
, charindex('_', col2, 0)
, left(col2,
case
when charindex('_', col2, 0) - 1 > 0
then charindex('_', col2, 0) - 1
else len(col2)
end) [result]
from (
select col
, substring(col, charindex('.', col, 0) + 1, len(col)) [col2]
from #tbl ) rs
I'm going to leave the full code so as you can hopefully understand what I did.
First identify and remove everything up to the dot "." (in the [col2] column in the nested SELECT)
Then I nest that SELECT so I can apply a new logic much easier on the result column from the first SELECT from which I only keep everything up to the underscore "_"
The final result is stored in the [result] column

Try this:
CREATE TABLE app (info varchar(20))
INSERT INTO app VALUES
('YY_12.Yellow'),
('ABC_WSA.Thisone_A'),
('SS_4MON.DHHE_A_A'),
('testnopoint')
SELECT
CASE
WHEN CHARINDEX('.', info) > 0 THEN
CASE
WHEN CHARINDEX('_', info, CHARINDEX('.', info) + 1) > 0 THEN
SUBSTRING(info, CHARINDEX('.', info) + 1, CHARINDEX('_', info, CHARINDEX('.', info) + 1) - CHARINDEX('.', info) - 1)
ELSE
SUBSTRING(info, CHARINDEX('.', info) + 1, LEN(info))
END
END
FROM app
My query, if . is not present returns NULL, if you want returns all string remove the CASE statement
Go on SqlFiddle

You could also try with parsename() function available from SQL Server 2012
select Name, left(parsename(Name,1),
case when charindex('_', parsename(Name,1)) > 0
then charindex('_', parsename(Name,1))-1
else len(parsename(Name,1))
end) [ExtrectedName] from table
This assumes you have always . in your string to read the name after .
Result :
Name ExtrectedName
YY_12.Yellow Yellow
ABC_WSA.Thisone_A Thisone
SS_4MON.DHHE_A_A DHHE

Try this, used STUFF here
SELECT LEFT(STUFF(col,1,CHARINDEX('.',col),''),
CHARINDEX('_',STUFF(col,1,CHARINDEX('.',col),'')+'_')-1
)
FROM #table
Output:-
Yellow
Thisone
DHHE

Related

remove substring after certain character if there is no number in it

I would like to remove a sub string after the last dot '.' if it does not contain a number.
Example data:
ID Name
1 example.jpg
2 exampleexample01.01.2014
3 example
4 example1.pdf
5 example13.pdf
6 this. is an. example
7 this.is.a.pdf
Desired result:
ID Name
1 example
2 exampleexample01.01.2014
3 example
4 example1
5 example13
6 this. is an. example
7 this.is.a
My solution which removes every sub string after a dot:
SELECT LEFT([Name], CHARINDEX('.', [Name] + '.') - 1 ) AS Name
FROM Table
Edit:
I updated the example to show that there could be multiple dots in one string.
This seems to do what you want; get the position of the last dot, check if those characters contain a number and if they do return Name. If not, string those characters from the end of the string:
SELECT *,
CASE WHEN RIGHT(V.[Name],CI.LastDot) LIKE '%[0-9]%' THEN V.Name ELSE LEFT(V.[Name], LEN(V.Name) - CI.LastDot) END
FROM (VALUES(1,'example.jpg'),
(2,'exampleexample01.01.2014'),
(3,'example'),
(4,'example1.pdf'),
(5,'example13.pdf'))V(ID,Name)
CROSS APPLY(VALUES(CHARINDEX('.',REVERSE(V.Name))))CI(LastDot);
You can use this query. Basically, you find the string before & after the dot, and apply a simple case when based on your requirement.
WITH before_after AS (
SELECT Name,
LEFT([Name], CHARINDEX('.', [Name] + '.') - 1 ) AS before_dot,
SUBSTRING([Name], CHARINDEX('.', [Name]) + 1, LEN([Name]) - CHARINDEX('.', [Name]) + 1) AS after_dot
FROM table
)
SELECT CASE
WHEN after_dot LIKE '%[0-9]%' THEN before_dot
ELSE Name
END Result
FROM before_after;
SELECT case when ISNUMERIC(RIGHT([Name], CHARINDEX('.', [Name] + '.') - 1 )) =1 then [Name]
else LEFT([Name], CHARINDEX('.', [Name] + '.') - 1 ) end as [Name] FROM Table
try this, but please note that PARSENAME can be used only with less than or equal to 3 dots :
SELECT ID, CASE WHEN PARSENAME(REVERSE([Name]),1) LIKE '%[0-9]%' THEN [Name]
ELSE LEFT([Name], LEN([Name]) - CHARINDEX('.', REVERSE([Name]))) END AS [Name],
FROM [Table]
another way is:
SELECT ID, CASE WHEN RIGHT([Name], CHARINDEX('.', REVERSE([Name]))) LIKE '%.[0-9]%' THEN [Name]
ELSE LEFT([Name], LEN([Name]) - CHARINDEX('.', REVERSE([Name]))) END AS [Name]
FROM [Table]

How to get a specific part from a string in SQL

I need to get a specific part from string.
In the following example the field POSITION contains the A- block, the M-0000000359 block and finally the block to the right of /.
What I need now is the full number to the right of / and if there is a , only the full number up to the comma.
So if the next output of POSITION would be A-M-0000000359/10 or A-M-0000000359/10,10 then the result I need now is 10 in both cases.
SQL
SELECT POSITION
,SUBSTRING((REPLACE(POSITION, SUBSTRING((POSITION), 1, CHARINDEX('/', (POSITION), 1)), '')), 1, CHARINDEX('/', (POSITION), 0)) AS TRIM_A
,SUBSTRING((REPLACE(POSITION, SUBSTRING((POSITION), 1, CHARINDEX('/', (POSITION), 1)), '')), 0, CHARINDEX(',', ((REPLACE(POSITION, SUBSTRING((POSITION), 1, CHARINDEX('/', (POSITION), 1)), ''))), 1)) AS TRIM_B
,*
FROM ORDER
Output
POSITION |TRIM_A|TRIM_B
---------------------|------|------|
A-M-0000000359/1 |1
---------------------|------|------|
A-M-0000000359/1,10 |1,10 1
You can accomplish this with a CASE statement then. Change the #position variable to test it out.
declare #position varchar(64)= 'A-M-0000000359/1111,10'
select
case
when patindex('%,%',#position) > 0
then substring(substring(#position,CHARINDEX('/',#position) + 1,len(#position) - CHARINDEX('/',#position)),1,patindex('%,%',substring(#position,CHARINDEX('/',#position) + 1,len(#position) - CHARINDEX('/',#position))) - 1)
else substring(#position,CHARINDEX('/',#position) + 1,len(#position) - CHARINDEX('/',#position))
end
Perhaps a lighter alternative
Declare #YourTable table (Position varchar(50))
Insert Into #YourTable values
('A-M-0000000359/1,10'),
('A-M-0000000359/1'),
('A-M-0000000359')
Select A.*
,Trim_A = case when charindex('/',Position)=0 then '' else substring(Position,charindex('/',Position)+1,50) end
,Trim_B = case when charindex(',',Position)=0 then ''
else substring(Position,charindex('/',Position)+1,charindex(',',Position)-charindex('/',Position)-1)
end
From #YourTable A
Returns
Position Trim_A Trim_B
A-M-0000000359/1,10 1,10 1
A-M-0000000359/1 1
A-M-0000000359
Can you please try this, I found it very simple and easy to understand that we can simply do it using CASE
create table #test(block varchar(50))
insert into #test values
('A-M-0000000359/10,11'), ('A-M-0000000359/10')
select substring(block, charindex('/', block)+1,
case when charindex(',', block) = 0 then
len(block)
else
(charindex(',', block)-1)-charindex('/', block)
end) finalValue
from #test
OUTPUT
----------
finalValue
10
10

How to use substring conditionally before and after two different symbols in SQL SERVER

I have a table A with ID col. Here is sample data -
ID
NT-QR-1499-1(2015)
NT-XYZ-1503-1
NT-RET-546-1(2014)
I need to select everything after first '-' from left and before '(' from the right. However, some records do not have '(', in which case, the second condition would not apply.
Here is what I need -
QR-1499-1
XYZ-1503-1
RET-546-1
You could get it done in a CASE statement, although I'd definitely take any advice from Aaron;
CREATE TABLE #TestData (ID nvarchar(50))
INSERT INTO #TestData (ID)
VALUES
('NT-QR-1499-1(2015)')
,('NT-XYZ-1503-1')
,('NT-RET-546-1(2014)')
SELECT
ID
,CASE
WHEN CHARINDEX('(',ID) = 0
THEN RIGHT(ID, LEN(ID)-CHARINDEX('-',ID))
ELSE LEFT(RIGHT(ID, LEN(ID)-CHARINDEX('-',ID)),CHARINDEX('(',RIGHT(ID, LEN(ID)-CHARINDEX('-',ID)))-1)
END Result
FROM #TestData
Try this:
SELECT y.i, SUBSTRING(ID, x.i + 1, IIF(y.i = 0, LEN(ID), y.i - x.i - 1))
FROM mytable
CROSS APPLY (SELECT CHARINDEX('-', ID)) AS x(i)
CROSS APPLY (SELECT CHARINDEX('(', ID)) AS y(i)
It looks like your column is not actually a single data element, but multiple data elements that have been concatenated together. A bad idea for database design, which is causing the problem that you're having now.
This should give you what you need, but strongly consider separating the column into the required pieces.
SELECT
SUBSTRING(id, CHARINDEX('-', id) + 1, LEN(id) - CHARINDEX('(', REVERSE(id)) - CHARINDEX('-', id))
FROM
My_Table
DECLARE #str varchar(64);
DECLARE #start int;
DECLARE #length int;
SELECT #str = 'NT-QR-1499-1(2015)';
/*SELECT #str = 'NT-XYZ-1503-1';*/
SELECT #start = CHARINDEX('-', #str) + 1;
SELECT #length = CHARINDEX('(', #str) - #start;
IF (#length > 0)
SELECT SUBSTRING(#str, #start, #length)
ELSE
SELECT SUBSTRING(#str, #start, LEN(#str))
GO
SELECT CASE
WHEN CHARINDEX('(',ID) > 0
THEN
SUBSTRING(ID,CHARINDEX('-',ID)+1,(CHARINDEX('(',ID)-CHARINDEX('-',ID)-1))
ELSE
SUBSTRING(ID,CHARINDEX('-',ID)+1)
END AS New_Column_Name
FROM Table_Name
First it will check whether "(" present or not .
If present then it will fetch the data from next position of "-" to before the position of "(".
otherwise it will fetch the data from next position of "-" to till end.

Extract string between after second / and before -

I have a field that holds an account code. I've managed to extract the first 2 parts OK but I'm struggling with the last 2.
The field data is as follows:
812330/50110/0-0
812330/50110/BDG001-0
812330/50110/0-X001
I need to get the string between the second "/" and the "-" and after the "-" .Both fields have variable lengths, so I would be looking to output 0 and 0 on the first record, BDG001 and 0 on the second record and 0 and X001 on the third record.
Any help much appreciated, thanks.
You can use CHARINDEX and LEFT/RIGHT:
CREATE TABLE #tab(col VARCHAR(1000));
INSERT INTO #tab VALUES ('812330/50110/0-0'),('812330/50110/BDG001-0'),
('812330/50110/0-X001');
WITH cte AS
(
SELECT
col,
r = RIGHT(col, CHARINDEX('/', REVERSE(col))-1)
FROM #tab
)
SELECT col,
r,
sub1 = LEFT(r, CHARINDEX('-', r)-1),
sub2 = RIGHT(r, LEN(r) - CHARINDEX('-', r))
FROM cte;
LiveDemo
EDIT:
or even simpler:
SELECT
col
,sub1 = SUBSTRING(col,
LEN(col) - CHARINDEX('/', REVERSE(col)) + 2,
CHARINDEX('/', REVERSE(col)) -CHARINDEX('-', REVERSE(col))-1)
,sub2 = RIGHT(col, CHARINDEX('-', REVERSE(col))-1)
FROM #tab;
LiveDemo2
EDIT 2:
Using PARSENAME SQL SERVER 2012+ (if your data does not contain .):
SELECT
col,
sub1 = PARSENAME(REPLACE(REPLACE(col, '/', '.'), '-', '.'), 2),
sub2 = PARSENAME(REPLACE(REPLACE(col, '/', '.'), '-', '.'), 1)
FROM #tab;
LiveDemo3
...Or you can do this, so you only go from left side to right, so you don't need to count from the end in case you have more '/' or '-' signs:
SELECT
SUBSTRING(columnName, CHARINDEX('/' , columnName, CHARINDEX('/' , columnName) + 1) + 1,
CHARINDEX('-', columnName) - CHARINDEX('/' , columnName, CHARINDEX('/' , columnName) + 1) - 1) AS FirstPart,
SUBSTRING(columnName, CHARINDEX('-' , columnName) + 1, LEN(columnName)) AS LastPart
FROM table_name
One method way is to download a split() function off the web and use it. However, the values end up in separate rows, not separate columns. An alternative is a series of nested subqueries, CTEs, or outer applies:
select t.*, p1.part1, p12.part2, p12.part3
from table t outer apply
(select t.*,
left(t.field, charindex('/', t.field)) as part1,
substring(t.field, charindex('/', t.field) + 1) as rest1
) p1 outer apply
(select left(p1.rest1, charindex('/', p1.rest1) as part2,
substring(p1.rest1, charindex('/', p1.rest1) + 1, len(p1.rest1)) as part3
) p12
where t.field like '%/%/%';
The where clause guarantees that the field value is in the right format. Otherwise, you need to start sprinkling the code with case statements to handle misformated data.

Splitting value of a varchar column into two columns

If I have a column in which strings vary in length but they ALL have a slash \ within,
how can I SELECT to have one column display everything BEFORE the \ and another column displaying everything AFTER the \?
name column1 column2
DB5697\DEV DB5697 DEV
I have seen CHARINDEX and REVERSE on MSDN but haven't been able to put together a soltuion.
How can I best split a varchar/string column value into 2 columns in a result set in TSQL ?
what about using PARSENAME function in a tricky way?
USE tempdb;
GO
CREATE TABLE #names
(
id int NOT NULL PRIMARY KEY CLUSTERED
, name varchar(30) NOT NULL
);
GO
INSERT INTO #names (id, name)
VALUES
(1, 'DB5697\DEV'),
(2, 'DB5800\STG'),
(3, 'DB5900\PRD');
GO
SELECT
name
, PARSENAME(REPLACE(name, '\', '.'), 2) AS [Server]
, PARSENAME(REPLACE(name, '\', '.'), 1) AS [Instance]
FROM
#names;
GO
DROP TABLE #names;
GO
The PARSENAME function accepts 2 parameters and gets the name part of a fully qualified name. The second parameter is the part name enumerator.
Value 2 is for SCHEMA and 1 is for OBJECT.
So, with the REPLACE function the "\" char is replaced by "." in order to have a SCHEMA.OBJECT format of your SERVERNAME\INSTANCE values. Then, PARSENAME behave like having a simple object name in the string.
How about the following (SQL Fiddle):
SELECT m.name,
LEFT(m.name, CHARINDEX('\', m.name) - 1) AS column1,
RIGHT(m.name, LEN(m.name) - CHARINDEX('\', m.name)) AS column2
FROM MyTable m
How to handle strings with no \ in them (SQL Fiddle):
SELECT m.name,
CASE WHEN CHARINDEX('\', m.name) = 0 THEN ''
ELSE LEFT(m.name, CHARINDEX('\', m.name) - 1) END AS column1,
CASE WHEN CHARINDEX('\', m.name) = 0 THEN ''
ELSE RIGHT(m.name, LEN(m.name) - CHARINDEX('\', m.name)) END AS column2
FROM MyTable m;
You can use CHARINDEX to check for the character position of the splitter ('/') and use SUBSTRING to split the string.
However care has to be taken to ensure you handle records without splitters else you would invoke an error.
Also in the case where splitter is unavailable, decision has to be made as to which column the data should be mapped to. Here I am mapping data to FirstName and assigning NULL to LastName
DECLARE #TableBuyer TABLE (ID INT, FullName VARCHAR(100))
INSERT INTO #TableBuyer
SELECT '1','Bryan/Greenberg' UNION ALL
SELECT '2','Channing/Tatum' UNION ALL
SELECT '3','Paul/William' UNION ALL
SELECT '4','EricBana' UNION ALL
SELECT '5','James/Lafferty' UNION ALL
SELECT '6','Wentworth/Miller'
SELECT
CASE
WHEN CHARINDEX('/', FullName) > 0 THEN SUBSTRING(FullName, 1, CHARINDEX('/', FullName) - 1)
ELSE FullName
END AS FirstName
,
CASE
WHEN CHARINDEX('/', FullName) > 0 THEN SUBSTRING(FullName, CHARINDEX('/', FullName) + 1, LEN(FullName))
ELSE NULL
END AS LastName
FROM #TableBuyer;
DECLARE #TableBuyer TABLE (ID INT, FullName VARCHAR(100))
INSERT INTO #TableBuyer
SELECT '1','Bryan/Greenberg' UNION ALL
SELECT '2','Channing/Tatum' UNION ALL
SELECT '3','Paul/William' UNION ALL
SELECT '4','EricBana' UNION ALL
SELECT '5','James/Lafferty' UNION ALL
SELECT '6','Wentworth/Miller'
select left(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))) as firstname,
substring(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))+ 2, len(FullName)) as lastname
from #TableBuyer
OR
select left(FullName, len(FullName)-CHARINDEX('/', REVERSE(FullName))) as firstname,
RIGHT(FullName, len(FullName)-CHARINDEX('/', FullName)) as lastname
from #TableBuyer
There is no "simple" method. Something like this should work:
select left(col, charindex('\', col) - 1) as column1,
right(col, charindex('\', reverse(col)) - 1) as column2
You might need to double up on the backslash ('\\') to get it to work properly.