Usando o SQL Server, como faço para dividir uma sequência para acessar o item x?
Pegue uma string "Olá John Smith". Como posso dividir a string por espaço e acessar o item no índice 1, que deve retornar "John"?
sql
sql-server
tsql
split
GateKiller
fonte
fonte
Respostas:
Você pode encontrar a solução na Função Definida pelo Usuário do SQL para Analisar uma Cadeia de caracteres Delimitada útil (no The Code Project ).
Você pode usar esta lógica simples:
fonte
SET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( RTRIM( LTRIM( @p_SourceText)))
e nãoSET @p_SourceText = RTRIM( LTRIM( @p_SourceText)) SET @w_Length = DATALENGTH( @p_SourceText)
?STRING_SPLIT
que dividirá uma sequência e retornará um resultado da tabela de uma coluna que você pode usar em umaSELECT
instrução ou em outro local.Não acredito que o SQL Server tenha uma função de divisão interna; portanto, além de uma UDF, a única outra resposta que eu sei é seqüestrar a função PARSENAME:
PARSENAME pega uma string e a divide no caractere de ponto. Ele usa um número como segundo argumento e esse número especifica qual segmento da cadeia de caracteres retornar (trabalhando de trás para frente).
O problema óbvio é quando a string já contém um ponto. Ainda acho que usar uma UDF é a melhor maneira ... outras sugestões?
fonte
SPLIT()
função não é fornecida porque incentiva um design de banco de dados ruim, e o banco de dados nunca será otimizado para usar os dados armazenados nesse formato. O RDBMS não é obrigado a ajudar os desenvolvedores a fazer coisas estúpidas que foram projetadas para não manipular. A resposta correta será sempre "Normalize seu banco de dados como dissemos a você 40 anos atrás". Nem o SQL nem o RDBMS são responsáveis pelo design inadequado.Primeiro, crie uma função (usando CTE, a expressão de tabela comum elimina a necessidade de uma tabela temporária)
Em seguida, use-o como qualquer tabela (ou modifique-o para caber no seu proc armazenado existente) como este.
Atualizar
A versão anterior falharia na string de entrada com mais de 4000 caracteres. Esta versão cuida da limitação:
O uso permanece o mesmo.
fonte
100
(para evitar loop infinito). Use a dica MAXRECURSION para definir o número de níveis de recursão (0
para32767
,0
é "sem limite" - pode esmagar o servidor). Entre, resposta muito melhor do quePARSENAME
, porque é universal :-). +1maxrecursion
a esta solução, lembre-se desta pergunta e de suas respostas Como configurar amaxrecursion
opção para um CTE dentro de uma função com valor de tabela .s
não está mais definidoA maioria das soluções aqui são usadas enquanto loops ou CTEs recursivas. Uma abordagem baseada em conjunto será superior, prometo, se você puder usar um delimitador que não seja um espaço:
Uso da amostra:
Resultados:
Você também pode adicionar o
idx
argumento desejado à função, mas deixarei isso como um exercício para o leitor.Você não pode fazer isso apenas com a função nativa
STRING_SPLIT
adicionada no SQL Server 2016, porque não há garantia de que a saída será renderizada na ordem da lista original. Em outras palavras, se você passar3,6,1
o resultado, provavelmente estará nessa ordem, mas poderia estar1,3,6
. Pedi a ajuda da comunidade para melhorar a função incorporada aqui:Com bastante feedback qualitativo , eles podem considerar fazer algumas dessas melhorias:
Mais sobre funções de divisão, por que (e prova disso) enquanto loops e CTEs recursivos não são dimensionados, e melhores alternativas, se as seqüências de caracteres provenientes da camada de aplicação são divididas:
No SQL Server 2016 ou superior, no entanto, você deve observar
STRING_SPLIT()
eSTRING_AGG()
:fonte
select * from DBO.SplitString('Hello John smith', ' ');
e a saída produzida foi: Valor Olá ello llo lo o John ohn hn n smith mito om th hVocê pode aproveitar uma tabela Number para fazer a análise de string.
Crie uma tabela de números físicos:
Criar tabela de teste com 1000000 linhas
Crie a função
Uso (gera linhas de 3mil em 40s no meu laptop)
Limpar
O desempenho aqui não é incrível, mas chamar uma função em uma tabela de um milhão de linhas não é a melhor idéia. Se estiver executando uma string dividida em muitas linhas, eu evitaria a função.
fonte
desc
fossem removidos?REVERSE(PARSENAME(REPLACE(REVERSE('Hello John Smith'), ' ', '.'), 1))
@NothingsImpossible foi concluído em 1,5 minutos . @hello_earth Como sua solução se compara em seqüências mais longas com mais de 4 campos?Esta questão não é sobre uma abordagem de divisão de cadeias , mas sobre como obter o enésimo elemento .
Todas as respostas aqui estão fazendo algum tipo de divisão string usando recursão,
CTE
s, múltiplaCHARINDEX
,REVERSE
ePATINDEX
, funções inventando, chamada de métodos CLR, tabelas de números,CROSS APPLY
é ... A maioria das respostas cobrir muitas linhas de código.Mas - se você realmente deseja nada além de uma abordagem para obter o enésimo elemento - isso pode ser feito como uma única linha , sem UDF, nem mesmo como uma sub-seleção ... E como um benefício extra: digite safe
Obtenha a parte 2 delimitada por um espaço:
Obviamente, você pode usar variáveis para delimitador e posição (use
sql:column
para recuperar a posição diretamente do valor de uma consulta):Se a sua sequência incluir caracteres proibidos (especialmente um entre eles
&><
), você ainda poderá fazê-lo dessa maneira. Basta usarFOR XML PATH
sua string primeiro para substituir todos os caracteres proibidos pela seqüência de escape apropriada.É um caso muito especial se - além disso - seu delimitador for o ponto e vírgula . Nesse caso, substituo o delimitador primeiro por '# DLMT #' e substituo-o pelas tags XML finalmente:
ATUALIZAÇÃO para SQL-Server 2016 ou superior
Lamentavelmente, os desenvolvedores esqueceram de retornar o índice da peça
STRING_SPLIT
. Mas, usando o SQL-Server 2016+, háJSON_VALUE
eOPENJSON
.Com
JSON_VALUE
podemos passar na posição como o array do índice.Para
OPENJSON
a documentação afirma claramente:A string como
1,2,3
necessidades nada mais do que colchetes:[1,2,3]
.Uma série de palavras como
this is an example
precisa ser["this","is","an","example"]
.Essas são operações de cadeia muito fáceis. Apenas tente:
--Veja isto para um separador de cadeia de posição seguro ( baseado em zero ):
Em este post eu testei várias abordagens e encontrado, que
OPENJSON
é muito rápido. Até muito mais rápido que o famoso método "delimitedSplit8k ()" ...ATUALIZAÇÃO 2 - Obtenha os valores seguros para o tipo
Podemos usar uma matriz dentro de uma matriz simplesmente usando o dobro
[[]]
. Isso permite umaWITH
cláusula digitada :fonte
<x><![CDATA[x<&>x]]></x>
.CDATA
seções também podem lidar com isso ... Mas depois do elenco elas desaparecem (alteradas para escapadastext()
implicitamente). Eu não gosto de mágica sob o capô , então prefiro a(SELECT 'Text with <&>' AS [*] FOR XML PATH(''))
abordagem. Isso parece mais limpo para mim e acontece de qualquer maneira ... (Um pouco mais sobre CDATA e XML ).Aqui está uma UDF que fará isso. Ele retornará uma tabela com os valores delimitados, ainda não experimentou todos os cenários, mas seu exemplo funciona bem.
Você poderia chamar assim:
Edit: Solução atualizada para manipular delimters com len> 1 como em:
fonte
Aqui eu posto uma maneira simples de solução
Execute a função como esta
fonte
Na minha opinião, vocês estão tornando as coisas muito complicadas. Basta criar um CLR UDF e pronto.
fonte
Que tal usar
string
evalues()
declaração?Conjunto de resultados alcançado.
fonte
Eu uso a resposta de frederic, mas isso não funcionou no SQL Server 2005
Eu modifiquei e eu estou usando
select
comunion all
e funcionaE o conjunto de resultados é:
fonte
EXEC
.EXEC
chama implicitamente um procedimento armazenado e você não pode usar procedimentos armazenados em UDFs.Esse padrão funciona bem e você pode generalizar
note FIELD , INDEX e TYPE .
Deixe alguma tabela com identificadores como
Então, você pode escrever
dividir e fundir todas as peças.
fonte
Se o seu banco de dados tiver um nível de compatibilidade 130 ou superior, você poderá usar a função STRING_SPLIT junto com as cláusulas OFFSET FETCH para obter o item específico por índice.
Para obter o item no índice N (baseado em zero), você pode usar o seguinte código
Para verificar o nível de compatibilidade do seu banco de dados , execute este código:
fonte
xml
abordagem baseada em -split, pois ela permite buscar o valor com segurança de tipo e não precisa de uma subconsulta, mas é um bom. +1 do meu ladoSTRING_SPLIT
demandas para v2016 +. Nesse caso, é muito melhor usarOPENJSON
ouJSON_VALUE
. Você pode querer verificar minha respostaEu estava procurando a solução na net e o abaixo funciona para mim. Ref .
E você chama a função assim:
fonte
Ainda outra não obtém parte da string pela função delimeter:
e o uso:
que retorna:
fonte
Tente o seguinte:
Teste assim:
fonte
O exemplo a seguir usa um CTE recursivo
Atualização 18.09.2013
Demonstração no SQLFiddle
fonte
fonte
Você pode dividir uma string no SQL sem precisar de uma função:
Se você precisar suportar seqüências de caracteres arbitrárias (com caracteres especiais xml)
fonte
Eu sei que é uma pergunta antiga, mas acho que alguém pode se beneficiar da minha solução.
SQL FIDDLE
Vantagens:
Limitações:
Nota : a solução pode fornecer sub-string até N.
Para superar a limitação, podemos usar a seguinte ref .
Mas, novamente, a solução acima não pode ser usada em uma tabela (não foi possível usá-la).
Mais uma vez, espero que esta solução possa ajudar alguém.
Atualização: No caso de Registros> 50000, não é aconselhável usar,
LOOPS
pois isso prejudicará o desempenhofonte
Solução pura baseada em conjunto usando
TVF
com recursivaCTE
. Você podeJOIN
eAPPLY
esta função para qualquer conjunto de dados.Uso:
Resultado:
fonte
Quase todas as outras respostas estão substituindo a sequência que está sendo dividida, que desperdiça ciclos da CPU e executa alocações de memória desnecessárias.
Cubro uma maneira muito melhor de fazer uma divisão de string aqui: http://www.digitalruby.com/split-string-sql-server/
Aqui está o código:
fonte
Solução CTE recursiva com problemas no servidor, teste-a
Configuração do esquema do MS SQL Server 2008 :
Consulta 1 :
Resultados :
fonte
embora semelhante à resposta baseada em xml de josejuan, eu descobri que o processamento do caminho xml apenas uma vez; em seguida, o giro foi moderadamente mais eficiente:
correu às 8:30
correu às 9:20
fonte
E USE
fonte
se alguém quiser obter apenas uma parte do texto separado pode usar isso
select * fromSplitStringSep ('Word1 wordr2 word3', '')
fonte
Eu desenvolvi isso,
a única atenção que você deve ter é o ponto '.' esse fim do @x sempre deve estar lá.
fonte
com base na solução @NothingsImpossible, ou melhor, comente a resposta mais votada (logo abaixo da resposta aceita), achei a seguinte solução rápida e suja que atende às minhas próprias necessidades - ela tem o benefício de estar exclusivamente no domínio SQL.
dada uma string "primeiro; segundo; terceiro; quarto; quinto", por exemplo, quero obter o terceiro token. isso funciona apenas se soubermos quantos tokens a string terá - nesse caso, são 5. Portanto, minha maneira de ação é cortar os dois últimos tokens (consulta interna) e depois os dois primeiros tokens ( consulta externa)
Eu sei que isso é feio e cobre as condições específicas em que eu estava, mas estou publicando apenas no caso de alguém achar útil. Felicidades
fonte
fonte
A partir do SQL Server 2016 , string_split
fonte
STRING_SPLIT
não garante devolver o mesmo pedido. MasOPENJSON
não (ver a minha resposta (seção de atualização) )