Substring output for different cases - sql

I need output with following cases:
+-----------------+--------+
| STRING in table | OUTPUT |
+-----------------+--------+
| NONGL_NONGL | NONGL |
| GL252_GL252 | GL |
| GL400_GL400 | GL |
| NOS_NOS | NOS |
+-----------------+--------+
I tried to use SUBSTRING() but it is not giving me proper output.

So for the NONGL and NOS result you need:
SELECT LEFT([col_name], CHARINDEX('_', [col_name]) - 1)
And for the GL output, since the string is containing numbers you need PATINDEX():
SELECT LEFT([col_name], PATINDEX('%[0-9]%', [col_name]) - 1)
In the end just use a CASE WHEN
DECLARE #tbl Table (string VARCHAR(MAX) );
INSERT INTO #tbl VALUES
('NONGL_NONGL'),
('GL252_GL252'),
('GL400_GL400'),
('NOS_NOS');
SELECT
string
,CASE WHEN
string LIKE '%[0-9]%' then LEFT(string, PATINDEX('%[0-9]%', string) - 1)
ELSE LEFT(string, CHARINDEX('_', string) - 1)
END AS [Output]
from #tbl

This should do what you want:
select (case when col like 'NONGL%' then 'NONGL'
when col like 'GL%' then 'GL'
when col like 'NOS%' then 'NOS'
end) as new_col

Here is another way:
DECLARE #StrTable Table (Str VARCHAR(MAX) );
INSERT INTO #StrTable VALUES
('NONGL_NONGL'),
('GL252_GL252'),
('GL400_GL400'),
('NOS_NOS');
SELECT Str,
IIF(Str LIKE 'NONGL%','NONGL',IIF(Str LIKE 'GL%', 'GL', IIF(Str LIKE 'NOS%', 'NOS', Str))) AS Outputs
FROM #StrTable;
Result:
+-------------+---------+
| Str | Outputs |
+-------------+---------+
| NONGL_NONGL | NONGL |
| GL252_GL252 | GL |
| GL400_GL400 | GL |
| NOS_NOS | NOS |
+-------------+---------+

Related

SQL Server - Ordering Combined Number Strings Prior To Column Insert

