Substitua os espaços duplicados por um único espaço no T-SQL

100

Preciso garantir que um determinado campo não tenha mais de um espaço (não estou preocupado com todos os espaços em branco, apenas espaço) entre os caracteres.

assim

'single    spaces   only'

precisa ser transformado em

'single spaces only'

O abaixo não vai funcionar

select replace('single    spaces   only','  ',' ')

pois isso resultaria em

'single  spaces  only'

Eu realmente preferiria ficar com o T-SQL nativo em vez de uma solução baseada em CLR.

Pensamentos?

Christoph
fonte
Você pode fazer isso com uma substituição REGEX
Raj More,

Respostas:

326

Ainda mais organizado:

select string = replace(replace(replace(' select   single       spaces',' ','<>'),'><',''),'<>',' ')

Resultado:

selecione espaços individuais

Neil Knight
fonte
6
Se você quiser remover os espaços na frente e no final da string, envolva a substituição em um LTRIM, RTRIM e ele fará isso por você.
Neil Knight de
5
Contanto que sua string não contenha muitos sinais <ou>. Parece frágil para o meu gosto.
JohnFx
8
Hack verdadeiramente elegante. Votado. Quaisquer dois caracteres podem ser usados ​​para a parte do meio se <> estiverem potencialmente no texto de entrada.
richardtallent
32
Chris, você pode usar caracteres ASCII não imprimíveis, como CHAR (17) e CHAR (18), pois eles NUNCA estarão em seu texto de entrada. Ainda mais rápido do que o loop da resposta aceita.
richardtallent
7
Eu realmente tive que olhar para isso por um momento para descobrir se você usou o '> <', '' Sem substituição de espaço, mas agora que entendi ... é muito brilhante. Eu gostei muito da sugestão @richardtallent de usar os caracteres ASCII não imprimíveis, cuja combinação adicional produz: REPLACE (REPLACE (REPLACE (LastName, '', 'CHAR (17) CHAR (18)'), 'CHAR (18 ) CHAR (17) ',' '),' CHAR (17) CHAR (18) ',' ')
Anthony Griggs
25

Isso funcionaria:

declare @test varchar(100)
set @test = 'this   is  a    test'

while charindex('  ',@test  ) > 0
begin
   set @test = replace(@test, '  ', ' ')
end

select @test
James Wiseman
fonte
1
Envolvendo em função e alterando varchar (100) para nvarchar (max)
Christoph
A diferença entre os scripts de James e Neil é que James executa um loop while que, por experiência pessoal, executá-lo em 50.000 registros de uma tabela tende a ser muito lento, então você precisa criá-lo como um procedimento e passar um registro e alguns trabalhos você pode não ter permissão para criar um novo procedimento de banda. Usos de Neil per-existente funções porque ele usa <>, se você tem uma string como "release < now"então você vai ter "release<><><<><>now", "release<<>now", "release< now", é a mesma com qualquer par de símbolos, se você tem uma única um do par, então ele vai se mover
Memor-X de
1
executar isso por meio de registros de 50k deve ser muito rápido, eu procuraria outros problemas se esse for o seu problema.
user3486773
17

Se você sabe que não haverá mais do que um certo número de espaços em uma linha, você pode simplesmente aninhar a substituição:

replace(replace(replace(replace(myText,'  ',' '),'  ',' '),'  ',' '),'  ',' ')

4 substituições devem fixar até 16 espaços consecutivos (16, depois 8, depois 4, depois 2 e depois 1)

Se pudesse ser significativamente mais longo, você teria que fazer algo como uma função in-line:

CREATE FUNCTION strip_spaces(@str varchar(8000))
RETURNS varchar(8000) AS
BEGIN 
    WHILE CHARINDEX('  ', @str) > 0 
        SET @str = REPLACE(@str, '  ', ' ')

    RETURN @str
END

Então é só fazer

SELECT dbo.strip_spaces(myText) FROM myTable
BradC
fonte
Brad, eu tinha um código quase idêntico, mas você chegou antes de mim no Post, então vote a favor. Múltiplas chamadas REPLACE () são hackeadas, mas se o número de espaços "extras" esperados for previsível e relativamente pequeno, isso funcionará bem e atenderá ao requisito do OP de não chamar o código RegEx através do CLR.
richardtallent de
6
update mytable
set myfield = replace (myfield, '  ',  ' ')
where charindex('  ', myfield) > 0 

Substituir funcionará em todos os espaços duplos, não há necessidade de colocar vários substituições. Esta é a solução baseada em conjunto.

HLGEM
fonte
Isso não reduziria 4 espaços em 2?
Christoph
Eu chamei esta solução em minhas perguntas como não atender a necessidade, mas obrigado.
Christoph de
6

Isso pode ser feito recursivamente por meio da função:

