Con SQL Server, ¿cómo divido una cadena para poder acceder al elemento x?
Tome una cadena "Hola John Smith". ¿Cómo puedo dividir la cadena por espacio y acceder al elemento en el índice 1 que debería devolver "John"?
sql
sql-server
tsql
split
GateKiller
fuente
fuente
Respuestas:
Puede encontrar útil la solución en la función definida por el usuario de SQL para analizar una cadena delimitada (desde The Code Project ).
Puedes usar esta lógica simple:
fuente
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
noSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
que dividirá una cadena y devolverá un resultado de tabla de una columna que puede usar en unaSELECT
declaración o en otro lugar.No creo que SQL Server tenga una función de división integrada, por lo que, aparte de un UDF, la única otra respuesta que conozco es secuestrar la función PARSENAME:
PARSENAME toma una cadena y la divide en el carácter de punto. Toma un número como su segundo argumento, y ese número especifica qué segmento de la cadena devolver (trabajando de atrás hacia adelante).
El problema obvio es cuando la cadena ya contiene un punto. Sigo pensando que usar un UDF es la mejor manera ... ¿alguna otra sugerencia?
fuente
SPLIT()
No se proporciona una función porque fomenta el diseño deficiente de la base de datos, y la base de datos nunca se optimizará para usar datos almacenados en este formato. El RDBMS no está obligado a ayudar a los desarrolladores a hacer cosas estúpidas para las que ha sido diseñado para no manejar. La respuesta correcta siempre será "Normalice su base de datos como le dijimos hace 40 años". Ni SQL ni RDBMS tienen la culpa de un diseño deficiente.Primero, cree una función (usando CTE, la expresión de tabla común elimina la necesidad de una tabla temporal)
Luego, úselo como cualquier tabla (o modifíquelo para que se ajuste a su proceso almacenado existente) como este.
Actualizar
La versión anterior fallaría para una cadena de entrada de más de 4000 caracteres. Esta versión se encarga de la limitación:
El uso sigue siendo el mismo.
fuente
100
(para evitar el bucle infinito). Use la sugerencia MAXRECURSION para definir el número de niveles de recursión (0
hasta32767
,0
es "sin límite", puede aplastar el servidor). Por cierto, mucho mejor respuesta quePARSENAME
, porque es universal :-). +1maxrecursion
de esta solución, tenga en cuenta esta pregunta y sus respuestas. Cómo configurar lamaxrecursion
opción para un CTE dentro de una función con valores de tabla .s
lo que ya no está definidoLa mayoría de las soluciones aquí usan bucles while o CTE recursivos. Un enfoque basado en conjuntos será superior, lo prometo, si puede usar un delimitador que no sea un espacio:
Uso de la muestra:
Resultados:
También puedes agregar el
idx
que desee como argumento a la función, pero lo dejaré como ejercicio para el lector.No puede hacer esto solo con la función nativa
STRING_SPLIT
agregada en SQL Server 2016, porque no hay garantía de que la salida se procesará en el orden de la lista original. En otras palabras, si pasa3,6,1
el resultado, es probable que esté en ese orden, pero podría serlo1,3,6
. He pedido la ayuda de la comunidad para mejorar la función incorporada aquí:Con suficientes comentarios cualitativos , en realidad pueden considerar hacer algunas de estas mejoras:
Más información sobre las funciones divididas, por qué (y prueba de ello) mientras que los bucles y los CTE recursivos no se escalan, y mejores alternativas, si las cadenas de división provienen de la capa de aplicación:
Sin embargo, en SQL Server 2016 o superior, debe mirar
STRING_SPLIT()
ySTRING_AGG()
:fuente
select * from DBO.SplitString('Hello John smith', ' ');
y la salida producida fue: Valor Hola llo llo o John ohn hn n smith mith ith th hPuede aprovechar una tabla de números para analizar las cadenas.
Crea una tabla de números físicos:
Crear tabla de prueba con 1000000 filas
Crea la función
Uso (produce 3mil filas en 40s en mi computadora portátil)
limpiar
El rendimiento aquí no es sorprendente, pero llamar a una función en una tabla de un millón de filas no es la mejor idea. Si realiza una cadena dividida en muchas filas, evitaría la función.
fuente
desc
se eliminaran?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
desde @NothingsImpossible se completó en 1,5 minutos. @hello_earth ¿Cómo se compararía su solución en cadenas más largas con más de 4 campos?Esta pregunta es no se trata de un enfoque de división de cadenas , sino de cómo obtener el enésimo elemento .
Todas las respuestas aquí están haciendo algún tipo de división de cadenas usando recursividad,
CTE
s, múltipleCHARINDEX
,REVERSE
yPATINDEX
, inventando funciones, llamada a los métodos de CLR, tablas de números,CROSS APPLY
es ... La mayoría de las respuestas cubre muchas líneas de código.Pero, si realmente no quieres nada más que un enfoque para obtener el enésimo elemento , esto se puede hacer como una sola línea real , sin UDF, ni siquiera una sub-selección ... Y como un beneficio adicional: escriba seguro
Obtenga la parte 2 delimitada por un espacio:
Por supuesto , puede usar variables para delimitador y posición (use
sql:column
para recuperar la posición directamente del valor de una consulta):Si su cadena puede incluir caracteres prohibidos (especialmente uno entre
&><
), aún puede hacerlo de esta manera. Solo useFOR XML PATH
en su cadena primero para reemplazar todos los caracteres prohibidos con la secuencia de escape adecuada implícitamente.Es un caso muy especial si, además, su delimitador es el punto y coma . En este caso, reemplazo el delimitador primero en '# DLMT #' y finalmente lo reemplazo por las etiquetas XML:
ACTUALIZACIÓN para SQL-Server 2016+
Lamentablemente, los desarrolladores olvidaron devolver el índice de la pieza
STRING_SPLIT
. Pero, usando SQL-Server 2016+, hayJSON_VALUE
yOPENJSON
.Con
JSON_VALUE
podemos pasar en la posición como el índice 'matriz.Para
OPENJSON
la documentación indica claramente:Una cadena como
1,2,3
necesita nada más que entre paréntesis:[1,2,3]
.Una cadena de palabras como
this is an example
debe ser["this","is","an","example"]
.Estas son operaciones de cadena muy fáciles. Solo pruébalo:
- Vea esto para un separador de cadenas seguro para la posición ( basado en cero ):
En esta publicación probé varios enfoques y descubrí que
OPENJSON
es realmente rápido. Incluso mucho más rápido que el famoso método "delimitedSplit8k ()" ...ACTUALIZACIÓN 2: obtenga los valores de tipo seguro
Podemos usar una matriz dentro de una matriz simplemente usando doubled
[[]]
. Esto permite unaWITH
cláusula escrita :fuente
<x><![CDATA[x<&>x]]></x>
.CDATA
secciones también pueden ocuparse de esto ... Pero después del elenco se han ido (cambiado para escapartext()
implícitamente). No me gusta la magia debajo del capó , así que preferiría el(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
enfoque. Esto me parece más limpio y sucede de todos modos ... (Un poco más sobre CDATA y XML ).Aquí hay un UDF que lo hará. Devolverá una tabla de los valores delimitados, no he probado todos los escenarios, pero su ejemplo funciona bien.
Lo llamarías así:
Editar: Solución actualizada para manejar delimitadores con un len> 1 como en:
fuente
Aquí publico una forma simple de solución
Ejecute la función así
fuente
En mi opinión, ustedes lo están haciendo demasiado complicado. Simplemente cree un CLR UDF y termine con él.
fuente
¿Qué pasa con el uso
string
y lavalues()
declaración?Conjunto de resultados alcanzado.
fuente
Uso la respuesta de frederic pero esto no funcionó en SQL Server 2005
Lo modifiqué y estoy usando
select
conunion all
y funcionaY el conjunto de resultados es:
fuente
EXEC
.EXEC
llama implícitamente a un procedimiento almacenado, y no puede usar procedimientos almacenados en UDF.Este patrón funciona bien y puedes generalizar
nota CAMPO , ÍNDICE y TIPO .
Deje alguna tabla con identificadores como
Entonces, puedes escribir
División y fundición de todas las partes.
fuente
Si su base de datos tiene un nivel de compatibilidad de 130 o superior, puede usar la función STRING_SPLIT junto con OFFSET FETCH cláusulas para obtener el elemento específico por índice.
Para obtener el elemento en el índice N (basado en cero), puede usar el siguiente código
Para verificar el nivel de compatibilidad de su base de datos , ejecute este código:
fuente
xml
usé esto antes ... Es bueno saberlo ... Todavía preferiría el enfoque basado en -split, ya que permite obtener el valor de tipo seguro y no necesita una subconsulta, pero esta es una bueno +1 de mi ladoSTRING_SPLIT
demandas para v2016 +. En este caso, es mucho mejor usarOPENJSON
oJSON_VALUE
. Es posible que desee comprobar mi respuestaEstaba buscando la solución en la red y lo siguiente funciona para mí. Ref .
Y llamas a la función así:
fuente
Sin embargo, otro obtiene la enésima parte de la cadena por función delimitador:
y el uso:
que devuelve:
fuente
Prueba esto:
Pruébalo así:
fuente
El siguiente ejemplo usa un CTE recursivo
Actualización 18.09.2013
Demostración en SQLFiddle
fuente
fuente
Puede dividir una cadena en SQL sin necesidad de una función:
Si necesita admitir cadenas arbitrarias (con caracteres especiales xml)
fuente
Sé que es una vieja pregunta, pero creo que alguien puede beneficiarse de mi solución.
FIDDLE SQL
Ventajas:
Limitaciones:
Nota : la solución puede dar subcadenas hasta N.
Para superar la limitación, podemos usar la siguiente referencia .
Pero, de nuevo, la solución anterior no se puede usar en una tabla (Actaully no pude usarla).
De nuevo, espero que esta solución pueda ayudar a alguien.
Actualización: en el caso de registros> 50000, no es aconsejable usarlo,
LOOPS
ya que degradará el rendimientofuente
Solución pura basada en conjuntos usando
TVF
con recursivoCTE
. PuedeJOIN
yAPPLY
esta función a cualquier conjunto de datos.Uso:
Resultado:
fuente
Casi todas las otras respuestas están reemplazando la cadena que se divide, lo que desperdicia los ciclos de la CPU y realiza asignaciones de memoria innecesarias.
Cubro una forma mucho mejor de hacer una división de cadenas aquí: http://www.digitalruby.com/split-string-sql-server/
Aquí está el código:
fuente
Solución CTE recursiva con dolor de servidor, pruébela
Configuración del esquema de MS SQL Server 2008 :
Consulta 1 :
Resultados :
fuente
Si bien es similar a la respuesta basada en xml de josejuan, descubrí que procesar la ruta xml solo una vez, luego pivotar fue moderadamente más eficiente:
corrió a las 8:30
corrió en 9:20
fuente
Y USARLO
fuente
si alguien quiere obtener solo una parte del texto separado puede usar esto
seleccione * de fromSplitStringSep ('Word1 wordr2 word3', '')
fuente
Desarrollé esto,
la única atención que debes hacer es dot '.' ese final de la @x siempre debe estar allí.
fuente
basándose en la solución @NothingsImpossible, o, más bien, comentando la respuesta más votada (justo debajo de la respuesta aceptada), encontré la siguiente pregunta rápida y sucia solución satisface mis propias necesidades: tiene el beneficio de estar únicamente dentro del dominio SQL.
dado una cadena "primero; segundo; tercero; cuarto; quinto", digamos, quiero obtener el tercer token esto funciona solo si sabemos cuántos tokens tendrá la cadena, en este caso son 5. así que mi forma de acción es cortar los dos últimos tokens (consulta interna) y luego cortar los dos primeros tokens ( consulta externa)
Sé que esto es feo y cubre las condiciones específicas en las que estaba, pero lo estoy publicando en caso de que alguien lo encuentre útil. salud
fuente
fuente
A partir de SQL Server 2016 , string_split
fuente
STRING_SPLIT
no garantiza devolver el mismo pedido. PeroOPENJSON
sí (ver mi respuesta (sección de actualización) )