I have 2 string columns (thousands of rows) with ordered numbers in each string (there can be zero to ten numbers in each string). Example:
+------------------+------------+
| ColString1 | ColString2 |
+------------------+------------+
| 1;3;5;12; | 4;6' |
+------------------+------------+
| 1;5;10 | 2;26; |
+------------------+------------+
| 4;7; | 3; |
+------------------+------------+
The end result is to combine these 2 columns, sort the numbers in
ascending order and then put each number into individual columns (smallest, 2nd smallest etc).
e.g. Colstring1 is 1;3;5;12; and ColString2 is 4;6; needs to return 1;3;4;5;6;12; which I then use xml to allocated into columns.
Everthing works fine using xml apart from the step to order the numbers (i.e I'm getting 1;3;5;12;4;6; when I combine the strings i.e. not in ascending order).
I've tried put them into a JSON array first to order, thinking I could do a top[1] etc but that did not work.
Any help on how to combine the 2 columns and order them before inserting into columns:
Steps so far:
Example data:
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, ColString1 VARCHAR(50), ColString2 VARCHAR(50));
INSERT INTO #tbl (ColString1, ColString2)
VALUES
('1;3;5;12;', '4;6;'),
('1;5;10;', '2;26;'),
('14;', '3;8;');
XML Approach (Combines strings and puts into columns but not in the correct order):
;WITH Split_Numbers (xmlname)
AS
(
SELECT
CONVERT(XML,'<Names><name>'
+ REPLACE ( LEFT(ColString1+ColString2,LEN(ColString1+ColString2) - 1),';', '</name><name>') + '</name></Names>') AS xmlname
FROM #tbl
)
SELECT
xmlname.value('/Names[1]/name[1]','int') AS Number1,
xmlname.value('/Names[1]/name[2]','int') AS Number2,
xmlname.value('/Names[1]/name[3]','int') AS Number3,
xmlname.value('/Names[1]/name[4]','int') AS Number4,
xmlname.value('/Names[1]/name[5]','int') AS Number5
--etc for additional columns
FROM Split_Numbers
Current Output: numbers not in correct order,
+---------+---------+---------+---------+---------+
| Number1 | Number2 | Number3 | Number4 | Number5 |
+---------+---------+---------+---------+---------+
| 1 | 3 | 5 | 12 | 4 |
| 1 | 5 | 10 | 2 | 26 |
| 14 | 3 | 8 | NULL | NULL |
+---------+---------+---------+---------+---------+
Desired Output: numbers in ascending order.
+---------+---------+---------+---------+---------+
| Number1 | Number2 | Number3 | Number4 | Number5 |
+---------+---------+---------+---------+---------+
| 1 | 3 | 4 | 5 | 6 |
| 1 | 2 | 5 | 10 | 26 |
| 3 | 8 | 14 | NULL | NULL |
+---------+---------+---------+---------+---------+
JSON Approach: combines the columns into a JSON array but I still can't order correctly when in JSON format.
REPLACE ( CONCAT('[', LEFT(ColString1+ColString2,LEN(ColString1+ColString2) - 1), ']') ,';',',')
Any help will be greatly appreciated whether there is a way to order the xml or JSON string prior to entry. Happy to consider an alternative way if there is an easier solution.
You can use string_agg() and string_split():
select t.*, newstring
from t cross apply
(select string_agg(value, ',') order by (value) as newstring
from (select s1.value
from unnest(colstring1, ',') s1
union all
select s2.value
from unnest(colstring2, ',') s2
) s
) s;
That said, you should probably put your effort into fixing the data model. Storing numbers in strings is bad. Storing multiple values in a string is bad, bad. If the numbers are foreign references to other tables, that is bad, bad, bad, bad, bad.
While waiting for a DDL and sample data population, etc., here is a conceptual example for you. It is using XQuery and its FLWOR expression.
CTE does most of the heavy lifting:
Concatenates both columns values into one string. CONCAT() function protects against NULL values.
Converts it into XML data type.
Sorts XML elements by converting their values to int data type in the FLWOR expression.
Filters out XML elements with no legit values.
The rest is trivial.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, col1 VARCHAR(100), col2 VARCHAR(100));
INSERT INTO #tbl (col1, col2)
VALUES
('1;3;5;12;', '4;6;'),
('1;5;10;', '2;26;');
-- DDL and sample data population, end
DECLARE #separator CHAR(1) = ';';
;WITH rs AS
(
SELECT *
, CAST('<root><r><![CDATA[' +
REPLACE(CONCAT(col1, col2), #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML).query('<root>
{
for $x in /root/r[text()]
order by xs:int($x)
return $x
}
</root>') AS sortedXML
FROM #tbl
)
SELECT ID
, c.value('(r[1]/text())[1]','INT') AS Number1
, c.value('(r[2]/text())[1]','INT') AS Number2
, c.value('(r[3]/text())[1]','INT') AS Number3
-- continue with the rest of the columns
FROM rs CROSS APPLY sortedXML.nodes('/root') AS t(c);
Output
+----+---------+---------+---------+
| ID | Number1 | Number2 | Number3 |
+----+---------+---------+---------+
| 1 | 1 | 3 | 4 |
| 2 | 1 | 2 | 5 |
+----+---------+---------+---------+

Sort the Alphanumeric column in SQL

I want sort the below Alphanumeric Column in SQL Server.
Column A
------------------------------
SP-SS-2
SP-FAB-8
WD-1
WD-4A
WD-11
WD-10
WD-2
WD-20
I want sorted by ascending order Output is as follows:
Column A
-----------------------
SP-FAB-8
SP-SS-2
WD-1
WD-2
WD-4A
WD-10
WD-11
WD-20
Any tricks to make it sort properly?
SELECT ColumnA FROM #TblTableA
ORDER BY
LEFT(ColumnA,PATINDEX('%[0-9]%',ColumnA)-1),
CASE
WHEN ISNUMERIC(ColumnA) = 0
THEN CAST(LEFT(RIGHT(ColumnA,LEN(ColumnA)-CHARINDEX('-',ColumnA)),
patindex('%[^0-9]%', RIGHT(ColumnA,LEN(ColumnA)-CHARINDEX('-',ColumnA))+'.') - 1) AS INT)
ELSE ColumnA
END
Output:-
ColumnA
---------
SP-FAB-8
SP-SS-2
WD-1
WD-2
WD-4A
WD-10
WD-11
WD-20
Note:- You will get this type of output using Patindex.....
For More Info...Follow this below Link
https://dba.stackexchange.com/questions/117379/sort-a-varchar-type-column-alphanumeric-values
If we want to overcome this issue, we need to separate strings and numbers and then sort them. In the first step we need a function that helps to separate numbers from the strings. Therefore, we will create this function Query to get only numbers from a string
CREATE FUNCTION dbo.udf_GetNumeric
(#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
GO
In the second step we can execute the following query that will help to sort alphanumeric characters.
CREATE TABLE #Temp
(Val VARCHAR(100))
INSERT INTO #Temp
VALUES ('SP-SS-2') ,
('SP-FAB-8'),
('WD-1'),
('WD-4A'),
('WD-11'),
('WD-10'),
('WD-2'),
('WD-20')
select val,dbo.udf_GetNumeric(val) as textpart
,LEFT(val,PATINDEX('%[0-9]%',val)-1) as stringpart
from
#Temp
order by LEFT(val,PATINDEX('%[0-9]%',val)-1) ,convert(int,dbo.udf_GetNumeric(val))
+----------+----------+------------+
| val | textpart | stringpart |
+----------+----------+------------+
| SP-FAB-8 | 8 | SP-FAB- |
| SP-SS-2 | 2 | SP-SS- |
| WD-1 | 1 | WD- |
| WD-2 | 2 | WD- |
| WD-4A | 4 | WD- |
| WD-10 | 10 | WD- |
| WD-11 | 11 | WD- |
| WD-20 | 20 | WD- |
+----------+----------+------------+

SQL Sort Numeric Strings After Split

I currently have char values in a table column which are in the format "IS-" and then 1 to 5 numbers, a possible period with either 2 numbers or a letter following the period.
Examples are, IS-1, IS-12, IS-123, IS-123.11, IS-123.a.
I need to split the string so that I grab only the number part, sort the strings ASC, and the bring the strings back together the way they were.
Explanation. I have the following set of values, IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a. As you can see, because IS-1 comes before IS-8 they are sorting out of numerical order.
Any idea where to begin? I was thinking of using CASE, but I'm not really sure how to proceed.
Thanks.
Do string functions in your ORDER BY to remove only the number. Something like this should work:
SELECT col
FROM table
ORDER BY CAST(CASE WHEN ISNUMERIC(SUBSTRING(col,4,20)) = 1
THEN SUBSTRING(col,4,20)
ELSE LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1)
END AS NUMERIC)
This will first remove the IS- and check if the rest of the string is a number. If it is, it will leave the decimal digits, otherwise it will remove the . and the following alpha characters.
This is assuming your intended ordering in the case of numeric decimal places would be:
IS-123.A
IS-123.1
IS-123.2
If you don't care about what's after the decimal/period, then simply:
ORDER BY CAST(LEFT(SUBSTRING(col,4,20),CHARINDEX('.',SUBSTRING(col,4,20),0)-1) AS NUMERIC)
If I understand you correctly, this might help you:
DECLARE #mockup TABLE(ID INT IDENTITY,YourExample VARCHAR(100));
INSERT INTO #mockup VALUES
('IS-1, IS-12, IS-123, IS-123.11, IS-123.a.')
,('IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a');
WITH Splitted AS
(
SELECT *
,CAST('<x>' + REPLACE(m.YourExample,',','</x><x>') + '</x>' AS XML) AS SplitAtComma
FROM #mockup AS m
)
,NumberExtracted AS
(
SELECT s.ID
,part.value('text()[1]','nvarchar(max)') AS OnePart
,CAST('<y>' + REPLACE(REPLACE(part.value('text()[1]','nvarchar(max)'),'.','-'),'-','</y><y>') + '</y>' AS XML).value('/y[2]/text()[1]','int') AS TheNumber
FROM Splitted AS s
CROSS APPLY s.SplitAtComma.nodes('/x') AS A(part)
)
SELECT *
FROM NumberExtracted
ORDER BY ID,TheNumber;
The first CTE uses a string-split via XML to get all values within the original string (btw: never store comma separated values!).
The second CTE will use the same approach to extract the number, typesafe as INT.
You can use this in an ORDER BY finally.
The result:
+----+-----------+-----------+
| ID | OnePart | TheNumber |
+----+-----------+-----------+
| 1 | IS-1 | 1 |
+----+-----------+-----------+
| 1 | IS-12 | 12 |
+----+-----------+-----------+
| 1 | IS-123 | 123 |
+----+-----------+-----------+
| 1 | IS-123.11 | 123 |
+----+-----------+-----------+
| 1 | IS-123.a. | 123 |
+----+-----------+-----------+
| 2 | IS-870.a | 870 |
+----+-----------+-----------+
| 2 | IS-871.a | 871 |
+----+-----------+-----------+
| 2 | IS-872.a | 872 |
+----+-----------+-----------+
| 2 | IS-1170 | 1170 |
+----+-----------+-----------+
| 2 | IS-1171 | 1171 |
+----+-----------+-----------+
| 2 | IS-1172 | 1172 |
+----+-----------+-----------+
| 2 | IS-1173 | 1173 |
+----+-----------+-----------+
| 2 | IS-1174 | 1174 |
+----+-----------+-----------+
IF OBJECT_ID(N'tempdb..##table1', N'U') IS NOT NULL
DROP TABLE ##table1;
create table ##table1(col1 varchar(20))
declare #query as nvarchar(max)
declare #var1 as varchar(max)='IS-1, IS-12, IS-123, IS-123.11, IS-123.a.,IS-1170, IS-1171, IS-1172, IS-1173, IS-1174, IS-870.a, IS-871.a, IS-872.a.'
set #var1=replace(#var1,',','''),(''')
set #var1='('''+#var1+''')'
set #var1=replace(#var1,' ','')
set #query='insert into ##table1 values'+#var1
EXEC sp_executesql #query
IF OBJECT_ID(N'tempdb..##table2', N'U') IS NOT NULL
DROP TABLE ##table2;
select * into ##table2 from ##table1 order by cast(replace(replace(replace(col1,'IS-',''),'.a.',''),'.a','') as float)
declare #results varchar(max)
select #results = coalesce(#results + ', ', '') + convert(varchar(12),col1) from ##table2
select #results
DROP TABLE ##table1
DROP TABLE ##table2

SQL Find String

I would like to know if finding a string can be done from another table. It's a bit complicated.
Here's the table: (tbl_dishes)
| dish | Type |
| egg, hotdog & bread | Breakfast |
From the table above, I want to get the individual descriptions of the column dish from another table
2nd Table (tbl_Foods)
| food | Description |
| egg | Fresh |
| hotdog | red |
| bread | toasted |
| steak | meat |
Let's say my query would look like this: (but it's wrong)
SELECT food, description FROM tbl_Foods
WHERE food Exists IN (SELECT dish FROM tbl_Dishes)
My desired results would be:
| food | Description |
| egg | Fresh |
| hotdog | red |
| bread | toasted |
It's like getting all matched word in the dish column. I don't know if it's possible. Please help.
Thank you.
SELECT food, description
FROM tbl_Foods
join tbl_Dishes
on tbl_Dishes.dish like ('%' + tbl_Foods.food +'%')
You will need to split the list
DECLARE #DelimString VARCHAR(100)
SET DelimString = SELECT REPLACE(REPLACE(dish,'&',','),' ', '') FROM tbl_Dishes
DECLARE #Dish TABLE (Dish VARCHAR(50)); INSERT INTO #Dish SELECT CAST(ParamValue AS VARCHAR) FROM MultiValueParams_String(#DelimString)
Use this function.
Create function [dbo].[MultiValueParams_String] (#ParamList varchar(4000))
returns #Values table (RoNum INT,ParamValue varchar(4000))
as
begin
declare #Delim char(1) = ',' -- comma is always the delimiter
declare #Chrind int = 1
declare #Piece nvarchar(50)
declare #RoNum int = 0
while #Chrind>0
begin
select #Chrind=charindex(#Delim,#ParamList)
if #Chrind>0
select #Piece=left(#ParamList,#chrind-1)
else
select #Piece=#ParamList
insert #values(RoNum,ParamValue) values (#RoNum,#Piece)
select #ParamList = right(#ParamList,len(#ParamList)-#chrind)
if len(#ParamList)=0 break
SELECT #RoNum = #RoNum + 1
end
return
end
SELECT food, description
FROM tbl_Foods f
INNER JOIN #Dish d ON f.food = d.dish
Something like this.

Extract characters after a symbol in sql server 2012

I have a table List shown below:
+------+-------------------------------------+
| Code | name |
+------+-------------------------------------+
| A001 | ABBOTT_1000000 |
| A002 | AGCO_1000001 |
| A003 | ALFA LAVAL_1000002 |
| A004 | ALSTOM POWER INDIA LIMITED_1000003 |
| A005 | AMERICAN BUREAU OF SHIPPING_1000004 |
+------+-------------------------------------+
I need to update the table extracting the characters present after _ in name and replace them in code column. like this.
+---------+-------------------------------------+
| Code | name |
+---------+-------------------------------------+
| 1000000 | ABBOTT_1000000 |
| 1000001 | AGCO_1000001 |
| 1000002 | ALFA LAVAL_1000002 |
| 1000003 | ALSTOM POWER INDIA LIMITED_1000003 |
| 1000004 | AMERICAN BUREAU OF SHIPPING_1000004 |
+---------+-------------------------------------+
This is has to be done in sql server 2012. please help me.
Try this
with cte as
(
select substring(name,charindex('_',name)+1,len(name)) as ext_str,*
from yourtable
)
update cte set code = ext_str
You can try to use SUBSTRING in following:
SAMPLE DATA
CREATE TABLE #MyTable
(
Code NVARCHAR(60),
Name NVARCHAR(60)
)
INSERT INTO #MyTable VALUES
('A001','ABBOTT_1000000' ),
('A002','AGCO_1000001' ),
('A003','ALFA LAVAL_1000002' ),
('A004','ALSTOM POWER INDIA LIMITED_1000003' ),
('A005','AMERICAN BUREAU OF SHIPPING_1000004' )
QUERY
UPDATE #MyTable
SET Code = SUBSTRING(Name, CHARINDEX('_', Name) + 1, LEN(Name))
TESTING
SELECT * FROM #MyTable
DROP TABLE #MyTable
OUTPUT
Code Name
1000000 ABBOTT_1000000
1000001 AGCO_1000001
1000002 ALFA LAVAL_1000002
1000003 ALSTOM POWER INDIA LIMITED_1000003
1000004 AMERICAN BUREAU OF SHIPPING_1000004
SQL FIDDLE
DEMO
UPDATE <table>
SET name = STUFF(name, 1, CHARINDEX('_', name), '')
WHERE name like '%[_]%'
You can do this:
First, you select the number that you want to place as code
select substr(name,-1,7) from table_name
After this, you can update the table.So,The complete statement will be :
update table_name t set t.code = (select substr(name,-1,7) from table_name where code = t.code);
You can use RIGHT together with CHARINDEX:
SQL Fiddle
UPDATE tbl
SET Code = RIGHT(Name, LEN(Name) - CHARINDEX('_', Name))
WHERE CHARINDEX('_', Name) > 0