web-dev-qa-db-fra.com

Chaîne scindée T-SQL basée sur un délimiteur

Je souhaite scinder certaines données sur la base d'un délimiteur qui peut exister ou non. 

Exemple de données:

John/Smith
Jane/Doe
Steve
Bob/Johnson

J'utilise le code suivant pour scinder ces données en noms et prénoms:

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable

Les résultats que je voudrais:

FirstName---LastName
John--------Smith
Jane--------Doe
Steve-------NULL
Bob---------Johnson

Ce code fonctionne très bien tant que toutes les lignes ont le délimiteur anticipé, mais il y a erreur quand une ligne ne le fait pas:

"Invalid length parameter passed to the LEFT or SUBSTRING function."

Comment une réécriture peut-elle fonctionner correctement?

38
Sesame

Peut-être que cela vous aidera.

SELECT SUBSTRING(myColumn, 1, CASE CHARINDEX('/', myColumn)
            WHEN 0
                THEN LEN(myColumn)
            ELSE CHARINDEX('/', myColumn) - 1
            END) AS FirstName
    ,SUBSTRING(myColumn, CASE CHARINDEX('/', myColumn)
            WHEN 0
                THEN LEN(myColumn) + 1
            ELSE CHARINDEX('/', myColumn) + 1
            END, 1000) AS LastName
FROM MyTable
55
sureshhh

Pour ceux qui recherchent des réponses à SQL Server 2016+. Utilisez la fonction STRING_SPLIT intégrée 

Par exemple:

DECLARE @tags NVARCHAR(400) = 'clothing,road,,touring,bike'  

SELECT value  
FROM STRING_SPLIT(@tags, ',')  
WHERE RTRIM(value) <> '';  

Référence: https://msdn.Microsoft.com/en-nz/library/mt684588.aspx

6
raga
 CHOISIR LE CAS 
 WHEN CHARINDEX ('/', maColonne, 0) = 0 
 PUIS ma colonne 
 ELSE LEFT (myColumn, CHARINDEX ('/', myColumn, 0) -1) 
 END AS Prénom 
 ,CAS 
 WHEN CHARINDEX ('/', maColonne, 0) = 0 
 PUIS ''
 ELSE RIGHT (myColumn, CHARINDEX ('/', REVERSE (myColumn), 0) -1) 
 END AS LastName 
 FROM MyTable 
5
chaitanya.moguluri

Essayez de filtrer les lignes qui contiennent des chaînes avec le délimiteur et travaillez sur celles-ci uniquement:

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable
WHERE CHARINDEX('/', myColumn) > 0

Ou

SELECT SUBSTRING(myColumn, 1, CHARINDEX('/', myColumn)-1) AS FirstName,
       SUBSTRING(myColumn, CHARINDEX('/', myColumn) + 1, 1000) AS LastName
FROM   MyTable
WHERE myColumn LIKE '%/%'
4
jpw
ALTER FUNCTION [dbo].[split_string](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
AS
BEGIN
  DECLARE @xml XML
  SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'

  INSERT INTO @t(val)
  SELECT  r.value('.','varchar(MAX)') as item
  FROM  @xml.nodes('/t') as records(r)
  RETURN
END
0
Bruno

Les exemples ci-dessus fonctionnent bien lorsqu'il n'y a qu'un seul délimiteur, mais ils ne s'adaptent pas bien à plusieurs délimiteurs. Notez que cela ne fonctionnera que pour SQL Server 2016 et versions ultérieures.

/*Some Sample Data*/
DECLARE @mytable TABLE ([id] VARCHAR(10), [name] VARCHAR(1000));
INSERT INTO @mytable
VALUES ('1','John/Smith'),('2','Jane/Doe'), ('3','Steve'), ('4','Bob/Johnson')


/*Split based on delimeter*/
SELECT P.id, [1] 'FirstName', [2] 'LastName', [3] 'Col3', [4] 'Col4'
FROM(
    SELECT A.id, X1.VALUE, ROW_NUMBER() OVER (PARTITION BY A.id ORDER BY A.id) RN
    FROM @mytable A
    CROSS APPLY STRING_SPLIT(A.name, '/') X1
    ) A
PIVOT (MAX(A.[VALUE]) FOR A.RN IN ([1],[2],[3],[4],[5])) P
0
James Moore