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!
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)
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)
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
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+()- ,#+', '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'), '@', '')
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
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
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
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
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).
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
Cela a fonctionné pour moi:
J'ai enlevé les guillemets simples.
J'ai ensuite utilisé un remplacer ","
avec "."
.
Cela aidera sûrement quelqu'un:
" & txtFinalscore.Text.Replace(",", ".") & "
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.
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
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')