web-dev-qa-db-fra.com

Requête de sélection T-SQL pour supprimer les caractères non numériques

J'ai des données sales dans une colonne de longueur alpha variable. Je veux juste éliminer tout ce qui n'est pas 0-9. 

Je ne veux pas courir une fonction ou un proc. J'ai un script similaire qui prend juste la valeur numérique après le texte, il ressemble à ceci:

Update TableName
set ColumntoUpdate=cast(replace(Columnofdirtydata,'Alpha #','') as int)
where Columnofdirtydata like 'Alpha #%'
And ColumntoUpdate is Null

Je pensais que cela fonctionnerait assez bien jusqu'à ce que je trouve que certains des champs de données que je pensais juste être au format Alpha # 12345789 ne sont pas ... 

Exemples de données à supprimer

AB ABCDE # 123
ABCDE# 123
AB: ABC# 123

Je veux juste le 123. Il est vrai que tous les champs de données ont le # avant le nombre. 

J'ai essayé sous-chaîne et PatIndex, mais je ne suis pas tout à fait la syntaxe correcte ou quelque chose. Quelqu'un a un conseil sur la meilleure façon de résoudre ce problème?

Je vous remercie!

46
SQL_Noob

Voir cet article blog sur l'extraction de nombres à partir de chaînes dans SQL Server. Vous trouverez ci-dessous un exemple utilisant une chaîne dans votre exemple:

DECLARE @textval NVARCHAR(30)
SET @textval = 'AB ABCDE # 123'

SELECT LEFT(SUBSTRING(@textval, PATINDEX('%[0-9.-]%', @textval), 8000),
           PATINDEX('%[^0-9.-]%', SUBSTRING(@textval, PATINDEX('%[0-9.-]%', @textval), 8000) + 'X') -1)
59
Ken Richards

Vous pouvez utiliser stuff et patindex .

stuff(Col, 1, patindex('%[0-9]%', Col)-1, '')

SQL Fiddle

33
Mikael Eriksson

Si certains caractères sont possibles entre les chiffres (par exemple, des séparateurs de milliers), essayez les solutions suivantes:

declare @table table (DirtyCol varchar(100))
insert into @table values
    ('AB ABCDE # 123')
    ,('ABCDE# 123')
    ,('AB: ABC# 123')
    ,('AB#')
    ,('AB # 1 000 000')
    ,('AB # 1`234`567')
    ,('AB # (9)(876)(543)')

;with tally as (select top (100) N=row_number() over (order by @@spid) from sys.all_columns),
data as (
    select DirtyCol, Col
    from @table
        cross apply (
            select (select C + ''
            from (select N, substring(DirtyCol, N, 1) C from tally where N<=datalength(DirtyCol)) [1]
            where C between '0' and '9'
            order by N
            for xml path(''))
        ) p (Col)
    where p.Col is not NULL
)
select DirtyCol, cast(Col as int) IntCol
from data

La sortie est:

DirtyCol              IntCol
--------------------- -------
AB ABCDE # 123        123
ABCDE# 123            123
AB: ABC# 123          123
AB # 1 000 000        1000000
AB # 1`234`567        1234567
AB # (9)(876)(543)    9876543

Pour la mise à jour, ajoutez ColToUpdate pour sélectionner la liste des data cte:

;with num as (...),
data as (
    select ColToUpdate, /*DirtyCol, */Col
    from ...
)
update data
set ColToUpdate = cast(Col as int)
20
i-one

Cela fonctionne bien pour moi:

CREATE FUNCTION [dbo].[StripNonNumerics]
(
  @Temp varchar(255)
)
RETURNS varchar(255)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^0-9]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End

Appelez ensuite la fonction comme suit pour voir quelque chose d'original à côté de quelque chose d'assaini:

SELECT Something, dbo.StripNonNumerics(Something) FROM TableA
13
BBauer42

Voici une solution élégante si votre serveur prend en charge la fonction TRANSLATE (sur SQL Server, il est disponible sur SQL Server 2017+ ainsi que SQL Azure).

Tout d'abord, il remplace tous les caractères non numériques par un caractère @ . Ensuite, il supprime tous les caractères @ . Vous devrez peut-être ajouter des caractères supplémentaires que vous savez éventuellement présents dans le deuxième paramètre de l'appel TRANSLATE.

select REPLACE(TRANSLATE([Col], 'abcdefghijklmnopqrstuvwxyz+()- ,#+', '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'), '@', '')
7
Clement

Pour ajouter à Ken's answer, cela gère les virgules, les espaces et les parenthèses

--Handles parentheses, commas, spaces, hyphens..
declare @table table (c varchar(256))
insert into @table
values
('This is a test 111-222-3344'),
('Some Sample Text (111)-222-3344'),
('Hello there 111222 3344 / How are you?'),
('Hello there 111 222 3344 ? How are you?'),
('Hello there 111 222 3344. How are you?')

