Sort Alphanumeric column in SQL Server - sql

My data is in this way
<400
1000-1200
1200-1400
1400-1600
1600-1800
400-600
600-700
700-800
800-1000
And I want this way
<400
400-600
600-700
700-800
800-1000
1000-1200
1200-1400
...
order by LEFT(WC.[WGHT_CLAS_DESC], PATINDEX('%[0-9]%', WC.[WGHT_CLAS_DESC])-1),
CONVERT(INT, SUBSTRING(WC.[WGHT_CLAS_DESC], PATINDEX('%[0-9]%', WC.[WGHT_CLAS_DESC]), LEN(WC.[WGHT_CLAS_DESC])))
This is the code I have used in SQL Server but its not working

Try this:
DECLARE #DataSource TABLE
(
[Column] VARCHAR(32)
);
INSERT INTO #DataSource ([Column])
VALUES ('<400')
,('1000-1200')
,('1200-1400')
,('1400-1600')
,('1600-1800')
,('400-600')
,('600-700')
,('700-800')
,('800-1000');
SELECT [Column]
,TRY_CONVERT(INT, SUBSTRING([Column], 0, CHARINDEX('-', [Column])))
FROM #DataSource
ORDER BY TRY_CONVERT(INT, SUBSTRING([Column], 0, CHARINDEX('-', [Column])));
Note, that TRY_CONVERT is available after SQL Server 2012, so if you are using earlier version you can use CAST:
ORDER BY CAST(SUBSTRING([Column], 0, CHARINDEX('-', [Column])) AS INT)

I think you mean this:
ORDER BY LEFT(WC.[WGHT_CLAS_DESC], PATINDEX('%[0-9]%', WC.[WGHT_CLAS_DESC])-1) DESC,
CONVERT(INT, SUBSTRING(WC.[WGHT_CLAS_DESC], PATINDEX('%[0-9]%', WC.[WGHT_CLAS_DESC]), PATINDEX('%[^0-9]%', WC.[WGHT_CLAS_DESC])-1))

Try this:
declare #t table(val varchar(max))
insert into #t
select '<400'
union select '1000-1200'
union select '1200-1400'
union select '1400-1600'
union select '1600-1800'
union select '400-600'
union select '600-700'
union select '700-800'
SELECT rn=row_number() over( order by StartNumber,EndNumber),StartNumber,EndNumber Val
FROM (
select
CAST(RIGHT(val,LEN(val)-CHARINDEX('-',val)) as int) EndNumber,
CAST(REPLACE(val,'-'+RIGHT(val,LEN(val)-CHARINDEX('-',val)),'') as int) StartNumber,
val
from (
SELECT REPLACE(Val,'<','0-') As Val from #t
) a
)Data
of course, i suggest to use TRY_CONVERT after SQL2012

Related

SQL select the last numbers from the right

I am trying to select only the numbers from a string, starting from the right. So from the following examples:
1ECCA15
ECCB9
I would only like to select the numbers from the right. So the result would be:
15
9
I've tried this, but this does not select the numbers from the right.
substring(col, PatIndex('%[0-9]%', col), len(col))
Try this:
DECLARE #t TABLE(Col VARCHAR(255));
INSERT #t SELECT '1ECCA15';
INSERT #t SELECT 'ECCB9';
SELECT REVERSE(LEFT(REVERSE(col), PATINDEX('%[a-z]%', REVERSE(col)) - 1)) FROM #t;
There you go, make use of REVERSE
CREATE TABLE #temp(col varchar(20))
INSERT INTO #temp values('1ECCA15'),('ECCB9')
SELECT REVERSE(SUBSTRING(REVERSE(Col), 0, PATINDEX('%[^0-9]%',REVERSE(col))))
FROM #temp
How about this?
select right(col, patindex('%[^0-9]%',reverse(col))-1) from your_table;

How do I select a substring from two different patindex?

