sql >> Databáze >  >> RDS >> Sqlserver

Pomocí T-SQL vraťte n-tý prvek s oddělovači z řetězce

Toto je nejjednodušší odpověď, jak získat 67 (typově bezpečné!! ):

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

V následujícím textu naleznete příklady, jak to použít s proměnnými pro řetězec, oddělovač a pozici (i pro okrajové případy se znaky zakázanými v XML)

Ten snadný

Tato otázka se netýká přístupu založeného na rozdělení řetězce , ale o tom, jak získat n-tý prvek . Nejjednodušší, plně inlineable způsob by byl tento IMO:

Toto je skutečný jednovrstvý chcete-li získat část 2 oddělenou mezerou:

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)')

Proměnné lze použít s sql:variable() nebo sql:column()

Samozřejmě můžete použít proměnné pro oddělovač a pozici (použijte sql:column pro načtení pozice přímo z hodnoty dotazu):

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 se znaky zakázanými XML

Pokud váš řetězec může obsahovat zakázané znaky , stále to můžete udělat tímto způsobem. Stačí použít FOR XML PATH na vašem řetězci, abyste implicitně nahradili všechny zakázané znaky vhodnou escape sekvencí.

Je to velmi zvláštní případ, pokud – navíc – vaším oddělovačem je středník . V tomto případě nejprve nahradím oddělovač na '#DLMT#' a nakonec ho nahrazuji značkami XML:

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)');

AKTUALIZACE pro SQL-Server 2016+

Vývojáři bohužel zapomněli vrátit index součásti pomocí STRING_SPLIT . Ale při použití SQL-Server 2016+ existuje JSON_VALUE a OPENJSON .

S JSON_VALUE můžeme předat pozici jako pole indexu.

Pro OPENJSON dokumentace jasně uvádí:

Když OPENJSON analyzuje pole JSON, funkce vrátí indexy prvků v textu JSON jako klíče.

Řetězec jako 1,2,3 nepotřebuje nic víc než závorky:[1,2,3] .
Řetězec slov jako this is an example musí být ["this","is","an"," example"] .
Jsou to velmi snadné operace s řetězci. Prostě to vyzkoušejte:

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,']'));

--Podívejte se na informace o bezpečném rozdělování řetězců (založené na nule ):

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

V tomto příspěvku jsem testoval různé přístupy a zjistil jsem, že OPENJSON je opravdu rychlý. Dokonce mnohem rychlejší než slavná metoda „delimitedSplit8k()“...

AKTUALIZACE 2 – Získejte hodnoty typově bezpečné

Můžeme použít pole v poli jednoduše pomocí zdvojeného [[]] . To umožňuje zadaný WITH -klauzule:

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. Záloha SQL Server 2017 -2

  2. použijte proměnnou pro název tabulky v mysql sproc

  3. Postgres UUID JDBC nefunguje

  4. Jak odeslat libovolné parametry do triggeru Oracle?