Articles

SQLShack

Os programadores de bases de dados necessitam frequentemente de converter um valor separado por vírgulas ou outros itens delimitados num formato tabular. Os delimitadores incluem tubo “|”, hash “#”, dólar “$” e outros caracteres. O SQL Server nível de compatibilidade 130, e versões subsequentes, suportam uma função string_split() para converter valores separados por delimitadores em linhas (formato de tabela). Para níveis de compatibilidade inferiores a 130, os programadores já o fizeram anteriormente com uma função definida pelo utilizador, que incorpora um While loop ou Cursor para extrair os dados.

Por que é necessária uma entrada separada por vírgula para um procedimento ou consulta T-SQL?

Executar um programa numa iteração usando um loop é um método comum na aplicação back-end, bem como na base de dados. Quando a contagem da iteração é menor do que o esperado, o tempo de execução pode ser menor, contudo o número de iterações é maior, o que leva a um tempo de processamento mais longo. Por exemplo, se a aplicação estiver a buscar dados de uma base de dados com a execução de um programa num laço através da análise de diferentes parâmetros de entrada, a aplicação terá de envolver a resposta da base de dados de cada iteração. Para lidar com este tipo de situação, podemos executar o mesmo programa com uma única execução com análise da vírgula ou delimitação de valores separados como parâmetro de entrada na base de dados e fazê-lo em formato tabular no programa T-SQL para proceder com mais lógica.

Execução de linhaSQL

Execução de linhaSQL

Hoje em dia, muitas plataformas foram alteradas para arquitectura de micro-serviço. Não só a aplicação, mas também a concepção de bases de dados poderia ser estruturada em arquitectura baseada em micro-serviços e a maior parte da comunicação interna entre as bases de dados é feita apenas com referências inteiras. Esta é a razão para obter alguma forma complicada de conseguir uma melhor execução do lado da base de dados.

Vários inputs para o mesmo parâmetro podem ser realizados com valores separados por vírgula no parâmetro de input do procedimento armazenado ou input para a função tabular, e utilizados com a tabela numa declaração T-SQL. Pode haver mais situações para esta estratégia quando se utiliza o T-SQL. Durante a programação com SQL Server, um programador deve quebrar uma cadeia em elementos utilizando um separador. A utilização da função de divisão contra a cadeia define o separador como um parâmetro de entrada. A cadeia de caracteres inteira será dividida e devolvida como uma tabela. Em determinadas circunstâncias, o parâmetro de entrada pode ser uma combinação de dois ou mais valores separados por caracteres para cada conjunto de entrada. Por exemplo:

N’203616, 198667, 193718, 188769,…’ N’1021|203616$1021|198667$1022|193718$1022|188769$…’ N’1021|203616,198667$1022|193718,188769$…’

Execução de um fio único

Execução de um fio único

Há vantagens na execução de um fio único com valores separados por vírgula sobre a execução de vários fios no SQL Server:

  • Execução única para parte do programa, resultando no número de entradas
  • Operação de leitura ou escrita única sobre as tabelas da base de dados em vez de várias iterações usando um laço
  • Utilização de recursos de um servidor único
  • Sem mais obstáculos na aplicação back-end para configurar uma resposta de múltiplos conjuntos de resultados
  • Compromisso de um disparo significa que a base de dados/SQL Server não irá bloquear a transacção e atrasar as coisas. Assim, nenhuma possibilidade de bloqueio
  • Fácil de supervisionar a consistência da transacção

Dividir função usando loop

Na maioria dos casos, um programador escreve a função tabela-valorizada com um loop para extrair os dados de valores separados por vírgula para uma lista ou formato de tabela. Um laço extrai o tuple um a um com a repetição. Podem surgir problemas de desempenho quando se trabalha com o grande parâmetro de entrada, uma vez que levará mais tempo a extraí-lo. Aqui, temos uma função simples com o nome de split_string, que utiliza um laço dentro da função valorizada pela tabela. Esta função permite dois argumentos ou parâmetros de entrada (1 – cadeia de entrada e 2 – delimitador):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

CREATE FUNCTION split_string
(
@in_string VARCHAR(MAX),
@delimeter VARCHAR(1)
)
RETURNS @list TABLE(tuple VARCHAR(100))
AS
BEGIN
WHILE LEN(@in_string) > 0
BEGIN
INSERT INTO @list(tuple)
SELECT left(@in_string) charindex(@delimiter, @in_string+’,’) -1) como tuple
SET @in_string = stuff(@in_string, 1, charindex(@delimiter, @in_string + @delimiter), ”)
fim
RETURN
END

