tags:

views:

346

answers:

7

Is there a more elegant way of doing this. I want to replace repeating blanks with single blanks....

   declare @i int

    set @i=0
    while @i <= 20
    begin
        update myTable
        set myTextColumn = replace(myTextColumn, '  ', ' ')
        set @i=@i+1
    end

(its sql server 2000 - but I would prefer generic SQL)

+1  A: 

Step through the characters one by one, and maintain a record of the previous character. If the current character is a space, and the last character is a space, stuff it.

CREATE FUNCTION [dbo].[fnRemoveExtraSpaces]  (@Number AS varchar(1000))
Returns Varchar(1000)
As
Begin
Declare @n int  -- Length of counter
Declare @old char(1)

Set @n = 1
--Begin Loop of field value
While @n <=Len (@Number)
    BEGIN
     If Substring(@Number, @n, 1) = ' ' AND @old = ' '
      BEGIN
        Select @Number = Stuff( @Number , @n , 1 , '' )
      END
     Else
      BEGIN
       SET @old = Substring(@Number, @n, 1)
       Set @n = @n + 1
      END
    END
Return @number
END
GO


select [dbo].[fnRemoveExtraSpaces]('xxx     xxx     xxx    xxx')
ck
+1 cool. thanks a lot for your time.
Saar
A: 
create table blank(
field_blank char(100))

insert into blank values('yyy      yyyy')
insert into blank values('xxxx    xxxx')
insert into blank values ('xxx    xxx')
insert into blank values ('zzzzzz zzzzz')

update blank 
set field_blank = substring(field_blank,1,charindex(' ',field_blank)-1) + ' ' + ltrim(substring(field_blank,charindex(' ',field_blank) + 1,len(field_blank)))
where CHARINDEX (' ' , rtrim(field_blank)) > 1

select * from blank
kevchadders
+1 nice logic :)
Saar
Doesn't work on multiple occurrences of excessive spaces.
ck
Doesn't work with the following:`insert into @blank values('y y y yyyy')``insert into @blank values('xx xx xxxx')``insert into @blank values ('x xx xxx')``insert into @blank values ('zz zzzz zzz zz')`
Codesleuth
@ck: I am interested to see loop in sql. Can you please post as update to your answer. tia.
Saar
@Saar - done. Tested and works a treat.
ck
+2  A: 

Not very SET Based but a simple WHILE would do the trick.

CREATE TABLE #myTable (myTextColumn VARCHAR(32))

INSERT INTO #myTable VALUES ('NoSpace')
INSERT INTO #myTable VALUES ('One Space')
INSERT INTO #myTable VALUES ('Two  Spaces')
INSERT INTO #myTable VALUES ('Multiple    Spaces    .')

WHILE EXISTS (SELECT * FROM #myTable WHERE myTextColumn LIKE '%  %')
  UPDATE  #myTable 
  SET     myTextColumn = REPLACE(myTextColumn, '  ', ' ') 
  WHERE   myTextColumn LIKE '%  %'

SELECT * FROM #myTable

DROP TABLE #myTable
Lieven
Of course, this won't work on SQL Server 2000 because of the `OUTPUT` clause, but good answer.
Codesleuth
@Codesleuth - thanks, I missed that requirement. The answer has been updated to work with SQL Server 2000.
Lieven
@Lieven: aww, but you changed it to a temp table? That makes me sad, declared tables work in 2000 too you know!
Codesleuth
@Codesleuth - lol, no I didn't know. All SQL Server 2000 knowledge is burried in the darkest corners of my head and then some. OP can always take the original version then and just remove the OUTPUT clause.
Lieven
+5  A: 

This works:

UPDATE myTable
SET myTextColumn =
    REPLACE(
        REPLACE(
            REPLACE(myTextColumn
                ,'  ',' '+CHAR(1)) -- CHAR(1) is unlikely to appear
        ,CHAR(1)+' ','')
    ,CHAR(1),'')
WHERE myTextColumn LIKE '%  %'

Entirely set-based; no loops.

So we replace any two spaces with an unusual character and a space. If we call the unusual character X, 5 spaces become: ' X X ' and 6 spaces become ' X X X'. Then we replace 'X ' with the empty string. So 5 spaces become ' ' and 6 spaces become ' X'. Then, in case there was an even number of spaces, we remove any remaining 'X's, leaving a single space.

Paul
Indeed it does, very interesting. Seems to be the most efficient answer too.
Codesleuth
Technically `REPLACE` will loop through the text...
ck
Technically, true. But technically pretty much any SQL will involve a loop. I should have said it uses a single query.
Paul
+1. Best answer I've seen.
Lieven
Cleverly avoids looping round the table. I wonder if it could be made any more readable though
cindi
If it were me, I'd hide it away in a function. Then you'd have UPDATE myTable SET myTextColumn = dbo.ReduceSpaces(myColumnText) WHERE... and then you can put whatever explanatory text in the function.
Paul
But as we all know (I hope), scalar functions cannot be optimised, so we all avoid them (I hope!)
Codesleuth
hehe...well it depends a bit on what you're using them for.
Paul
+1  A: 
SELECT 'starting...' --sets @@rowcount
WHILE @@rowcount <> 0
    update myTable
    set myTextColumn = replace(myTextColumn, '  ', ' ')
    where myTextColumn like '%  %'
gbn
Cheeky, but not particularly efficient...
ck
I prefer "Elegant and simple"...
gbn
Using rowcount with the where clause was a good idea
cindi
A: 

Update myTable set myTextColumn = replace(myTextColumn, ' ', ' ');

The above query will remove all the double blank spaces with single blank space

But this would work only once.

Ravia
But it won't update 3 spaces in a row to be one space.
ck
whence my loop ....
cindi
+3  A: 

Here is a simple set based way that will collapse multiple spaces into a single space by applying three replaces.

DECLARE @myTable TABLE (myTextColumn VARCHAR(50))

INSERT INTO @myTable VALUES ('0Space')
INSERT INTO @myTable VALUES (' 1 Spaces 1 Spaces. ')
INSERT INTO @myTable VALUES ('  2  Spaces  2  Spaces.  ')
INSERT INTO @myTable VALUES ('   3   Spaces  3   Spaces.   ')
INSERT INTO @myTable VALUES ('    4    Spaces  4    Spaces.    ')
INSERT INTO @myTable VALUES ('     5     Spaces  5     Spaces.     ')
INSERT INTO @myTable VALUES ('      6      Spaces  6      Spaces.      ')


select replace(
          replace(
             replace(
                LTrim(RTrim(myTextColumn)), --Trim the field
             '  ',' |'),                    --Mark double spaces
          '| ',''),                         --Delete double spaces offset by 1
       '|','')                              --Tidy up
       AS SingleSpaceTextColumn
 from @myTable

Your Update statement can now be set based:

 update @myTable
    set myTextColumn = replace(
                          replace(
                             replace(
                                LTrim(RTrim(myTextColumn)),
                             '  ',' |'),
                          '| ',''),
                       '|','')  

Use an appropriate Where clause to limit the Update to only the rows that have you need to update or maybe have double spaces.

e.g.

where 1<=Patindex('%  %', myTextColumn)

I have found an external write up on this method: REPLACE Multiple Spaces with One

Andrew
I think this is the same as Paul's answer, but your comments make it a bit more readable
cindi
Well spotted they are the same method.
Andrew
External Reference clarified things
cindi
I agree it is better worded and better understandable but somehow it feels like taking credit for someone else's work. Paul's answer is exactly the same.
Lieven
@Lieven : I made the decision based on reading the external reference Andrew cited above.
cindi