select
replace(LEFT(SUBSTRING(replace(replace(replace(replace(replace(c,'(',''),')',''),'-',''),' ',''),',',''), PATINDEX('%[0-9.-]%', replace(replace(replace(replace(replace(c,'(',''),')',''),'-',''),' ',''),',','')), 8000),
           PATINDEX('%[^0-9.-]%', SUBSTRING(replace(replace(replace(replace(replace(c,'(',''),')',''),'-',''),' ',''),',',''), PATINDEX('%[0-9.-]%', replace(replace(replace(replace(replace(c,'(',''),')',''),'-',''),' ',''),',','')), 8000) + 'X') -1),'.','')
from @table
1
scsimon
 Declare @MainTable table(id int identity(1,1),TextField varchar(100))
  INSERT INTO @MainTable (TextField)
 VALUES
 ('6B32E')
 declare @i int=1
  Declare @originalWord varchar(100)=''
  WHile @i<=(Select count(*) from @MainTable)
  BEGIN
  Select @originalWord=TextField from @MainTable where id=@i

 Declare @r varchar(max) ='', @len int ,@c char(1), @x int = 0

    Select @len = len(@originalWord)
    declare @pn varchar(100)=@originalWord
    while @x <= @len 
    begin

      Select @c = SUBSTRING(@pn,@x,1)
    if(@c!='')
    BEGIN
            if ISNUMERIC(@c) = 0 and @c <> '-'
    BEGIN
     Select @r = cast(@r as varchar) + cast(replace((SELECT ASCII(@c)-64),'-','') as varchar)

   end
   ELSE
   BEGIN
    Select @r = @r + @c


   END

END


    Select @x = @x +1

    END
    Select @r
  Set @i=@i+1
  END
0

Voici la réponse:

DECLARE @t TABLE (tVal VARCHAR(100))

INSERT INTO @t VALUES('123')
INSERT INTO @t VALUES('123S')
INSERT INTO @t VALUES('A123,123')
INSERT INTO @t VALUES('a123..A123')


;WITH cte (original, tVal, n)
     AS
     (
         SELECT t.tVal AS original,
                LOWER(t.tVal)  AS tVal,
                65             AS n
         FROM   @t             AS t
         UNION ALL
         SELECT tVal AS original,
                CAST(REPLACE(LOWER(tVal), LOWER(CHAR(n)), '') AS VARCHAR(100)),
                n + 1
         FROM   cte
         WHERE  n <= 90
     )

SELECT t1.tVal  AS OldVal,
       t.tval   AS NewVal
FROM   (
           SELECT original,
                  tVal,
                  ROW_NUMBER() OVER(PARTITION BY tVal + original ORDER BY original) AS Sl
           FROM   cte
           WHERE  PATINDEX('%[a-z]%', tVal) = 0
       ) t
       INNER JOIN @t t1
            ON  t.original = t1.tVal
WHERE  t.sl = 1
0
Khorshed Alam
Create function fn_GetNumbersOnly(@pn varchar(100))
    Returns varchar(max)
    AS
    BEGIN
      Declare @r varchar(max) ='', @len int ,@c char(1), @x int = 0
      Select @len = len(@pn)
      while @x <= @len 
      begin
        Select @c = SUBSTRING(@pn,@x,1)
        if ISNUMERIC(@c) = 1 and @c <> '-'
         Select @r = @r + @c
       Select @x = @x +1
      end
    return @r
End
0
eDriven_Levar

Voici une version qui extrait tous les chiffres d'une chaîne. c'est-à-dire, donné I'm 35 years old; I was born in 1982. The average family has 2.4 children., ceci renverrait 35198224. c'est-à-dire que c'est bon lorsque vous avez des données numériques qui ont peut-être été formatées sous forme de code (par exemple, #123,456,789/123-00005), mais qui ne conviennent pas si vous cherchez à extraire des nombres spécifiques (c'est-à-dire par opposition aux chiffres/uniquement numériques) caractères) du texte. En outre, il ne gère que les chiffres; donc ne retournera pas de signes négatifs (-) ni de périodes .).

declare @table table (id bigint not null identity (1,1), data nvarchar(max)) 
insert @table (data) 
values ('hello 123 its 45613 then') --outputs: 12345613
,('1 some other string 98 example 4') --outputs: 1984
,('AB ABCDE # 123') --outputs: 123 
,('ABCDE# 123') --outputs: 123
,('AB: ABC# 123') --outputs: 123
; with NonNumerics as (
    select id
    , data original
    --the below line replaces all digits with blanks
    , replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(data,'0',''),'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9','') nonNumeric
    from @table
)
--each iteration of the below CTE removes another non-numeric character from the original string, putting the result into the numerics column
, Numerics as (
    select id
    , replace(original, substring(nonNumeric,1,1), '') numerics
    , replace(nonNumeric, substring(nonNumeric,1,1), '') charsToreplace
    , len(replace(nonNumeric, substring(nonNumeric,1,1), '')) charsRemaining
    from NonNumerics

    union all

    select id
    , replace(numerics, substring(charsToreplace,1,1), '') numerics
    , replace(charsToreplace, substring(charsToreplace,1,1), '') charsToreplace
    , len(replace(charsToreplace, substring(charsToreplace,1,1), '')) charsRemaining
    from Numerics
    where charsRemaining > 0
)
--we select only those strings with `charsRemaining=0`; i.e. the rows for which all non-numeric characters have been removed; there should be 1 row returned for every 1 row in the original data set.
select * from Numerics where charsRemaining = 0

