Comment remplacer plusieurs caractères dans SQL?

Ceci est basé sur une question similaire Comment remplacer plusieurs caractères dans Access SQL?

j'ai écrit ceci depuis que sql server 2005 semble avoir une limite sur la fonction replace() à 19 remplacements à l'intérieur d'une clause where.

j'ai la tâche suivante: besoin d'effectuer une correspondance sur une colonne, et d'améliorer les chances d'une correspondance démêler plusieurs caractères non nécessaires en utilisant remplacer () la fonction

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, ça ne marche pas. Donc la solution que j'ai trouvée est de créer une fonction sql appelée trimChars dans cet exemple (excusez-les commençant à @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 ê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éé un peu plus de fonctions pour faire similaires en remplaçant comme ainsi 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)))

est-ce que quelqu'un peut me donner une meilleure solution à ce problème en termes de performance et peut-être une mise en œuvre plus propre?

30
demandé sur Community 2009-10-16 23:38:23

9 réponses

je considérerais sérieusement faire un CLR UDF au lieu de et en utilisant des expressions régulières (à la fois la chaîne et le modèle peuvent être passés en tant que paramètres) pour faire une recherche complète et remplacer pour une gamme de caractères. Il devrait facilement surpasser ce SQL UDF.

22
répondu Cade Roux 2018-01-15 21:59:59

un truc utile en SQL est la capacité d'utiliser @var = function(...) pour assigner une valeur. Si vous avez plusieurs enregistrements dans votre jeu de disques, votre var est assigné 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'
44
répondu Juliet 2013-05-23 17:21:13

j'aime vraiment la solution de @Juliett! Je voudrais juste utiliser un CTE pour obtenir tous les caractères invalides:

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

Juliette ro0zs mon s0xrzone

14
répondu Duanne 2015-03-20 08:35:26

je vous suggère de créer une fonction scalaire définie par l'utilisateur. Ceci est un exemple (désolé à l'avance, parce que les noms de 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 d'utilisation de 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 voir, chaque caractère du paramètre @caracteresElim est remplacé par le caractère dans la même position du @caracteresReem paramètre.

2
répondu Guillermo Gutiérrez 2013-01-18 20:57:17
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;
1
répondu Adil 2016-06-01 16:01:41

une option est d'utiliser une table de nombres/décompte pour piloter un processus itératif via une requête basée sur un pseudo-jeu.

l'idée générale du remplacement de l'omble peut être démontrée à l'aide d'une table de correspondance 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

alors vous pouvez introduire l'approche de la table de comptage pour faire la recherche sur chaque position de 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)
0
répondu ahains 2009-10-16 20:46:27

Je ne sais pas pourquoi Charles Bretana a supprimé sa réponse, donc je l'ajoute de nouveau comme une réponse CW, mais une colonne persisted computed est un très bon moyen de gérer ces cas où vous avez besoin de données nettoyées ou transformées presque tout le temps, mais besoin de préserver les déchets d'origine. Sa suggestion est pertinente et appropriée quelle que soit 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 garnitures tous les zéros de tête (heureusement, cela est en réalité facilement manipulé en T-SQL droit) à partir de certains identificateurs numériques particuliers stockés de manière incohérente avec des zéros de tête. Ceci est stocké dans les colonnes calculées persistées dans les tables qui en ont besoin et indexées parce que cet identifiant conformé est souvent utilisé dans les jointures.

0
répondu Cade Roux 2009-10-17 02:58:29

Voici les étapes

  1. créer une fonction CLR

voir 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;
    }
}
}
  1. déployez votre fonction CLR

  2. maintenant tester

voir 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!!!!!!!!!!!!!
0
répondu HimalayanNinja 2014-03-21 10:00:32

bien que cette question ait été posée à propos de SQL Server 2005, il est intéressant de noter qu'à partir de Sql Server 2017, la requête peut être faite avec la nouvelle fonction TRANSLATE.

https://docs.microsoft.com/en-us/sql/t-sql/functions/translate-transact-sql

j'espère que cette information aide les gens qui arrivent à cette page à l'avenir.

0
répondu Ethan1701 2018-02-14 13:44:33