This question already has answers here:
T-SQL split string based on delimiter
(9 answers)
Closed 6 years ago.
Got dbo where i need to split it into two, after first '-' character. Working on SSMS 2014
example in spreadsheet:
example
PartNumber holds data which needs to be break up.
Part - Need to have all characters before first '-'
Number - need to have all characters after first '-'
Any help appreciated
thanks
You need LEFT and RIGHT. And to find the location where you want to split to LEFT and RIGHT, us CHARINDEX.
Maybe something like this?
SELECT parts.PartID as ID,
Part = (SELECT TOP 1 value FROM STRING_SPLIT(parts.PartNumber, '-')),
Number = (SELECT value FROM STRING_SPLIT(parts.PartNumber, '-') LIMIT 1 OFFSET 1),
FROM dbo.PartsTable parts
You could try this.
SELECT
PartNum
, REPLACE(LEFT(PartNum, CHARINDEX('-', PartNum)),'-', '') as 'PartNum First'
, REPLACE(SUBSTRING(PartNum,CHARINDEX('-', PartNum), LEN(PartNum)), '-','') as 'PartNum Second'
FROM Part
The query above splits the PartNum string when it finds '-', it then replaces it with a blank space so you have the result you expected.
I tried it and it works. Hope it's useful to you.
Declare #YourTable table (PartNumber varchar(50))
Insert Into #YourTable values
('HHY-12-1800-2'),
('FC-P-41-4')
Select PartNumber
,Part = Left(PartNumber,CharIndex('-',PartNumber)-1)
,Number = Substring(PartNumber,CharIndex('-',PartNumber)+1,Len(PartNumber))
From #YourTable
Returns
PartNumber Part Number
HHY-12-1800-2 HHY 12-1800-2
FC-P-41-4 FC P-41-4
Related
I want to reverse the sub-strings in NVARCHAR column, that are separated by one character like '-', for example:
Input column cl:
a1-b1-c1-d1
Required output:
d1-c1-b1-a1
I tried REVERSE(cl), the result was 1d-1c-1b-1a!
The best approach I think is using:
STRING_SPLIT(cl,'-')
And then looking for reversing the resulted sub strings and rejoining them, but since we don't know how many delimited sub strings, it is still difficult to handle.
How can we achieve this?
Thank you in advance
REVERSE isn't what you are after here. What you are after is a string splitter that supports (is aware of) ordinal positions; STRING_SPLIT is documented that it explicitly "doesn't care" about the ordinal positions of values in a delimited string.
One function that is aware of ordinal positions is DelimitedSplit8k_LEAD. You can then use that, along with STRING_AGG to recreate your delimited string:
SELECT STRING_AGG(DS.item,'-') WITHIN GROUP (ORDER BY DS.ItemNumber DESC) AS R
FROM (VALUES('a1-b1-c1-d1'))V(S)
CROSS APPLY dbo.DelimitedSplit8K_LEAD(V.S,'-') DS;
Of course, the real solution here is to stop storing delimited data in your database in the first place.
If using an UDF is not an option, you may try a JSON-based approach. You need to transform the input values into a valid JSON array (a1-b1-c1-d1 into ["a1", "b1","c1","d1"]) and parse this array with OPENJSON():
CREATE TABLE Data (ColumnData nvarchar(max))
INSERT INTo Data (ColumnData) VALUES (N'a1-b1-c1-d1')
UPDATE Data
SET ColumnData = (
SELECT STRING_AGG([value], N'-') WITHIN GROUP (ORDER BY CONVERT(int, [key]) DESC)
FROM OPENJSON(CONCAT(N'["', REPLACE(STRING_ESCAPE(ColumnData, 'json'), N'-', '","'), '"]'))
)
Result:
ColumnData
-----------
d1-c1-b1-a1
If you have a modern version of SQL Server (2016 or higher), you can do it as you said: you split the string with string_split, you reverse its order, and aggregate the result with string_agg.
with cte as (
select value,
row_number() over (order by (select null)) as number
from string_split('a1-b1-c1-d1', '-')
)
select string_agg(value, '-') within group (order by number desc)
from cte
This splits the string while preserving the ordinal position without using a custom splitter. To preserve the ordering of words the CHARINDEX function is used as per this.
declare
#string nvarchar(4000)='a1-b1-c1-d1',
#added_delimitter CHAR(1)= '-';
;with ndx_split_cte(split_val, split_ndx) as (
select
sp.[value],
CHARINDEX(#added_delimitter + sp.[value] + #added_delimitter, #added_delimitter + #string + #added_delimitter)
from
string_split(#string, '-') sp)
select string_agg(split_val, '-') within group (order by split_ndx desc) rev_split_str
from ndx_split_cte;
Results
rev_split_str
d1-c1-b1-a1
I am using a column which is named ItemCode. ItemCode is Varchar(50) type.
Here is my query
Select * from Inventory order by ItemCode
So, now my result is looks like
ItemCode-1
ItemCode-10
ItemCode-2
ItemCode-20
And so on.
How can I order my string as the example below?
ItemCode-1
ItemCode-2
ItemCode-10
ItemCode-20
Should I convert my column as number? Also I mention that I have some fields that contain no number.
You could order by the numbers as
SELECT Str
FROM
(
VALUES
('ItemCode-1'),
('ItemCode-10'),
('ItemCode-2'),
('ItemCode-20')
) T(Str)
ORDER BY CAST(RIGHT(Str, LEN(Str) - CHARINDEX('-', Str)) AS INT)
Note: Since you tagged your Q with SQL Server 2008 tag, you should upgrade as soon as possible because it's out of support.
UPDATE:
Since you don't provide a good sample data, I'm just guessing.
Here is another way may feet your requirements
SELECT Str
FROM
(
VALUES
('ItemCode-1'),
('ItemCode-10'),
('ItemCode-2'),
('ItemCode-20'),
('Item-Code')
) T(Str)
ORDER BY CASE WHEN Str LIKE '%[0-9]' THEN CAST(RIGHT(Str, LEN(Str) - CHARINDEX('-', Str)) AS INT) ELSE 0 END
This is an expected behavior, based on this:
that is lexicographic sorting which means basically the language
treats the variables as strings and compares character by character
You need to use something like this:
ORDER BY
CASE WHEN ItemCode like '%[0-9]%'
THEN Replicate('0', 100 - Len(ItemCode)) + ItemCode
ELSE ItemCode END
This question already has answers here:
How do I split a delimited string so I can access individual items?
(46 answers)
Splitting a Full Name into First and Last Name
(7 answers)
Closed 3 years ago.
I am trying to split names into columns, for example, column 1 named "Name would contain in row 1 the varChar "Jesus Lopez" How could I split it up so that I can create a second column with row 1 to contain "Jesus" and a third column with row 1 to contain "Lopez". I can only use string functions to accomplish this task.
I thought about using the Left() function and Nest Charindex() to find the first set of string. I'm trying to figure out gather the rest of the name and put it on its own column.
Select Name,
Left(Name, Charindex(' ', Name)) as FirstName,
From Person.StateProvince
I expect to have a total of 3 columns. One with the original name, another with the first name only, and lastly a third column with what ever is left from the data in the first column.
What is the requirement with the spaces? Considering you want to ignore any leading or trailing spaces for the values, and making the value as NULL when the value is not there, this would work:
SELECT Name
,FirstName = CASE WHEN CHARINDEX(' ', LTRIM(Name)) > 1 THEN LEFT(LTRIM(Name), CHARINDEX(' ', LTRIM(Name))-1) WHEN LEN(LTRIM(RTRIM(Name))) > 1 THEN LTRIM(RTRIM(Name)) ELSE NULL END
,Remaining = CASE WHEN CHARINDEX(' ', LTRIM(RTRIM(Name))) > 0 THEN LTRIM(SUBSTRING(LTRIM(Name),CHARINDEX(' ', LTRIM(Name))+1, LEN(LTRIM(Name)) - CHARINDEX(' ', LTRIM(Name)))) ELSE NULL END
FROM Person.StateProvince;
If you're string has not more than four parts then you could use PARSENAME
SELECT [Name]
,PARSENAME(REPLACE([Name],' ','.'),4) AS Part1
,PARSENAME(REPLACE([Name],' ','.'),3) AS Part2
,PARSENAME(REPLACE([Name],' ','.'),2) AS Part3
,PARSENAME(REPLACE([Name],' ','.'),1) AS Part4
FROM #temp
This question already has answers here:
Using T-SQL, return nth delimited element from a string
(14 answers)
Closed 4 years ago.
I'm using below query to split the names as shown below:
select value from STRING_SPLIT('Name1~Name2~Name3' , '~' );
How to get second name i.e, Name2, without using WHERE condition?
Note: Names can be dynamic
Try PARSENAME function
SELECT PARSENAME( REPLACE('Name1~Name2~Name3','~','.'),2)
output
Name2
PARSENAME Returns the specified part of an object name. The parts of an object that can be retrieved are the object name, owner name,
database name, and server name.
Instead of using STRING_SPLIT you can convert your string to XML and then use .value to retrieve the 2nd element:
SELECT CAST('<t>' + REPLACE('Name1~Name2~Name3' , '~','</t><t>') + '</t>' AS XML).value('/t[2]','varchar(50)')
Try below code:
SELECT TOP 1 T.* FROM
(SELECT TOP 2 * FROM STRING_SPLIT('Name1~Name2~Name3' , '~' ) ORDER BY value ASC) AS T
ORDER BY value DESC;
This question already has answers here:
How to use GROUP BY to concatenate strings in SQL Server?
(22 answers)
Closed 7 years ago.
I have a table which looks like the following:
EventProfileID ParamName ParamValue
1 _CommandText usp_storedproc_1
2 _CommandText usp_storedproc_2
2 _CommandText usp_storedproc_3
2 _CommandText usp_storedproc_100
3 _CommandText usp_storedproc_11
3 _CommandText usp_storedproc_123
What I would like my output to be is the following:
EventProfileID ParamValue
1 usp_storedproc_1
2 usp_storedproc_2, usp_storedproc_3, usp_storedproc_100
3 usp_storedproc_11, usp_storedproc_123
However I am having some bother. If I do a select on one of the event profile ID's I can get an output using the following logic:
SELECT LEFT(c.ParamValue, LEN(c.ParamValue) - 1)
FROM (
SELECT a.ParamValue + ', '
FROM DP_EventProfileParams AS a
WHERE a.ParamName = '_CommandText'
and a.EventProfileId = '13311'
FOR XML PATH ('')
) c (paramvalue)
However that just gives me the output for one EventProfileID and also I would like the EventProfileID as part of the output.
Can anyone give me any pointers in the right direction into how I can expand my code to include this and allow the code to be dynamic so that I can show all EventProfileID's?
Thanks
You can do it this way:
select distinct a.EventProfileID,
stuff((select ','+ ParamValue)
from DP_EventProfileParams s
where s.EventProfileID = a.EventProfileID
for XML path('')),1,1,'')
from DP_EventProfileParams a
You were on the right track with for XML path. STUFF function makes it easier to achieve what you want.
The original query does not work because it uses simple subquery (works only for one specific id)
To make it work for all ids you can use XML + STUFF inside correlated subquery:
Many queries can be evaluated by executing the subquery once and
substituting the resulting value or values into the WHERE clause of
the outer query. In queries that include a correlated subquery (also
known as a repeating subquery), the subquery depends on the outer
query for its values. This means that the subquery is executed
repeatedly, once for each row that might be selected by the outer
query.
SELECT DISTINCT
EventProfileID,
[ParamVaues] =
STUFF((SELECT ',' + d2.ParamValue
FROM #DP_EventProfileParams d2
WHERE d1.EventProfileID = d2.EventProfileID
AND d2.ParamName = '_CommandText'
FOR XML PATH('')), 1, 1, '')
FROM #DP_EventProfileParams d1
ORDER BY EventProfileID;
LiveDemo
I strongly suggest reading Concatenating Row Values in Transact-SQL