Ce code fonctionne en supprimant tous les chiffres (c'est-à-dire les caractères souhaités) d'une chaîne donnée en les remplaçant par des blancs. Ensuite, il passe par la chaîne d'origine (qui comprend les chiffres) en supprimant tous les caractères qui ont été laissés (c'est-à-dire les caractères non numériques), ne laissant ainsi que les chiffres.

La raison pour laquelle nous faisons cela en 2 étapes, plutôt que de simplement supprimer tous les caractères non numériques, est qu'il n'y a que 10 chiffres, alors qu'il y a un très grand nombre de caractères possibles; le remplacement de cette petite liste est donc relativement rapide; puis nous donne une liste de ces caractères non numériques qui existent réellement dans la chaîne, afin que nous puissions ensuite remplacer ce petit ensemble.

La méthode utilise un SQL récursif en utilisant des expressions de table communes (CTE).

0
JohnLBevan

Dans votre cas, il semble que le symbole # sera toujours après le symbole #; utiliser CHARINDEX () avec LTRIM () et RTRIM () donnerait probablement les meilleurs résultats. Mais voici une méthode intéressante pour se débarrasser de N'IMPORTE QUEL chiffre. Il utilise une table de comptage et un tableau de chiffres pour limiter les caractères acceptés, puis la technique XML pour concaténer en une seule chaîne sans les caractères non numériques. La bonne chose à propos de cette technique est qu’elle pourrait être étendue pour inclure TOUS les caractères autorisés et supprimer tout ce qui n’est pas autorisé.

DECLARE @ExampleData AS TABLE (Col VARCHAR(100))
INSERT INTO @ExampleData (Col) VALUES ('AB ABCDE # 123'),('ABCDE# 123'),('AB: ABC# 123')

DECLARE @Digits AS TABLE (D CHAR(1))
INSERT INTO @Digits (D) VALUES ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9')

;WITH cteTally AS (
SELECT
    I = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM
    @Digits d10
    CROSS APPLY @Digits d100
    --add more cross applies to cover longer fields this handles 100
)

SELECT *
FROM
    @ExampleData e
    OUTER APPLY (
    SELECT CleansedPhone = CAST((
    SELECT TOP 100
       SUBSTRING(e.Col,t.I,1)
    FROM
       cteTally t
       INNER JOIN @Digits d
       ON SUBSTRING(e.Col,t.I,1) = d.D
    WHERE
       I <= LEN(e.Col)
    ORDER BY
       t.I
    FOR XML PATH('')) AS VARCHAR(100))) o
0
Matt

Cela a fonctionné pour moi:

  1. J'ai enlevé les guillemets simples.

  2. J'ai ensuite utilisé un remplacer "," avec ".".

Cela aidera sûrement quelqu'un:

" & txtFinalscore.Text.Replace(",", ".") & "
0
Peter Mankge

Vous pouvez créer une fonction scalaire SQL CLR afin de pouvoir utiliser des expressions régulières telles que les modèles de remplacement. 

Ici vous pouvez trouver un exemple sur la façon de créer une telle fonction. 

Avoir une telle fonction résoudra le problème avec juste les lignes suivantes:

SELECT [dbo].[fn_Utils_RegexReplace] ('AB ABCDE # 123', '[^0-9]', '');
SELECT [dbo].[fn_Utils_RegexReplace] ('ABCDE# 123', '[^0-9]', '');
SELECT [dbo].[fn_Utils_RegexReplace] ('AB: ABC# 123', '[^0-9]', '');

Plus important encore, vous serez en mesure de résoudre des problèmes plus complexes, car les expressions régulières apporteront un tout nouveau monde d’options directement dans vos instructions T-SQL.

0
gotqn

J'ai créé une fonction pour ce 

Create FUNCTION RemoveCharacters (@text varchar(30))
RETURNS VARCHAR(30)
AS
BEGIN
declare @index as int 
declare @newtexval as varchar(30)
set @index = (select PATINDEX('%[A-Z.-/?]%', @text))
if (@index =0)
begin 
return @text
end
else
begin 
set @newtexval  = (select STUFF ( @text , @index , 1 , '' ))
return dbo.RemoveCharacters(@newtexval)
end
return 0
END
GO
0
leonardo sanchez
CREATE FUNCTION FN_RemoveNonNumeric (@Input NVARCHAR(512))
RETURNS NVARCHAR(512)
AS
BEGIN
DECLARE @Trimmed NVARCHAR(512)

SELECT @Trimmed = @Input

WHILE PATINDEX('%[^0-9]%', @Trimmed) > 0
    SELECT @Trimmed = REPLACE(@Trimmed, SUBSTRING(@Trimmed, PATINDEX('%[^0-9]%', @Trimmed), 1), '')

RETURN @Trimmed
END

GO

SELECT dbo.FN_RemoveNonNumeric('ABCDE# 123')
0
Elmer C