Uma tabela de conjunto de resultados devolvida por esta função contém cada substrato da cadeia de parâmetros de entrada que é separado pelo delimitador. Os substratos na tabela estão na ordem em que ocorrem no parâmetro de entrada. Se o separador ou delimitador não coordenar com nenhuma parte da cadeia de entrada, então a tabela de saída terá apenas um componente. A função tabular retornará o resultado definido num formato linha-coluna a partir da cadeia de caracteres separada por vírgulas.

1
SELECT * FROM split_string(‘1001,1002,1003,1004’, ‘,’)

Versões recentes do SQL Server fornecem uma string_split() de função integrada para fazer a mesma tarefa com os parâmetros de entrada da string de entrada e delimitador. Mas existe outra forma eficiente de executar esta tarefa usando XML.

Função Split usando XML

A função Split usando lógica XML é um método útil para separar valores de uma string delimitada. A utilização da lógica XML com a abordagem XQUERY baseada em T-SQL resulta em que o T-SQL não seja caracterizado como uma recursividade usando laço ou cursor. Essencialmente, a cadeia de parâmetros de entrada é convertida para XML através da substituição do nó XML na articulação T-SQL. O XML resultante é utilizado em XQUERY para extrair o valor do nó para o formato de tabela. Também resulta num melhor desempenho.

Por exemplo, temos um valor separado por vírgula com a variável @user_ids na declaração abaixo do T-SQL. Numa variável, uma vírgula é substituída pelas etiquetas XML para a tornar num documento de tipo de dados XML e depois extraída usando XQUERY com a XPATH como ‘/root/U’:

1
2
3
4
5
6
7
8
9
10

>/td>

DECLARE @user_ids NVARCHAR(MAX) = N’203616, 198667, 193718, 188769, 183820, 178871, 173922, 168973, 164024, 159075, 154126, 149177, 144228, 139279, 134330, 129381, 124432, 119483, 114534, 109585, 104636, 99687, 94738, 89789, 84840, 79891, 74942, 69993, 65044, 60095, 55146′
DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@user_ids, ‘,’, </U><U></U></root>’ AS XML)
SELECT f.x.valor(‘.’, ‘BIGINT’) AS user_id
INTO #users
FROM @sql_xml.nodes(‘/root/U’) f(x)
SELECT *
FROM #users

T-Código SQL para Comma separated to list

Código T-SQL para Comma separated to list

Na função acima, utilizámos o tipo de dados VARCHAR (100) para o valor extraído em vez de BIGINT. Também pode haver alterações na cadeia de parâmetros de entrada. Por exemplo, se a cadeia de entrada tiver um ‘,’ extra no início ou fim da cadeia, devolve uma linha extra com 0 para o tipo de dados BIGINT e ” para VARCHAR.

Por exemplo,

DECLARE @user_ids VARCHAR(MAX) = N’203616, 198667, 193718, 188769, 183820, 178871,’
DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@user_ids, ‘,’, </U><U></U></root>’ AS XML)
SELECT f.x.value(‘.’, ‘BIGINT’) AS user_id
FROM @sql_xml.nodes(‘/root/U’) f(x)

1
2
3
4
5

T-Amostra SQL

T-SQL sample

Para lidar com este tipo de ” ou 0 dados no conjunto de resultados, podemos acrescentar a condição abaixo na declaração T-SQL:

DECLARE @user_ids VARCHAR(MAX) = N’203616, 198667, 193718, 188769, 183820, 178871,’
DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@user_ids, ‘,’, </U><U></U></root>’ AS XML)
SELECT f.x.value(‘.’, ‘BIGINT’) COMO user_id
DE @sql_xml.nodes(‘/root/U’) f(x)
ONDE f.x.value(‘.’, ‘BIGINT’) <> 0

1
2
3
4
5
6

Aqui, f.x.value(‘.’, ‘BIGINT’) <> 0 exclui o 0 e f.x.value(‘.’, ‘VARCHAR(100)’) <> ” exclui o ” no conjunto de resultados da consulta. Esta condição T-SQL pode ser adicionada às funções valorizadas na tabela com o número de parâmetros de entrada para lidar com este delimitador extra.

Função:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

CREATE FUNCTION split_string_XML
(
@in_string VARCHAR(MAX),
@delimeter VARCHAR(1)
)
RETURNS @list TABLE(tuple VARCHAR(100))
AS
BEGIN
DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@in_string_string, @delimetro, </U><U></U></root>’ AS XML)
INSERT INTO @list(tuple)
SELECT f.x.value(‘.’, ‘VARCHAR(100)’) COMO tuple
DE @sql_xml.nodes(‘/root/U’) f(x)
ONDE f.x.value(‘.’, ‘BIGINT’) <> 0
RETURN
END

