2

Heads!

In my database, I have a column that contains the following data (examples):

H-01-01-02-01

BLE-01-03-01

H-02-05-1.1-03

The task is to get the second to last element of the array if you would split that using the "-" character. The strings are of different length.

So this would be the result using the above mentioned data:

02

03

1.1

Basically I'm searching for an equivalent of the following ruby-statement for use in a Select-Statement in SQL-Server:

"BLE-01-03-01".split("-")[-2]

Is this possible in any way in SQL Server? After spending some time searching for a solution, I only found ones that work for the last or first element.

Thanks very much for any clues or solutions!

PS: Version of SQL Server is Microsoft SQL Server 2012

4
  • Which version of SQL Server? Commented Oct 23, 2019 at 10:06
  • If you only want the second to last, you might get better performance using charindex, substring and reverse instead of actually splitting the string. Commented Oct 23, 2019 at 10:07
  • Substring is not really possible because the strings are of different length. I also edited the post to include the SQL Server Version. Commented Oct 23, 2019 at 10:10
  • That's why you need charindex Commented Oct 23, 2019 at 10:16

4 Answers 4

2

As an alternative you can try this:.

--A mockup table with some test data to simulate your issue

DECLARE @mockupTable TABLE (ID INT IDENTITY, YourColumn VARCHAR(50));
INSERT INTO @mockupTable VALUES 
 ('H-01-01-02-01') 
,('BLE-01-03-01')
,('H-02-05-1.1-03');

--The query

SELECT CastedToXml.value('/x[sql:column("CountOfFragments")-1][1]','nvarchar(10)') AS TheWantedFragment
FROM @mockupTable t
CROSS APPLY(SELECT CAST('<x>' + REPLACE(t.YourColumn,'-','</x><x>') + '</x>' AS XML))A(CastedToXml)
CROSS APPLY(SELECT CastedToXml.value('count(/x)','int')) B(CountOfFragments);

The idea in short:

The first APPLY will transform the string to a XML like this

<x>H</x>
<x>01</x>
<x>01</x>
<x>02</x>
<x>01</x>

The second APPLY will xquery into this XML to get the count of fragments. As APPLY will add this as a column to the result set, we can use the value using sql:column() to get the wanted fragment by its position.

Sign up to request clarification or add additional context in comments.

Comments

1

As I wrote in my comment - using charindex with reverse.

First, create and populate sample table (Please save us this step in your future questions):

DECLARE @T AS TABLE
(
    Col Varchar(100)
);

INSERT INTO @T (Col) VALUES
('H-01-01-02-01'),
('BLE-01-03-01'),
('H-02-05-1.1-03');

The query:

SELECT  Col, 
        LEFT(RIGHT(Col, AlmostLastDelimiter-1), AlmostLastDelimiter - LastDelimiter - 1) As SecondToLast
FROM @T 
CROSS APPLY (SELECT CharIndex('-', Reverse(Col)) As LastDelimiter) As A
CROSS APPLY (SELECT CharIndex('-', Reverse(Col), LastDelimiter+1) As AlmostLastDelimiter) As B

Results:

Col             SecondToLast
H-01-01-02-01   02
BLE-01-03-01    03
H-02-05-1.1-03  1.1

Comments

1

Similar to Zohar's solution, but using CTEs instead of CROSS APPLY to prevent redundancy. I personally find this easier to follow, as you can see what happens in each step. Doesn't make it a better solution though ;)

DECLARE @strings TABLE (data VARCHAR(50));
INSERT INTO @strings VALUES ('H-01-01-02-01') , ('BLE-01-03-01'), ('H-02-05-1.1-03');
WITH rev AS (
    SELECT
        data,
        REVERSE(data) AS reversed
    FROM
        @strings),
first_hyphen AS (
    SELECT
        data,
        reversed,
        CHARINDEX('-', reversed) + 1 AS first_pos
    FROM
        rev),
second_hyphen AS (
    SELECT
        data,
        reversed,
        first_pos,
        CHARINDEX('-', reversed, first_pos) AS second_pos
    FROM
        first_hyphen)
SELECT
    data,
    REVERSE(SUBSTRING(reversed, first_pos, second_pos - first_pos)) AS result
FROM
    second_hyphen;

Results:

data            result
H-01-01-02-01   02
BLE-01-03-01    03
H-02-05-1.1-03  1.1

Comments

0

Try this

declare @input NVARCHAR(100)
declare @dlmt NVARCHAR(3);
declare @pos INT = 2
SET @input=REVERSE(N'H-02-05-1.1-03');
SET @dlmt=N'-';
SELECT 
    CAST(N'<x>' 
    + REPLACE(
                (SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH(''))
                    ,N'#DLMT#',N'</x><x>'
              ) + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.