I have many different types of string, but they all follow the two same patterns:
ABC123-S-XYZ789
ABC123-P-XYZ789
QUESTION 1:
I know how I can extract the first part: ABC123
But how do I extract the second part??? XYZ789
QUESTION 2:
I can't tell beforehand if the string follows the -S- pattern or the -P- pattern, it can be different each time. Anyone who know how I can solve this?
Thanks! / Sophie
You can try following code:
SELECT CASE WHEN #a LIKE '%-S-%' THEN right(#a, CHARINDEX('-S-', #a)-1)
WHEN #a LIKE '%-P-%' THEN right(#a, CHARINDEX('-P-', #a)-1)
ELSE NULL END AS 'ColName'
FROM tablename
Is this what you need?
DECLARE #Input VARCHAR(100) = 'ABC123-S-XYZ789'
SELECT
FirstPart = SUBSTRING(
#Input,
1,
CHARINDEX('-', #Input) - 1),
SecondPart = SUBSTRING(
#Input,
LEN(#Input) - CHARINDEX('-', REVERSE(#Input)) + 2,
100),
Pattern = CASE
WHEN #Input LIKE '%-S-%' THEN 'S'
WHEN #Input LIKE '%-P-%' THEN 'P' END
You can use parsename() if the string has always this kind of parts such as ABC123-S-XYZ789
select col, parsename(replace(col, '-', '.'), 1)
However, the parsename() requires the SQL Server+12 if not then you can use reverse()
select col, reverse(left(reverse(col), charindex('-', reverse(col))-1))
If you're using SQL Server 2016 or newer, you can use STRING_SPLIT
CREATE TABLE #temp (string VARCHAR(100));
INSERT #temp VALUES ('ABC123-S-XYZ789'),('ABC123-P-XYZ789');
SELECT *, ROW_NUMBER() OVER (PARTITION BY string ORDER BY string)
FROM #temp t
CROSS APPLY STRING_SPLIT(t.string, '-');
I can't tell beforehand if the string folllows the -S- pattern or the -P- pattern
You can then use a CTE to get a specific part of the string:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY string ORDER BY string) rn
FROM #temp t
CROSS APPLY STRING_SPLIT(t.string, '-')
)
SELECT * FROM cte WHERE rn = 2

Adding columns with two data types in SQL Server

I need to achieve the output like this can anyone please help me. Thanks in advance
You could use left() & right() function if your data format will always in specified format
select LEFT(names, 1) [name], SUM(cast(right(names, 2) as int)) [sum] from <table>
group by LEFT(names, 1)
try the following:
declare #tab table (names varchar(1000))
insert into #tab
select 'a10' union select 'abc20' union select 'xyz5' union select 'b6'
select * from #tab
select names, substring(names, 1, patindex('%[0-9]%',names)-1) [name], substring(names, patindex('%[0-9]%',names), len(names)) [sum]
from #tab
Thanks.
Sql (works even for "a5" - Yogesh Sharma (https://stackoverflow.com/a/47727953/7505395) did the hard work, I fixed it):
select
left(names,1) as name,
sum(cast( right(names,len(names)-1) as int))
from t
group by left(names,1)
Testdata:
CREATE TABLE t ( names varchar(30));
INSERT INTO t ( names ) VALUES ('a10'), ('b20'), ('a5'), ('b6');
Result:
name sum
a 15
b 26
If you need more then one character in front you can do this:
select
left(n,idxFirstNum-1) as name,
sum(cast(right(n,len(n)-idxFirstNum+1) as int)) as sum
from (
select
names as n,
PatIndex('%[0-9]%', names) as idxFirstNum
from t
) as tmp
group by left(n,idxFirstNum-1)
which will store the index of the first digit on each name in an inner tableselect and then cast/sum/group it in the outer select.
Create a function like
Create Function dbo.GetNumbers(#Data VarChar(8000))
Returns VarChar(8000)
AS
Begin
Return Left(
SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000),
PatIndex('%[^0-9.-]%', SubString(#Data, PatIndex('%[0-9.-]%', #Data), 8000) + 'X')-1)
End
Source Solved Already
If you want more control (multiple numbers in a string) would be better to create a CLR function.
Use below T-SQL to get aggregated results without function:
DROP TABLE IF EXISTS #splitString
CREATE TABLE #splitString(
[columnA] [nchar](10) NULL,
[columnB] [nchar](10) NULL) ON [PRIMARY]
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a10', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a05', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'b20', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'a5', NULL)
GO
INSERT #splitString ([columnA], [columnB]) VALUES (N'b9', NULL)
GO
select * from #splitString
select a,sum(b) from (
select
Left(
SubString([columnA], PatIndex('%[a-z.-]%', [columnA]), 8000),
PatIndex('%[^a-z.-]%', SubString([columnA], PatIndex('%[a-z.-]%', [columnA]), 8000) + 'X')-1) a,
cast (Left( SubString([columnA], PatIndex('%[0-9.-]%', [columnA]), 8000),
PatIndex('%[^0-9.-]%', SubString([columnA], PatIndex('%[0-9.-]%', [columnA]), 8000) + 'X')-1) as int) b
From #splitString )aTable group by a
Explanation (Thanks the external link person)
Get the first character that is int (PatIndex(‘%[0-9.-]%’, Data))
Remove all characters left to int (SubString(Data, PatIndex(‘%[0-9.-]%’, Data), 8000))
Find end of numbers (Select PatIndex(‘%[^0-9.-]%’, SubString(Data, PatIndex(‘%[0-9.-]%’, Data)+1, 8000)) )
Get all ints - (Select Left(SubString(Data, PatIndex(‘%[0-9.-]%’, Data), 8000), PatIndex(‘%[^0-9.-]%’, SubString(Data, PatIndex(‘%[0-9.-]%’, Data), 8000) + ‘X’)-1))
Repeat above procedure for strings.

split string in sql server 2008

In my table, I have Experience field like
Experience
0to0Years
2to0Years
7to12Years
Here I want to split into
Yearfrom - 0
Yearto- 0
How to split strings here. I search so many articles. I can't find the correct solution. Is there any way to do here?
Here is a working solution
declare #yearfrom varchar(2),#yearto varchar(2)
select #yearfrom=substring('0to0Years',0,patindex('%to%','0to0Years')),
#yearto=substring('0to0Years',patindex('%to%','0to0Years')+2,patindex('%Years%','0to0Years')-patindex('%to%','0to0Years')-2)
SqlFiddle: http://www.sqlfiddle.com/#!3/d41d8/12483
For working on your column replace '0to0Years' with column name
declare #yearfrom varchar(2),#yearto varchar(2)
select #yearfrom=substring(col_name,0,patindex('%to%',col_name)),
#yearto=substring(,patindex('%to%',col_name)+2,patindex('%Years%',col_name)-patindex('%to%',col_name)-2)
from table_name where <condition>
Try with following Steps...
--Create Table :
Create Table #Table
(
Name Varchar(50),
Experience Varchar(20)
)
Go
-- Insert Values :
Insert into #Table Values('Tom','0to0Years')
Insert into #Table Values('Victor','0to1Years')
Insert into #Table Values('Mark','11to12Years')
Go
--View Data
Select * from #Table
--Using CharIndex and Substring :
Select Name,
Substring(Experience,1,CharIndex('to',Experience)-1) as Yearfrom,
Substring(Experience,(CharIndex('to',Experience)+2),Len(Replace(Experience,'Years','')) - (CharIndex('to',Experience)+1)) as YearTo
from #Table
Please try:
select 'YearFrom - '+substring(Data, 0, PatIndex('%[to]%', Data)) YearFrom,
'YearTo - '+replace(stuff(Data, 1, PatIndex('%[to]%', Data)+1, ''), 'Years', '') YearTo
from
(
Select '0to0Years' Data union
Select '2to0Years' Data union
Select '756to12Years' Data
)x
Try this using Parsename function
Select parsename(replace(Experience,'to','.'),2) ,
substring(parsename(replace(Experience,'to','.'),1),0,
charindex('Y',parsename(replace(Experience,'to','.'),1)))
from YourTable
Demo in SQLFiddle

how to substring of a string in SQL

My data will be like that
IPDocument/XR/test_20120409_clearGAC.txt
IPDocument/XR/test_20120409_clearGAC_05.txt
IPDocument/XR/test_20120409_clearGAC_01.txt
I would like to extract clearGAC.txt from above.
How can I use substring in SQL ?
I assume that you want the _05 and _01 - the question is not clear.
DECLARE #var VARCHAR(250)
DECLARE #table TABLE ( val VARCHAR(250) )
INSERT INTO #table
SELECT 'IPDocument/XR/test_20120409_clearGAC_01.txt'
UNION ALL
SELECT 'IPDocument/XR/test_20120409_clearGAC_05.txt'
UNION ALL
SELECT 'IPDocument/XR/test_20120409_clearGAC.txt'
SELECT SUBSTRING(val, CHARINDEX('clearGAC', val), 50),
SUBSTRING(SUBSTRING(val, CHARINDEX('_', val)+1, 50), CHARINDEX('_', SUBSTRING(val, CHARINDEX('_', val)+1, 50))+1, 50)
FROM #table
Returns this:
clearGAC_01.txt
clearGAC_05.txt
clearGAC.txt
The third parameter in the CHARDINDEX can be larger than the length.
EDIT: I added logic if you don't know if clearGAC is the name
After reading your comment, you may just want this:
I am going to pass ClearGAC.txt and see if it's in the DB. this
ClearGAC.txt may be named like above codes.
DECLARE #var VARCHAR(250)
DECLARE #table TABLE ( val VARCHAR(250) )
INSERT INTO #table
SELECT 'IPDocument/XR/test_20120409_clearGAC_01.txt'
UNION ALL
SELECT 'IPDocument/XR/test_20120409_clearGAC_05.txt'
UNION ALL
SELECT 'IPDocument/XR/test_20120409_clearGAC.txt'
SELECT *
FROM #table
WHERE val LIKE '%clearGAC%.txt'
SELECT SUBSTRING('IPDocument/XR/test_20120409_clearGAC.txt', CHARINDEX('09_','IPDocument/XR/test_20120409_clearGAC.txt')+3, 100)
result :
clearGAC.txt