À l'aide de SQL Server, comment fractionner une chaîne pour pouvoir accéder à l'élément x?
Prenez une chaîne "Bonjour John Smith". Comment puis-je diviser la chaîne par espace et accéder à l'élément à l'index 1 qui devrait retourner "John"?
sql
sql-server
tsql
split
GateKiller
la source
la source
Réponses:
Vous pouvez trouver la solution dans la fonction définie par l'utilisateur SQL pour analyser une chaîne délimitée utile (à partir du projet de code ).
Vous pouvez utiliser cette logique simple:
la source
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
et nonSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
qui fractionnera une chaîne et renverra un résultat de table à une colonne que vous pouvez utiliser dans uneSELECT
instruction ou ailleurs.Je ne crois pas que SQL Server possède une fonction de division intégrée, donc à part un UDF, la seule autre réponse que je connaisse est de détourner la fonction PARSENAME:
PARSENAME prend une chaîne et la divise sur le caractère point. Il prend un nombre comme deuxième argument, et ce nombre spécifie le segment de la chaîne à retourner (de l'arrière vers l'avant).
Le problème évident est lorsque la chaîne contient déjà un point. Je pense toujours que l'utilisation d'un UDF est la meilleure façon ... d'autres suggestions?
la source
SPLIT()
fonction n'est pas fournie car elle encourage une mauvaise conception de la base de données et la base de données ne sera jamais optimisée pour utiliser les données stockées dans ce format. Le SGBDR n'est pas obligé d'aider les développeurs faire des choses stupides qu'il a été conçu non à manipuler. La bonne réponse sera toujours "Normalisez votre base de données comme nous vous l'avions dit il y a 40 ans". Ni SQL ni le SGBDR ne sont à blâmer pour une mauvaise conception.Tout d'abord, créez une fonction (en utilisant CTE, l'expression de table commune élimine le besoin d'une table temporaire)
Ensuite, utilisez-le comme n'importe quelle table (ou modifiez-le pour l'adapter à votre proc stocké existant) comme ceci.
Mise à jour
La version précédente échouait pour une chaîne d'entrée supérieure à 4 000 caractères. Cette version prend en charge la limitation:
L'utilisation reste la même.
la source
100
(pour éviter une boucle infinie). Utilisez l' indication MAXRECURSION pour définir le nombre de niveaux de récursivité (0
à32767
,0
est "pas de limite" - peut écraser le serveur). BTW, bien meilleure réponse quePARSENAME
parce que c'est universel :-). +1maxrecursion
à cette solution, gardez à l'esprit cette question et ses réponses Comment configurer l'maxrecursion
option pour un CTE à l'intérieur d'une fonction table .s
n'est donc plus définieLa plupart des solutions utilisées ici utilisent des boucles while ou des CTE récursifs. Une approche basée sur un ensemble sera supérieure, je le promets, si vous pouvez utiliser un délimiteur autre qu'un espace:
Exemple d'utilisation:
Résultats:
Vous pouvez également ajouter l'
idx
argument souhaité comme argument à la fonction, mais je laisse cela comme exercice au lecteur.Vous ne pouvez pas le faire avec uniquement la fonction native
STRING_SPLIT
ajoutée dans SQL Server 2016, car il n'y a aucune garantie que le résultat sera rendu dans l'ordre de la liste d'origine. En d'autres termes, si vous réussissez,3,6,1
le résultat sera probablement dans cet ordre, mais il pourrait l' être1,3,6
. J'ai demandé l'aide de la communauté pour améliorer la fonction intégrée ici:Avec suffisamment de commentaires qualitatifs , ils peuvent en fait envisager d'apporter certaines de ces améliorations:
Plus d'informations sur les fonctions de fractionnement, pourquoi (et preuve que) alors que les boucles et les CTE récursifs ne sont pas mis à l'échelle, et de meilleures alternatives, si le fractionnement des chaînes provenant de la couche d'application:
Sur SQL Server 2016 ou supérieur, cependant, vous devriez regarder
STRING_SPLIT()
etSTRING_AGG()
:la source
select * from DBO.SplitString('Hello John smith', ' ');
et la sortie produite était: Valeur Bonjour ello llo lo o John ohn hn n smith mith ith th hVous pouvez tirer parti d'une table numérique pour effectuer l'analyse syntaxique des chaînes.
Créez une table de nombres physiques:
Créer une table de test avec 1000000 lignes
Créer la fonction
Utilisation (produit 3mil de lignes en 40s sur mon ordinateur portable)
nettoyer
Les performances ici ne sont pas étonnantes, mais appeler une fonction sur un million de lignes n'est pas la meilleure idée. Si vous effectuez une chaîne divisée sur plusieurs lignes, j'éviterais la fonction.
la source
desc
étaient supprimés?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
@NothingsImpossible s'est terminé en 1,5 minute. @hello_earth Comment comparerait votre solution sur des chaînes plus longues avec plus de 4 champs?Cette question ne concerne pas une approche de partage de chaînes , mais la façon d'obtenir le nième élément .
Toutes les réponses ici font une sorte de division de chaîne en utilisant récursion,
CTE
s, multipleCHARINDEX
,REVERSE
etPATINDEX
, inventant des fonctions, appel à des méthodes CLR, tableaux de nombres,CROSS APPLY
s ... La plupart des réponses couvrent de nombreuses lignes de code.Mais - si vous ne voulez vraiment rien de plus qu'une approche pour obtenir le nième élément - cela peut être fait comme une véritable doublure , pas d'UDF, pas même une sous-sélection ... Et comme avantage supplémentaire: tapez safe
Obtenez la partie 2 délimitée par un espace:
Bien sûr, vous pouvez utiliser des variables pour le délimiteur et la position (utilisez
sql:column
pour récupérer la position directement à partir de la valeur d'une requête):Si votre chaîne peut inclure des caractères interdits (en particulier un parmi
&><
), vous pouvez toujours le faire de cette façon. UtilisezFOR XML PATH
d'abord votre chaîne pour remplacer implicitement tous les caractères interdits par la séquence d'échappement appropriée.C'est un cas très spécial si - en plus - votre délimiteur est le point-virgule . Dans ce cas, je remplace d'abord le délimiteur par '# DLMT #', puis je le remplace par les balises XML:
MISE À JOUR pour SQL-Server 2016+
Malheureusement, les développeurs ont oublié de retourner l'index de la pièce avec
STRING_SPLIT
. Mais, en utilisant SQL-Server 2016+, il y aJSON_VALUE
etOPENJSON
.Avec
JSON_VALUE
nous pouvons passer en position de tableau d'index.Car
OPENJSON
la documentation indique clairement:Une chaîne comme
1,2,3
rien de plus que les besoins entre parenthèses:[1,2,3]
.Une chaîne de mots comme
this is an example
doit être["this","is","an","example"]
.Ce sont des opérations de chaîne très faciles. Essayez-le:
- Voir ceci pour un séparateur de chaîne sûr de position ( basé sur zéro ):
Dans cet article, j'ai testé différentes approches et j'ai trouvé que c'était
OPENJSON
vraiment rapide. Encore plus rapide que la fameuse méthode "delimitedSplit8k ()" ...UPDATE 2 - Obtenez les valeurs de type sécurisé
Nous pouvons utiliser un tableau dans un tableau simplement en utilisant doublé
[[]]
. Cela permet uneWITH
clause typée :la source
<x><![CDATA[x<&>x]]></x>
.CDATA
sections peuvent gérer cela aussi ... Mais après le casting, elles ont disparu (changé en échappétext()
implicitement). Je n'aime pas la magie sous le capot , donc je préfère l'(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
approche -. Cela me semble plus propre et se produit de toute façon ... (Un peu plus sur CDATA et XML ).Voici un UDF qui le fera. Il renverra un tableau des valeurs délimitées, je n'ai pas essayé tous les scénarios mais votre exemple fonctionne bien.
Vous l'appeleriez ainsi:
Edit: Solution mise à jour pour gérer les délimiteurs avec un len> 1 comme dans:
la source
Ici je poste un moyen simple de solution
Exécutez la fonction comme ceci
la source
À mon avis, vous rendez les choses beaucoup trop compliquées. Il suffit de créer un UDF CLR et d'en finir.
la source
Qu'en est-il de l'utilisation
string
et de lavalues()
déclaration?Ensemble de résultats atteint.
la source
J'utilise la réponse de Frederic mais cela n'a pas fonctionné dans SQL Server 2005
Je l'ai modifié et j'utilise
select
avecunion all
et ça marcheEt l'ensemble de résultats est:
la source
EXEC
.EXEC
appelle implicitement une procédure stockée et vous ne pouvez pas utiliser de procédures stockées dans les FDU.Ce modèle fonctionne bien et vous pouvez généraliser
notez FIELD , INDEX et TYPE .
Laissez une table avec des identifiants comme
Ensuite, vous pouvez écrire
fendre et couler toutes les pièces.
la source
Si votre base de données a un niveau de compatibilité de 130 ou supérieur, vous pouvez utiliser la fonction STRING_SPLIT avec les clauses OFFSET FETCH pour obtenir l'élément spécifique par index.
Pour obtenir l'élément à l' index N (basé sur zéro), vous pouvez utiliser le code suivant
Pour vérifier le niveau de compatibilité de votre base de données , exécutez ce code:
la source
xml
approche basée sur -split, car elle permet de récupérer la valeur de type sécurisé et n'a pas besoin d'une sous-requête, mais c'est un bon. +1 de mon côtéSTRING_SPLIT
demandes pour v2016 +. Dans ce cas, il est préférable d'utiliserOPENJSON
ouJSON_VALUE
. Vous voudrez peut-être vérifier ma réponseJe cherchais la solution sur le net et ce qui suit fonctionne pour moi. Réf. .
Et vous appelez la fonction comme ceci:
la source
Encore une autre partie de la chaîne par fonction de délimitation:
et l'utilisation:
qui renvoie:
la source
Essaye ça:
Testez-le comme ceci:
la source
L'exemple suivant utilise un CTE récursif
Mise à jour 18.09.2013
Démo sur SQLFiddle
la source
la source
Vous pouvez fractionner une chaîne en SQL sans avoir besoin d'une fonction:
Si vous devez prendre en charge des chaînes arbitraires (avec des caractères spéciaux xml)
la source
Je sais que c'est une vieille question, mais je pense que quelqu'un peut bénéficier de ma solution.
SQL FIDDLE
Avantages:
Limites:
Remarque : la solution peut donner une sous-chaîne jusqu'à N.
Pour surmonter la limitation, nous pouvons utiliser la référence suivante .
Mais encore une fois la solution ci-dessus ne peut pas être utilisée dans une table (en fait, je n'ai pas pu l'utiliser).
Encore une fois, j'espère que cette solution pourra aider quelqu'un.
Mise à jour: En cas d'enregistrements> 50000, il n'est pas conseillé de l'utiliser
LOOPS
car cela dégraderait les performancesla source
Solution basée sur un ensemble pur utilisant
TVF
avec récursifCTE
. Vous pouvezJOIN
etAPPLY
cette fonction à n'importe quel ensemble de données.Usage:
Résultat:
la source
Presque toutes les autres réponses remplacent la chaîne en cours de fractionnement qui gaspille les cycles CPU et effectue des allocations de mémoire inutiles.
Je couvre une bien meilleure façon de faire un split de chaîne ici: http://www.digitalruby.com/split-string-sql-server/
Voici le code:
la source
Solution CTE récursive avec des problèmes de serveur, testez-la
Configuration du schéma MS SQL Server 2008 :
Requête 1 :
Résultats :
la source
bien que similaire à la réponse basée sur xml de josejuan, j'ai trouvé que le traitement du chemin xml une seule fois, puis le pivotement était modérément plus efficace:
couru en 8:30
couru en 9:20
la source
ET L'UTILISER
la source
si quelqu'un veut obtenir une seule partie du texte séparé, vous pouvez l'utiliser
sélectionnez * parmi fromSplitStringSep ('Word1 wordr2 word3', '')
la source
J'ai développé ça,
la seule attention que vous devriez faire est le point '.' cette extrémité du @x doit toujours être là.
la source
en s'appuyant sur la solution @NothingsImpossible ou, plutôt, en commentant la réponse la plus votée (juste en dessous de la solution acceptée), j'ai trouvé que la solution rapide et sale suivante répond à mes propres besoins - elle a l'avantage d'être uniquement dans le domaine SQL.
étant donné une chaîne "premier; deuxième; troisième; quatrième; cinquième", disons, je veux obtenir le troisième jeton. cela ne fonctionne que si nous savons combien de jetons la chaîne va avoir - dans ce cas, c'est 5. donc ma façon d'agir est de couper les deux derniers jetons (requête interne), puis de couper les deux premiers jetons ( requête externe)
je sais que c'est moche et couvre les conditions spécifiques dans lesquelles j'étais, mais je le poste juste au cas où quelqu'un le trouverait utile. à votre santé
la source
la source
À partir de SQL Server 2016, nous string_split
la source
STRING_SPLIT
ne garantit pas de retourner la même commande. Mais leOPENJSON
fait (voir ma réponse (section mise à jour) )