CREATE FUNCTION dbo.RemSpaceFromStr(@str VARCHAR(MAX)) RETURNS VARCHAR(MAX) AS
BEGIN
  RETURN (CASE WHEN CHARINDEX('  ', @str) > 0 THEN
    dbo.RemSpaceFromStr(REPLACE(@str, '  ', ' ')) ELSE @str END);
END

então, por exemplo:

SELECT dbo.RemSpaceFromStr('some   string    with         many     spaces') AS NewStr

retorna:

NewStr
some string with many spaces

Ou a solução baseada no método descrito por @ agdk26 ou @Neil Knight (mas mais seguro)
ambos os exemplos retornam a saída acima:

SELECT REPLACE(REPLACE(REPLACE('some   string    with         many     spaces'
  , '  ', ' ' + CHAR(7)), CHAR(7) + ' ', ''), ' ' + CHAR(7), ' ') AS NewStr 
--but it remove CHAR(7) (Bell) from string if exists...

ou

SELECT REPLACE(REPLACE(REPLACE('some   string    with         many     spaces'
  , '  ', ' ' + CHAR(7) + CHAR(7)), CHAR(7) + CHAR(7) + ' ', ''), ' ' + CHAR(7) + CHAR(7), ' ') AS NewStr
--but it remove CHAR(7) + CHAR(7) from string

Como funciona: insira a descrição da imagem aqui

Cuidado: O
caractere / string usado para substituir espaços não deve existir no início ou no final da string e ficar sozinho.

Adam Silenko
fonte
1
Eu meio que gosto da ideia de uma função recursiva para isso. há alguma coisa a ter em conta?
Zach Smith
5

Isso é um pouco força bruta, mas funcionará

CREATE FUNCTION stripDoubleSpaces(@prmSource varchar(max)) Returns varchar(max)
AS 
BEGIN
    WHILE (PATINDEX('%  %', @prmSource)>0)
     BEGIN
        SET @prmSource = replace(@prmSource  ,'  ',' ')
     END

    RETURN @prmSource
END

GO

-- Unit test -- 
PRINT dbo.stripDoubleSpaces('single    spaces   only')

single spaces only
JohnFx
fonte
2

Aqui está uma função simples que criei para limpar todos os espaços antes ou depois e vários espaços dentro de uma string. Ele segura até cerca de 108 espaços em um único trecho e tantos blocos quantos houver na corda. Você pode aumentar isso por fatores de 8, adicionando linhas adicionais com pedaços maiores de espaços, se necessário. Parece ter um desempenho rápido e não causou nenhum problema, apesar de seu uso generalizado em um aplicativo grande.

CREATE FUNCTION [dbo].[fnReplaceMultipleSpaces] (@StrVal AS VARCHAR(4000)) 
RETURNS VARCHAR(4000) 
AS 
BEGIN

    SET @StrVal = Ltrim(@StrVal)
    SET @StrVal = Rtrim(@StrVal)

    SET @StrVal = REPLACE(@StrVal, '                ', ' ')  -- 16 spaces
    SET @StrVal = REPLACE(@StrVal, '        ', ' ')  -- 8 spaces
    SET @StrVal = REPLACE(@StrVal, '    ', ' ')  -- 4 spaces
    SET @StrVal = REPLACE(@StrVal, '  ', ' ')  -- 2 spaces
    SET @StrVal = REPLACE(@StrVal, '  ', ' ')  -- 2 spaces (for odd leftovers)

RETURN @StrVal

END
Robert Petolillo
fonte
1

Encontrei isto enquanto procurava por uma resposta:

SELECT REPLACE(
        REPLACE(
             REPLACE(
                LTRIM(RTRIM('1 2  3   4    5     6'))
            ,'  ',' '+CHAR(7))
        ,CHAR(7)+' ','')
    ,CHAR(7),'') AS CleanString
where charindex('  ', '1 2  3   4    5     6') > 0

A resposta completa (com explicação) foi obtida de: http://techtipsbysatish.blogspot.com/2010/08/sql-server-replace-multiple-spaces-with.html

Olhando uma segunda vez, parece ser apenas uma versão ligeiramente diferente da resposta selecionada.

Limey
fonte
1

Método 1

O primeiro método é substituir os espaços extras entre as palavras por uma combinação incomum de símbolos como um marcador temporário. Em seguida, você pode substituir os símbolos de marcador temporário usando a função de substituição em vez de um loop.

Aqui está um exemplo de código que substitui o texto em uma variável String.

DECLARE @testString AS VARCHAR(256) = ' Test        text   with  random*        spacing. Please normalize  this spacing!';
SELECT REPLACE(REPLACE(REPLACE(@testString, ' ', '*^'), '^*', ''), '*^', ' ');

Teste de tempo de execução nº 1: em dez execuções desse método de substituição, o tempo médio de espera nas respostas do servidor foi de 1,7 milissegundos e o tempo total de execução foi de 4,6 milissegundos. Teste de tempo de execução nº 2: o tempo médio de espera nas respostas do servidor foi de 1,7 milissegundos e o tempo total de execução foi de 3,7 milissegundos.

