Ceci est basé sur une question similaire Comment remplacer plusieurs caractères dans Access SQL?
J'ai écrit ceci car SQL Server 2005 semble avoir une limite sur la fonction replace () à 19 remplacements dans une clause where.
J'ai la tâche suivante: Nécessité d'effectuer une correspondance sur une colonne et d'améliorer les chances qu'une correspondance supprime plusieurs caractères inutiles à l'aide de la fonction replace ()
DECLARE @es NVarChar(1) SET @es = ''
DECLARE @p0 NVarChar(1) SET @p0 = '!'
DECLARE @p1 NVarChar(1) SET @p1 = '@'
---etc...
SELECT *
FROM t1,t2
WHERE REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es)
= REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es)
---etc
S'il y a> 19 REPLACE () dans cette clause where, cela ne fonctionne pas. La solution que j’ai proposée est donc de créer une fonction SQL appelée trimChars dans cet exemple (excusez-les à partir de @ 22
CREATE FUNCTION [trimChars] (
@string varchar(max)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE @es NVarChar(1) SET @es = ''
DECLARE @p22 NVarChar(1) SET @p22 = '^'
DECLARE @p23 NVarChar(1) SET @p23 = '&'
DECLARE @p24 NVarChar(1) SET @p24 = '*'
DECLARE @p25 NVarChar(1) SET @p25 = '('
DECLARE @p26 NVarChar(1) SET @p26 = '_'
DECLARE @p27 NVarChar(1) SET @p27 = ')'
DECLARE @p28 NVarChar(1) SET @p28 = '`'
DECLARE @p29 NVarChar(1) SET @p29 = '~'
DECLARE @p30 NVarChar(1) SET @p30 = '{'
DECLARE @p31 NVarChar(1) SET @p31 = '}'
DECLARE @p32 NVarChar(1) SET @p32 = ' '
DECLARE @p33 NVarChar(1) SET @p33 = '['
DECLARE @p34 NVarChar(1) SET @p34 = '?'
DECLARE @p35 NVarChar(1) SET @p35 = ']'
DECLARE @p36 NVarChar(1) SET @p36 = '\'
DECLARE @p37 NVarChar(1) SET @p37 = '|'
DECLARE @p38 NVarChar(1) SET @p38 = '<'
DECLARE @p39 NVarChar(1) SET @p39 = '>'
DECLARE @p40 NVarChar(1) SET @p40 = '@'
DECLARE @p41 NVarChar(1) SET @p41 = '-'
return REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
@string, @p22, @es), @p23, @es), @p24, @es), @p25, @es), @p26, @es), @p27, @es), @p28, @es), @p29, @es), @p30, @es), @p31, @es), @p32, @es), @p33, @es), @p34, @es), @p35, @es), @p36, @es), @p37, @es), @p38, @es), @p39, @es), @p40, @es), @p41, @es)
END
Ceci peut alors être utilisé en plus des autres chaînes de remplacement
SELECT *
FROM t1,t2
WHERE trimChars(REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es)
= REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es))
J'ai créé quelques fonctions supplémentaires pour effectuer un remplacement similaire, comme so trimChars (trimMoreChars (
SELECT *
FROM t1,t2
WHERE trimChars(trimMoreChars(REPLACE(REPLACE(t1.stringkey,@p0, @es), @p1, @es)
= REPLACE(REPLACE(t2.stringkey,@p0, @es), @p1, @es)))
Quelqu'un peut-il me donner une meilleure solution à ce problème en termes de performances et peut-être une mise en œuvre plus propre?
Je considérerais sérieusement faisant un UDF CLR } _ à la place et utilisant des expressions régulières (la chaîne et le motif peuvent être passés en paramètres) personnages. Il devrait facilement surpasser cet UDF SQL.
Une astuce utile en SQL est la possibilité d’utiliser @var = function(...)
pour attribuer une valeur. Si vous avez plusieurs enregistrements dans votre jeu d'enregistrements, votre var est affecté plusieurs fois avec des effets secondaires:
declare @badStrings table (item varchar(50))
INSERT INTO @badStrings(item)
SELECT '>' UNION ALL
SELECT '<' UNION ALL
SELECT '(' UNION ALL
SELECT ')' UNION ALL
SELECT '!' UNION ALL
SELECT '?' UNION ALL
SELECT '@'
declare @testString varchar(100), @newString varchar(100)
set @teststring = 'Juliet ro><0zs my s0x()rz!!?!one!@!@!@!'
set @newString = @testString
SELECT @newString = Replace(@newString, item, '') FROM @badStrings
select @newString -- returns 'Juliet ro0zs my s0xrzone'
J'aime beaucoup la solution de @ Juliett! Je voudrais juste utiliser un CTE pour obtenir tous les caractères non valides:
DECLARE @badStrings VARCHAR(100)
DECLARE @teststring VARCHAR(100)
SET @badStrings = '><()!?@'
SET @teststring = 'Juliet ro><0zs my s0x()rz!!?!one!@!@!@!'
;WITH CTE AS
(
SELECT SUBSTRING(@badStrings, 1, 1) AS [String], 1 AS [Start], 1 AS [Counter]
UNION ALL
SELECT SUBSTRING(@badStrings, [Start] + 1, 1) AS [String], [Start] + 1, [Counter] + 1
FROM CTE
WHERE [Counter] < LEN(@badStrings)
)
SELECT @teststring = REPLACE(@teststring, CTE.[String], '') FROM CTE
SELECT @teststring
Juliet ro0zs mon s0xrzone
Je vous suggère de créer une fonction définie par l'utilisateur scalaire. Ceci est un exemple (désolé d'avance, car les noms des variables sont en espagnol):
CREATE FUNCTION [dbo].[Udf_ReplaceChars] (
@cadena VARCHAR(500), -- String to manipulate
@caracteresElim VARCHAR(100), -- String of characters to be replaced
@caracteresReem VARCHAR(100) -- String of characters for replacement
)
RETURNS VARCHAR(500)
AS
BEGIN
DECLARE @cadenaFinal VARCHAR(500), @longCad INT, @pos INT, @caracter CHAR(1), @posCarER INT;
SELECT
@cadenaFinal = '',
@longCad = LEN(@cadena),
@pos = 1;
IF LEN(@caracteresElim)<>LEN(@caracteresReem)
BEGIN
RETURN NULL;
END
WHILE @pos <= @longCad
BEGIN
SELECT
@caracter = SUBSTRING(@cadena,@pos,1),
@pos = @pos + 1,
@posCarER = CHARINDEX(@caracter,@caracteresElim);
IF @posCarER <= 0
BEGIN
SET @cadenaFinal = @cadenaFinal + @caracter;
END
ELSE
BEGIN
SET @cadenaFinal = @cadenaFinal + SUBSTRING(@caracteresReem,@posCarER,1)
END
END
RETURN @cadenaFinal;
END
Voici un exemple utilisant cette fonction:
SELECT dbo.Udf_ReplaceChars('This is a test.','sat','Z47');
Et le résultat est: 7hiZ iZ 4 7eZ7.
Comme vous pouvez le constater, chaque caractère du paramètre @caracteresElim
est remplacé par le caractère situé au même emplacement à partir du paramètre @caracteresReem
.
declare @testVal varchar(20)
set @testVal = '?t/es?ti/n*g 1*2?3*'
select @testVal = REPLACE(@testVal, item, '') from (select '?' item union select '*' union select '/') list
select @testVal;
Une option consiste à utiliser une table de nombres/comptage pour diriger un processus itératif via une requête basée sur un pseudo-ensemble.
L'idée générale de remplacement de caractères peut être démontrée avec une approche de table de carte de caractères simple:
create table charMap (srcChar char(1), replaceChar char(1))
insert charMap values ('a', 'z')
insert charMap values ('b', 'y')
create table testChar(srcChar char(1))
insert testChar values ('1')
insert testChar values ('a')
insert testChar values ('2')
insert testChar values ('b')
select
coalesce(charMap.replaceChar, testChar.srcChar) as charData
from testChar left join charMap on testChar.srcChar = charMap.srcChar
Ensuite, vous pouvez utiliser l'approche de la table de pointage pour effectuer la recherche sur chaque position du caractère dans la chaîne.
create table tally (i int)
declare @i int
set @i = 1
while @i <= 256 begin
insert tally values (@i)
set @i = @i + 1
end
create table testData (testString char(10))
insert testData values ('123a456')
insert testData values ('123ab456')
insert testData values ('123b456')
select
i,
SUBSTRING(testString, i, 1) as srcChar,
coalesce(charMap.replaceChar, SUBSTRING(testString, i, 1)) as charData
from testData cross join tally
left join charMap on SUBSTRING(testString, i, 1) = charMap.srcChar
where i <= LEN(testString)
Bien que cette question concerne SQL Server 2005, il convient de noter que depuis SQL Server 2017, la requête peut être effectuée à l'aide de la nouvelle fonction TRANSLATE.
https://docs.Microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql
J'espère que cette information aidera les personnes qui accèdent à cette page à l'avenir.
Je ne sais pas pourquoi Charles Bretana a supprimé sa réponse. Je l'ajoute donc sous forme de réponse CW, mais une colonne calculée persistante est un VRAIMENT bon moyen de gérer ces cas où vous avez besoin presque toujours de données nettoyées ou transformées. , mais il faut préserver les ordures d'origine. Sa suggestion est pertinente et appropriée, peu importe la façon dont vous décidez de nettoyer vos données.
Plus précisément, dans mon projet actuel, j'ai une colonne calculée persistante qui élimine tous les zéros non significatifs (heureusement, cette tâche est facilement gérée de manière simple dans T-SQL) à partir de certains identificateurs numériques stockés de manière incohérente avec les zéros non significatifs. Ceci est stocké dans des colonnes calculées persistantes dans les tables qui en ont besoin et indexé car cet identifiant conforme est souvent utilisé dans les jointures.
Voici les étapes
Voir le code suivant:
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString Replace2(SqlString inputtext, SqlString filter,SqlString replacewith)
{
string str = inputtext.ToString();
try
{
string pattern = (string)filter;
string replacement = (string)replacewith;
Regex rgx = new Regex(pattern);
string result = rgx.Replace(str, replacement);
return (SqlString)result;
}
catch (Exception s)
{
return (SqlString)s.Message;
}
}
}
Déployez votre fonction CLR
Maintenant le tester
Voir le code suivant:
create table dbo.test(dummydata varchar(255))
Go
INSERT INTO dbo.test values('P@ssw1rd'),('This 12is @test')
Go
Update dbo.test
set dummydata=dbo.Replace2(dummydata,'[0-9@]','')
select * from dbo.test
dummydata, Psswrd, This is test booom!!!!!!!!!!!!!