sql >> Database >  >> RDS >> Sqlserver

Gebruik T-SQL en retourneer het n-de gescheiden element van een string

Dit is het gemakkelijkste antwoord om de 67 (type-safe!! ):

SELECT CAST('<x>' + REPLACE('1,222,2,67,888,1111',',','</x><x>') + '</x>' AS XML).value('/x[4]','int')

Hieronder vindt u voorbeelden hoe u dit kunt gebruiken met variabelen voor de string, het scheidingsteken en de positie (zelfs voor edge-cases met XML-verboden tekens)

De makkelijke

Deze vraag gaat niet over een string-split-aanpak , maar over hoe je het n-de element kunt krijgen . De gemakkelijkste, volledig inlineable manier zou deze IMO zijn:

Dit is een echte oneliner om deel 2 begrensd te krijgen door een spatie:

DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')

Variabelen kunnen worden gebruikt met sql:variable() of sql:column()

Natuurlijk u kunt variabelen gebruiken voor scheidingsteken en positie (gebruik sql:column om de positie direct uit de waarde van een zoekopdracht te halen):

DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')

Edge-Case met XML-verboden tekens

Als uw tekenreeks verboden tekens kan bevatten , je kunt het nog steeds op deze manier doen. Gebruik gewoon FOR XML PATH eerst op je string om alle verboden tekens impliciet te vervangen door de passende escape-reeks.

Het is een heel speciaal geval als - bovendien - uw scheidingsteken de puntkomma is . In dit geval vervang ik eerst het scheidingsteken in '#DLMT#', en vervang dit ten slotte door de XML-tags:

SET @input=N'Some <, > and &;Other äöü@€;One more';
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)');

UPDATE voor SQL-Server 2016+

Helaas zijn de ontwikkelaars vergeten de index van het onderdeel terug te sturen met STRING_SPLIT . Maar met SQL-Server 2016+ is er JSON_VALUE en OPENJSON .

Met JSON_VALUE we kunnen de positie doorgeven als de index-array.

Voor OPENJSON de documentatie vermeldt duidelijk:

Wanneer OPENJSON een JSON-array parseert, retourneert de functie de indexen van de elementen in de JSON-tekst als sleutels.

Een tekenreeks zoals 1,2,3 heeft niets meer nodig dan haakjes:[1,2,3] .
Een reeks woorden zoals this is an example moet ["this","is","an"," example"] . zijn .
Dit zijn zeer eenvoudige tekenreeksbewerkingen. Probeer het gewoon:

DECLARE @str VARCHAR(100)='Hello John Smith';
DECLARE @position INT = 2;

--We can build the json-path '$[1]' using CONCAT
SELECT JSON_VALUE('["' + REPLACE(@str,' ','","') + '"]',CONCAT('$[',@position-1,']'));

--Zie dit voor een positieveilige string-splitter (op nul gebaseerd ):

SELECT  JsonArray.[key] AS [Position]
       ,JsonArray.[value] AS [Part]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]') JsonArray

In dit bericht heb ik verschillende benaderingen getest en ontdekt dat OPENJSON is echt snel. Zelfs veel sneller dan de beroemde "delimitedSplit8k()"-methode...

UPDATE 2 - Verkrijg de waarden typeveilig

We kunnen een array gebruiken binnen een array gewoon door verdubbelde [[]] . te gebruiken . Dit zorgt voor een getypte WITH -clausule:

DECLARE  @SomeDelimitedString VARCHAR(100)='part1|1|20190920';

DECLARE @JsonArray NVARCHAR(MAX)=CONCAT('[["',REPLACE(@SomeDelimitedString,'|','","'),'"]]');

SELECT @SomeDelimitedString          AS TheOriginal
      ,@JsonArray                    AS TransformedToJSON
      ,ValuesFromTheArray.*
FROM OPENJSON(@JsonArray)
WITH(TheFirstFragment VARCHAR(100) '$[0]'
    ,TheSecondFragment INT '$[1]'
    ,TheThirdFragment DATE '$[2]') ValuesFromTheArray


  1. MySQL relationele databases gebruiken op Arch Linux

  2. Oracle PL/SQL - Hoe maak ik een eenvoudige arrayvariabele aan?

  3. Wanneer of waarom een ​​SET DEFINE OFF gebruiken in Oracle Database?

  4. Plezier met (columnstore) compressie op een hele grote tafel – deel 2