Execução:

SELECT *
FROM split_string_XML(‘203616,198667,193718,188769,183820,178871,173922,’, ‘,’)

1
2

Combinação de caracteres em cadeia delimitada

Mas e quando o parâmetro de entrada é uma combinação de dois valores com múltiplos separadores? Neste caso, o parâmetro de entrada deve ser extraído duas vezes com a ajuda de uma subconsulta, como se mostra abaixo:

1
2
3
4
5
6
7
8
9
10
11
12

DECLARE @in_string VARCHAR(MAX) = ‘1021|203616$1021|198667$1022|193718$1022|188769 XML = Cast(‘<root><U>’+ Replace(@in_string, ‘ </U><U></U></root>’ AS XML)
SELECT X.Y.valor(‘(U)’, ‘VARCHAR(20)’) COMO role_id,
X.Y.valor(‘(U)’, VARCHAR(20)’) COMO user_id
FROM
(
SELECT Cast(‘<root><U>’+ Substituir(f.x.value(‘.”, ‘VARCHAR(MAX)’), ‘|’, </U><U></U></root>’ AS XML) AS xml_
FROM @sql_xml.nodes(‘/root/U’) f(x)
WHERE f.x.value(‘.’, ‘VARCHAR(MAX)’) <> ”
)T
OUTER APPLY T.xml_.nodes(‘root’) como X(Y)

Este exemplo é semelhante ao exemplo acima, mas utilizámos o tubo “|” como um delimitador com um segundo delimitador, dólar “$”. Aqui, o parâmetro de entrada é a combinação de duas colunas, role_id, e user_id. Como vemos abaixo, user_id e role_id estão numa coluna separada no conjunto de resultados da tabela:

códigoT-SQL para delimitador combinado separado para lista

códigoT-SQL para delimitador combinado separado para lista

Podemos utilizar qualquer caracter na função acima, tal como uma única cadeia de caracteres separada ou uma combinação de cadeias de caracteres separadas. Um desenvolvedor deve simplesmente substituir o caractere nas declarações T-SQL acima. Siga os passos aqui descritos para converter qualquer cadeia de caracteres delimitada para uma lista. Basta lembrar que a função XML do SQL Server aceita uma string de entrada e a string de entrada será delimitada com o separador especificado usando a função tabular.

  • Autor
  • Posts recentes
Jignesh Raiyani
Jignesh tem boa experiência em Soluções de Base de Dados e Arquitectura, trabalhando com múltiplos clientes em Database Design & Architecture, SQL Development, Administration, Query Optimization, Performance Tuning, HA e Disaster Recovery.
Ver todos os posts de Jignesh Raiyani

Jignesh Raiyani
Página Expectativa de Vida (APA) no SQL Server – 17 de Julho, 2020

  • Como automatizar o particionamento de tabelas no SQL Server – 7 de Julho de 2020
  • Configurar o SQL Server Always On Availability Groups no AWS EC2 – 6 de Julho de 2020
  • DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@in_string, ‘$’, ‘</U><U></U></root>’ AS XML)
    SELECT X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS role_id,
    X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS user_id
    FROM
    (
    SELECT Cast(‘<root><U>’+ Replace(f.x.value(‘.’, ‘VARCHAR(MAX)’), ‘|’, ‘</U><U></U></root>’ AS XML) AS xml_
    FROM @sql_xml.nodes(‘/root/U’) f(x)
    WHERE f.x.value(‘.’, ‘VARCHAR(MAX)’) <> ”
    )T
    OUTER APPLY T.xml_.nodes(‘root’) as X(Y)

    This example is similar to the above example but we have utilized pipe “|” as a delimiter with a second delimiter, dollar “$”. Here, the input parameter is the combination of two-columns, role_id, and user_id. As we see below, user_id and role_id are in a separate column in the table result set:

    T-SQL code for combinational delimiter separated to list

    T-SQL code for combinational delimiter separated to list

    We can use any character in the above function, such as a single character-separated string or combination of character-separated strings. A developer must simply replace the character in the T-SQL statements above. Follow the steps described here to convert any delimited string to a list. Simply remember that the XML function of SQL Server accepts a string input and the input string will be delimited with the specified separator using the tabular function.

    • Author
    • Recent Posts
    Jignesh Raiyani
    Jignesh has good experience in Database Solutions and Architecture, working with multiple customers on Database Design & Architecture, SQL Development, Administration, Query Optimization, Performance Tuning, HA and Disaster Recovery.
    View all posts by Jignesh Raiyani

    Jignesh Raiyani
    Latest posts by Jignesh Raiyani (see all)
    • Page Life Expectancy (PLE) in SQL Server – July 17, 2020
    • How to automate Table Partitioning in SQL Server – July 7, 2020
    • Configuring SQL Server Always On Availability Groups on AWS EC2 – July 6, 2020

    , ‘</U><U></U></root>’ AS XML)

    SELECT X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS role_id,
    X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS user_id
    FROM
    (
    SELECT Cast(‘<root><U>’+ Replace(f.x.value(‘.’, ‘VARCHAR(MAX)’), ‘|’, ‘</U><U></U></root>’ AS XML) AS xml_
    FROM @sql_xml.nodes(‘/root/U’) f(x)
    WHERE f.x.value(‘.’, ‘VARCHAR(MAX)’) <> ”
    )T
    OUTER APPLY T.xml_.nodes(‘root’) as X(Y)

    This example is similar to the above example but we have utilized pipe “|” as a delimiter with a second delimiter, dollar “$”. Here, the input parameter is the combination of two-columns, role_id, and user_id. As we see below, user_id and role_id are in a separate column in the table result set:

    T-SQL code for combinational delimiter separated to list

    T-SQL code for combinational delimiter separated to list

    We can use any character in the above function, such as a single character-separated string or combination of character-separated strings. A developer must simply replace the character in the T-SQL statements above. Follow the steps described here to convert any delimited string to a list. Simply remember that the XML function of SQL Server accepts a string input and the input string will be delimited with the specified separator using the tabular function.

    • Author
    • Recent Posts
    Jignesh Raiyani
    Jignesh has good experience in Database Solutions and Architecture, working with multiple customers on Database Design & Architecture, SQL Development, Administration, Query Optimization, Performance Tuning, HA and Disaster Recovery.
    View all posts by Jignesh Raiyani

    Jignesh Raiyani
    Latest posts by Jignesh Raiyani (see all)
    • Page Life Expectancy (PLE) in SQL Server – July 17, 2020
    • How to automate Table Partitioning in SQL Server – July 7, 2020
    • Configuring SQL Server Always On Availability Groups on AWS EC2 – July 6, 2020

    DECLARE @sql_xml XML = Cast(‘<root><U>’+ Replace(@in_string, ‘$’, ‘</U><U></U></root>’ AS XML)
    SELECT X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS role_id,
    X.Y.value(‘(U)’, ‘VARCHAR(20)’) AS user_id
    FROM
    (
    SELECT Cast(‘<root><U>’+ Replace(f.x.value(‘.’, ‘VARCHAR(MAX)’), ‘|’, ‘</U><U></U></root>’ AS XML) AS xml_
    FROM @sql_xml.nodes(‘/root/U’) f(x)
    WHERE f.x.value(‘.’, ‘VARCHAR(MAX)’) <> ”
    )T
    OUTER APPLY T.xml_.nodes(‘root’) as X(Y)

    This example is similar to the above example but we have utilized pipe “|” as a delimiter with a second delimiter, dollar “$”. Here, the input parameter is the combination of two-columns, role_id, and user_id. As we see below, user_id and role_id are in a separate column in the table result set:

    T-SQL code for combinational delimiter separated to list

    T-SQL code for combinational delimiter separated to list

    We can use any character in the above function, such as a single character-separated string or combination of character-separated strings. A developer must simply replace the character in the T-SQL statements above. Follow the steps described here to convert any delimited string to a list. Simply remember that the XML function of SQL Server accepts a string input and the input string will be delimited with the specified separator using the tabular function.

    • Author
    • Recent Posts
    Jignesh Raiyani
    Jignesh has good experience in Database Solutions and Architecture, working with multiple customers on Database Design & Architecture, SQL Development, Administration, Query Optimization, Performance Tuning, HA and Disaster Recovery.
    View all posts by Jignesh Raiyani

    Jignesh Raiyani
    Latest posts by Jignesh Raiyani (see all)
    • Page Life Expectancy (PLE) in SQL Server – July 17, 2020
    • How to automate Table Partitioning in SQL Server – July 7, 2020
    • Configuring SQL Server Always On Availability Groups on AWS EC2 – July 6, 2020

    Deixe uma resposta

    O seu endereço de email não será publicado. Campos obrigatórios marcados com *