Método # 2

O segundo método não é tão elegante quanto o primeiro, mas também realiza o trabalho. Este método funciona aninhando quatro (ou opcionalmente mais) instruções de substituição que substituem dois espaços em branco por um espaço em branco.

DECLARE @testString AS VARCHAR(256) = ' Test        text   with  random*        spacing. Please normalize  this spacing!';
SELECT REPLACE(REPLACE(REPLACE(REPLACE(@testString,' ',' '),' ',' '),' ',' '),' ',' ')

Teste de tempo de execução nº 1: em dez execuções desse método de substituição, o tempo médio de espera nas respostas do servidor foi de 1,9 milissegundos e o tempo total de execução foi de 3,8 milissegundos. Teste de tempo de execução nº 2: o tempo médio de espera nas respostas do servidor foi de 1,8 milissegundos e o tempo total de execução foi de 4,8 milissegundos.

Método # 3

O terceiro método de substituir espaços extras entre palavras é usar um loop simples. Você pode fazer uma verificação nos espaços extras em um loop while e, em seguida, usar a função replace para reduzir os espaços extras a cada iteração do loop.

DECLARE @testString AS VARCHAR(256) = ' Test text with random* spacing. Please normalize this spacing!';
WHILE CHARINDEX(' ',@testString) > 0
SET @testString = REPLACE(@testString, ' ', ' ')
SELECT @testString

Teste de tempo de execução nº 1: em dez execuções desse método de substituição, o tempo médio de espera nas respostas do servidor foi de 1,8 milissegundos e o tempo total de execução foi de 3,4 milissegundos. Teste de tempo de execução nº 2: o tempo médio de espera nas respostas do servidor foi de 1,9 milissegundos e o tempo total de execução foi de 2,8 milissegundos.


fonte
1

Esta é a solução por meio de substituição múltipla, que funciona para qualquer string (não precisa de caracteres especiais, que não fazem parte da string).

declare @value varchar(max)
declare @result varchar(max)
set @value = 'alpha   beta gamma  delta       xyz'

set @result = replace(replace(replace(replace(replace(replace(replace(
  @value,'a','ac'),'x','ab'),'  ',' x'),'x ',''),'x',''),'ab','x'),'ac','a')

select @result -- 'alpha beta gamma delta xyz'
agdk26
fonte
coisa legal, mas mudando 'abe' para 'machado'
Adam Silenko
0

Eu uso a solução FOR XML PATH para substituir vários espaços em um único espaço

A ideia é substituir os espaços por tags XML Em seguida, dividir a string XML em fragmentos de string sem tags XML Finalmente concatenando esses valores de string adicionando caracteres de espaço único entre dois

Aqui está como a função UDF final pode ser chamada

select dbo.ReplaceMultipleSpaces('   Sample   text  with  multiple  space     ')
Eralper
fonte
0
 DECLARE @str varchar(150)
SET @str='Hello    My   name  is Jiyaul   mustafa'
Select REPLACE(REPLACE(REPLACE(@str,' ','{}'),'}{',''),'{}',' ')
Código
fonte
0

Normalmente uso esta abordagem:

declare @s varchar(50)
set @s = 'TEST         TEST'
select REPLACE(REPLACE(REPLACE(@s,' ','[o][c]'),'[c][o]',''),'[o][c]',' ')
Matthys Du Toit
fonte
0

Apenas adicionando outro método-

Substituindo Vários Espaços com Espaço Único SEM usar REPLACE no SQL Server-

DECLARE @TestTable AS TABLE(input VARCHAR(MAX));

INSERT INTO @TestTable VALUES
('HAPPY         NEWYEAR     2020'),
('WELCOME       ALL     !');

SELECT
    CAST('<r><![CDATA[' + input + ']]></r>' AS XML).value('(/r/text())[1] cast as xs:token?','VARCHAR(MAX)')
    AS Expected_Result
FROM @TestTable;

--OUTPUT
/*
Expected_Result
HAPPY NEWYEAR 2020
WELCOME ALL !
*/
Arulmouzhi
fonte
0

Encontre o código abaixo

select trim(string_agg(value,' ')) from STRING_SPLIT('  single    spaces   only  ',' ')
where value<>' '

Isso funcionou para mim .. Espero que isso ajude ...

Lekhnath Pandey
fonte
-1

Você pode tentar isto:

select Regexp_Replace('single    spaces   only','( ){2,}', ' ') from dual;
Karthika Harisankar
fonte
DECLARE @str varchar (150) SET @ str = 'Olá, bem-vindo ao mundo de .net' Selecione REPLACE (REPLACE (REPLACE (@str, '', '{}'), '} {', ''), '{ } ',' ')
Código
-3
update mytable
set myfield = replace(myfield, '  ',  ' ')
where myfield like '%  %'

Experimente isso ..

Henry
fonte
Eu chamei esta solução em minhas perguntas como não atender a necessidade, mas obrigado.
Christoph de