it-swarm.com.de

Wie entferne ich Akzente und alle Zeichen <> a..z im SQL-Server?

Ich muss folgende Änderungen an einem varchar (20) -Feld vornehmen:

  1. ersatzakzente mit normalen Buchstaben (wie è bis e)
  2. nach (1) alle Zeichen entfernen, die nicht in a..z sind

zum Beispiel

'aèàç=.32s df' 

muss werden 

'aeacsdf'

gibt es spezielle gespeicherte Funktionen, um dies problemlos zu erreichen?

UPDATE: Bitte geben Sie eine T-SQL- und keine CLR-Lösung an. Dies ist der Workaround, den ich vorübergehend durchgeführt habe, da er zeitlich auf meine Bedürfnisse zugeschnitten ist. Eine elegantere Vorgehensweise wäre jedoch besser.

CREATE FUNCTION sf_RemoveExtraChars (@NAME nvarchar(50))
RETURNS nvarchar(50)
AS
BEGIN
  declare @TempString nvarchar(100)
  set @TempString = @NAME 
  set @TempString = LOWER(@TempString)
  set @TempString =  replace(@TempString,' ', '')
  set @TempString =  replace(@TempString,'à', 'a')
  set @TempString =  replace(@TempString,'è', 'e')
  set @TempString =  replace(@TempString,'é', 'e')
  set @TempString =  replace(@TempString,'ì', 'i')
  set @TempString =  replace(@TempString,'ò', 'o')
  set @TempString =  replace(@TempString,'ù', 'u')
  set @TempString =  replace(@TempString,'ç', 'c')
  set @TempString =  replace(@TempString,'''', '')
  set @TempString =  replace(@TempString,'`', '')
  set @TempString =  replace(@TempString,'-', '')
  return @TempString
END
GO
37
LaBracca

Sie suchen etwas, um Diakritik von einzelnen Zeichen zu entfernen. Ich fürchte, die Lösung, die Sie haben, wird zumindest mit reinem SQL fast so gut wie möglich sein. dotNet/CLR stellt jedoch eine einfache Methode zur Verfügung. Entschuldigung, ich weiß, dass Sie eine andere CLR-Lösung vermeiden möchten, aber Microsoft SQL Server bietet hierfür kein T-SQL-Äquivalent.

Wenn Sie Glück haben, haben Sie in Ihrer Datenbank die Einstellung Kollatierung als "SQL_Latin1_General_CP1_CI_AS" oder eine beliebige Variante, die mit "SQL_Latin1_General" beginnt. Dies ist äquivalent zu Windows-1252, das sehr gut dokumentiert ist. Sie können jedes Zeichen in ein englisches Äquivalent "übersetzen", indem Sie die Zeichen überprüfen und ein Äquivalent mithilfe einer SQL-CASE-Anweisung wie zuvor zuordnen.

Ich habe jedoch eine schnelle Korrektur für Ihren Code. Sie möchten varchar in Ihren Variablen und Parametern verwenden. Es erzeugt zusätzlichen Overhead, der die Datentypkonvertierung vor und zurück durchführt, und kann Unicode-Zeichen, die nur als Unicode vorliegen, in die Mischung einfügen. Außerdem finden Sie auf Bruce Schneier s Blog einen für Ihre Situation spezifischen sicherheitsbezogenen Grund.

Update Einige großartige Informationen zu Diacritics und zur Internationalisierung von Windows finden Sie im Blog von Michael S Kaplan .

15
jveazey

Der beste Weg, dies zu erreichen, ist sehr einfach und effizient:

SELECT 'àéêöhello!' Collate SQL_Latin1_General_CP1253_CI_AI

welche gibt 'aeeohello!'

Die Zeichenfolge darf kein Unicode sein. Wenn Sie einen nvarchar haben, werfen Sie ihn einfach in varchar, bevor Sie die Sortierung verwenden.

Hier ist eine Funktion, die den OP-Anforderungen entspricht:

create function [dbo].[RemoveExtraChars] ( @p_OriginalString varchar(50) )
returns varchar(50) as
begin

  declare @i int = 1;  -- must start from 1, as SubString is 1-based
  declare @OriginalString varchar(100) = @p_OriginalString Collate SQL_Latin1_General_CP1253_CI_AI;
  declare @ModifiedString varchar(100) = '';

  while @i <= Len(@OriginalString)
  begin
    if SubString(@OriginalString, @i, 1) like '[a-Z]'
    begin
      set @ModifiedString = @ModifiedString + SubString(@OriginalString, @i, 1);
    end
    set @i = @i + 1;
  end

  return @ModifiedString

end

Dann der Befehl:

select dbo.RemoveExtraChars('aèàç=.32s df')

ausgänge

aeacsdf
96
Dominic Goulet
    SELECT 'áéíóú' COLLATE Cyrillic_General_CI_AI

Dies wird alle akzentuierten Zeichen ersetzen ...

ergebnis: aeiou

Hoffe das hilft dir!

6

Lassen Sie mich zunächst etwas klarstellen: Die von Ihnen gezeigten Zeichen mit Akzent sind eigentlich kein Unicode (wie eine Antwort impliziert); Dies sind 8-Bit ASCII Zeichen. Eine Sache, die Sie im Hinterkopf behalten sollten: Sie sehen Zeichen wie è und à, weil Ihre Codepage (die von Ihrem Betriebssystem und/oder SQL-Server verwendete Codepage (ich bin nicht sicher, welche)) sie anzeigt. In einer anderen Codepage werden diese Zeichen durch völlig unterschiedliche Symbole dargestellt (z. B. wenn Sie eine kyrillische oder türkische Codepage verwenden).

Nehmen Sie an, Sie möchten diese 8-Bit-Zeichen durch das nächstgelegene US-/lateinische Zeichen für Ihre Standard-Codepage ersetzen. Auf diese Weise bin ich an ein ähnliches Problem herangegangen (Haftungsausschluss: Dies ist keine sehr elegante Lösung, aber zu dieser Zeit konnte ich mir nichts Besseres vorstellen):

Erstellen Sie eine UDF, um ein 8-Bit-Zeichen ASCII in ein druckbares 7-Bit-Format ASCII zu übersetzen, z.

CREATE FUNCTION dbo.fnCharToAscii
(
  @Char AS VARCHAR
)
RETURNS
  VARCHAR   
AS
BEGIN
IF (@Char IS NULL)
  RETURN ''

-- Process control and DEL chars.
IF (ASCII(@Char) < 32) OR (ASCII(@Char) = 127)
    RETURN ''

-- Return printable 7-bit ASCII chars as is.
-- UPDATE TO DELETE NON-ALPHA CHARS.
IF (ASCII(@Char) >= 32) AND (ASCII(@Char) < 127)
    RETURN @Char

-- Process 8-bit ASCII chars.
RETURN
  CASE ASCII(@Char)
    WHEN 128 THEN 'E'
    WHEN 129 THEN '?'
    WHEN 130 THEN ','
    WHEN 131 THEN 'f'
    WHEN 132 THEN ','
    WHEN 133 THEN '.'
    WHEN 134 THEN '+'
    WHEN 135 THEN '+'
    WHEN 136 THEN '^'
    WHEN 137 THEN '%'
    WHEN 138 THEN 'S'
    WHEN 139 THEN '<'
    WHEN 140 THEN 'C'
    WHEN 141 THEN '?'
    WHEN 142 THEN 'Z'
    WHEN 143 THEN '?'
    WHEN 144 THEN '?'
    WHEN 145 THEN ''''
    WHEN 146 THEN ''''
    WHEN 147 THEN '"'
    WHEN 148 THEN '"'
    WHEN 149 THEN '-'
    WHEN 150 THEN '-'
    WHEN 151 THEN '-'
    WHEN 152 THEN '~'
    WHEN 153 THEN '?'
    WHEN 154 THEN 's'
    WHEN 155 THEN '>'
    WHEN 156 THEN 'o'
    WHEN 157 THEN '?'
    WHEN 158 THEN 'z'
    WHEN 159 THEN 'Y'
    WHEN 160 THEN ' '
    WHEN 161 THEN 'i'
    WHEN 162 THEN 'c'
    WHEN 163 THEN 'L'
    WHEN 164 THEN '?'
    WHEN 165 THEN 'Y'
    WHEN 166 THEN '|'
    WHEN 167 THEN '$'
    WHEN 168 THEN '^'
    WHEN 169 THEN 'c'
    WHEN 170 THEN 'a'
    WHEN 171 THEN '<'
    WHEN 172 THEN '-'
    WHEN 173 THEN '-'
    WHEN 174 THEN 'R'
    WHEN 175 THEN '-'
    WHEN 176 THEN 'o'
    WHEN 177 THEN '+'
    WHEN 178 THEN '2'
    WHEN 179 THEN '3'
    WHEN 180 THEN ''''
    WHEN 181 THEN 'm'
    WHEN 182 THEN 'P'
    WHEN 183 THEN '-'
    WHEN 184 THEN ','
    WHEN 185 THEN '1'
    WHEN 186 THEN '0'
    WHEN 187 THEN '>'
    WHEN 188 THEN '?'
    WHEN 189 THEN '?'
    WHEN 190 THEN '?'
    WHEN 191 THEN '?'
    WHEN 192 THEN 'A'
    WHEN 193 THEN 'A'
    WHEN 194 THEN 'A'
    WHEN 195 THEN 'A'
    WHEN 196 THEN 'A'
    WHEN 197 THEN 'A'
    WHEN 198 THEN 'A'
    WHEN 199 THEN 'C'
    WHEN 200 THEN 'E'
    WHEN 201 THEN 'E'
    WHEN 202 THEN 'E'
    WHEN 203 THEN 'E'
    WHEN 204 THEN 'I'
    WHEN 205 THEN 'I'
    WHEN 206 THEN 'I'
    WHEN 207 THEN 'I'
    WHEN 208 THEN 'D'
    WHEN 209 THEN 'N'
    WHEN 210 THEN 'O'
    WHEN 211 THEN 'O'
    WHEN 212 THEN 'O'
    WHEN 213 THEN 'O'
    WHEN 214 THEN 'O'
    WHEN 215 THEN 'x'
    WHEN 216 THEN 'O'
    WHEN 217 THEN 'U'
    WHEN 218 THEN 'U'
    WHEN 219 THEN 'U'
    WHEN 220 THEN 'U'
    WHEN 221 THEN 'Y'
    WHEN 222 THEN 'b'
    WHEN 223 THEN 'B'
    WHEN 224 THEN 'a'
    WHEN 225 THEN 'a'
    WHEN 226 THEN 'a'
    WHEN 227 THEN 'a'
    WHEN 228 THEN 'a'
    WHEN 229 THEN 'a'
    WHEN 230 THEN 'a'
    WHEN 231 THEN 'c'
    WHEN 232 THEN 'e'
    WHEN 233 THEN 'e'
    WHEN 234 THEN 'e'
    WHEN 235 THEN 'e'
    WHEN 236 THEN 'i'
    WHEN 237 THEN 'i'
    WHEN 238 THEN 'i'
    WHEN 239 THEN 'i'
    WHEN 240 THEN 'o'
    WHEN 241 THEN 'n'
    WHEN 242 THEN 'o'
    WHEN 243 THEN 'o'
    WHEN 244 THEN 'o'
    WHEN 245 THEN 'o'
    WHEN 246 THEN 'o'
    WHEN 247 THEN '-'
    WHEN 248 THEN 'o'
    WHEN 249 THEN 'u'
    WHEN 250 THEN 'u'
    WHEN 251 THEN 'u'
    WHEN 252 THEN 'u'
    WHEN 253 THEN 'y'
    WHEN 254 THEN 'b'
    WHEN 255 THEN 'y'
  END
RETURN ''
END

Der obige Code ist für allgemeine Zwecke gedacht, sodass Sie die Zeichenzuordnungen anpassen können, um alle nicht alphabetischen Zeichen zu entfernen, z. Sie können Code wie folgt im Abgleich für druckbare 7-Bit ASCII Zeichen verwenden (dies setzt eine Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung voraus):

IF @Char NOT LIKE '[a-z]' RETURN ''

Führen Sie den folgenden Code aus, um festzustellen, ob Ihre Zeichenzuordnung für 8-Bit ASCII -Symbole ordnungsgemäß funktioniert.

DECLARE @I   INT
DECLARE @Msg VARCHAR(32)

SET @I = 128

WHILE @I < 256
BEGIN
    SELECT @Msg = CAST(@I AS VARCHAR) + 
    ': ' + 
    CHAR(@I) + 
    '=' + 
    dbo.fnCharToAscii(CHAR(@I))
    PRINT @Msg
    SET @I = @I + 1 
END

Jetzt können Sie eine UDF erstellen, um eine Zeichenfolge zu verarbeiten:

CREATE FUNCTION dbo.fnStringToAscii
(
  @Value AS VARCHAR(8000)
)
RETURNS
  VARCHAR(8000) 
AS
BEGIN
IF (@Value IS NULL OR DATALENGTH(@Value) = 0)
  RETURN ''

DECLARE @Index  INT
DECLARE @Result VARCHAR(8000)

SET @Result = ''
SET @Index  = 1

WHILE (@Index <= DATALENGTH(@Value))
BEGIN
  SET @Result = @Result + dbo.fnCharToAscii(SUBSTRING(@Value, @Index, 1))
  SET @Index = @Index + 1   
END

RETURN @Result
END
GO
5
Alek Davis

Sie können hartcodierte REPLACE-Anweisungen vermeiden, indem Sie eine COLLATE-Klausel mit einer akzentunabhängigen Kollatierung verwenden, um die akzentuierten alphabetischen Zeichen mit nicht alphabetischen zu vergleichen: 

DECLARE 
  @s1 NVARCHAR(200),
  @s2 NVARCHAR(200)

SET @s1 = N'aèàç=.32s df' 

SET @s2 = N''
SELECT @s2 = @s2 + no_accent 
FROM ( 
  SELECT 
    SUBSTRING(@s1, number, 1) AS accent,
    number
  FROM master.dbo.spt_values 
  WHERE TYPE = 'P'
  AND number BETWEEN 1 AND LEN(@s1) 
) s1 
INNER JOIN (
  SELECT NCHAR(number) AS no_accent
  FROM master.dbo.spt_values 
  WHERE type = 'P'
  AND (number BETWEEN 65 AND 90 OR number BETWEEN 97 AND 122) 
) s2 
  ON s1.accent COLLATE LATIN1_GENERAL_CS_AI = s2.no_accent 
ORDER BY number

SELECT @s1 
SELECT @s2 

/*
aèàç=.32s df
aeacsdf
*/
4
8kb

Nun, das ist nicht viel besser, aber es ist zumindest eine Lösung, die sich auf das SQL-Netzwerk konzentriert

declare @TempString varchar(100)

set @TempString='textàè containing éìòaccentsç''''` and things-'

select @TempString=
    replace(
        replace(
            replace(
                replace(
                    replace(
                        replace(
                            replace(
                                replace(
                                    replace(
                                        replace(
                                            replace(@TempString,' ', '') 
                                        ,'à', 'a')
                                    ,'è', 'e') 
                                ,'é', 'e')
                            ,'ì', 'i')
                        ,'ò', 'o') 
                    ,'ù', 'u') 
                ,'ç', 'c') 
            ,'''', '') 
        ,'`', '')
    ,'-', '') 



select @TempString
2
DForck42

AFAIK, es gibt keine direkte Zuordnung für Unicode/UTF-X-Zeichen, die "ähnlich aussehen". Wenn nicht irgendjemand etwas Cooleres hat, würde ich vorschlagen, einen Ansatz zu verfolgen, damit Sie Ihre Arbeit bis dahin erledigen können. 

Es klingt, als müssten Sie 2 Pässe machen. Der erste Durchlauf besteht darin, Buchstaben zu ersetzen, die zuerst ähnlich aussehen, dann alle anderen nicht-englischen Buchstaben durchzublättern und zu entfernen.

In diesem Artikel können Sie eine benutzerdefinierte Funktion erstellen, mit der Sie reguläre Ausdrücke anstelle von Dutzenden von REPLACE-Aufrufen verwenden können: http://msdn.Microsoft.com/en-us/magazine/cc163473.aspx

Hier ist ein Wörterbuch, das ich für diesen Fall verwendet habe:

    public static Dictionary<char, string> NonEnglishLetterMapping = new Dictionary<char, string>
    {
          {'a', "áàâãäåāăą"}
        //, {'b', ""}
        , {'c', "ćĉċč"}
        , {'d', "ďđ"}
        , {'e', "éëêèēĕėę"}
        //, {'f', ""}
        , {'g', "ĝğġģ"}
        , {'h', "ĥħ"}
        , {'i', "ìíîïĩīĭįı"}
        , {'j', "ĵ"}
        , {'k', "ķĸ"}
        , {'l', "ĺļľŀł"}
        //, {'m', ""}
        , {'n', "ñńņňʼnŋ"}
        , {'o', "òóôõöōŏőơ"}
        //, {'p', ""}
        //, {'q', ""}
        , {'r', "ŕŗř"}
        , {'s', "śŝşšș"}
        , {'t', "ţťŧț"}
        , {'u', "ùúûüũūŭůűųư"}
        //, {'v', ""}
        , {'w', "ŵ"}
        //, {'x', ""}
        , {'y', "ŷ"}
        , {'z', "źżž"}
    };
2
soslo

Ich weiß, es ist nicht elegant, aber wenn die Sortierung nicht funktioniert und Sie keine Funktionen verwenden können, können Sie diesen verschachtelten Ersatz für die meisten verwendeten Diakritiken verwenden. Ich poste das, damit Sie es nicht noch einmal selbst eingeben müssen :)

select REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(myfield,'é','e'),'ê','e'),'ë','e'),'è','e'),'É','E'),'È','E'),'Ê','E'),'Ë','E'),'ð','D'),'Ð','D'),'â','a'),'à','a'),'á','a'),'ã','a'),'æ','a'),'à','a'),'å','a'),'Å','A'),'À','A'),'Á','A'),'Â','A'),'Ã','A'),'Æ','A'),'ä','a'),'Ä','A'),'ï','i'),'î','i'),'ì','i'),'í','i'),'Ì','I'),'Í','I'),'Î','I'),'Ï','I'),'ô','o'),'ò','o'),'ó','o'),'õ','o'),'ø','o'),'Ò','O'),'Ó','O'),'Ô','O'),'Õ','O'),'Ø','O'),'ö','o'),'Ö','O'),'û','u'),'ù','u'),'ú','u'),'Ù','U'),'Ú','U'),'Û','U'),'Ü','U'),'ü','u'),'ñ','n'),'Ñ','N'),'Ç','C'),'ç','c'),'ý','y'),'ÿ','y'),'Ý','Y'),'þ','T'),'Þ','t'),'ß','ss') from mytable
1
Gilbert

Mit zwei Hilfstabellen in Ihrem Schema können Sie Ihre Daten mit einer SELECT-Anweisung transformieren.

Erklären Sie zuerst eine Ansicht, um eine Zahlentabelle von 1 bis 65536 zu implementieren. Folgende Technik beruht auf Itzik Ben-Gan :

CREATE VIEW Sequence
AS
WITH T1(_) AS (SELECT NULL UNION ALL SELECT NULL),
T2(_) AS (SELECT NULL FROM T1 AS L CROSS JOIN T1 AS R),
T3(_) AS (SELECT NULL FROM T2 AS L CROSS JOIN T2 AS R),
T4(_) AS (SELECT NULL FROM T3 AS L CROSS JOIN T3 AS R),
T5(_) AS (SELECT NULL FROM T4 AS L CROSS JOIN T4 AS R)
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS Number
FROM T5;

Als Nächstes erklären Sie eine Zuordnung zwischen Charakteren mit Diakritik und und ihren undiakritischen Äquivalenten. Diese Beispieldaten sind keine vollständige Abbildung, sondern dienen als Beispiel:

CREATE TABLE UndiacriticMap (
  DiacriticCharacter CHAR(1) NOT NULL PRIMARY KEY,
  UndiacriticCharacter CHAR(1) NOT NULL
);

INSERT INTO UndiacriticMap (
  DiacriticCharacter,
  UndiacriticCharacter
)
VALUES
  ('à', 'a'),
  ('è', 'e'),
  ('é', 'e'),
  ('ì', 'i'),
  ('ò', 'o'),
  ('ç', 'c');

Zum Schluss deklarieren Sie eine Tabelle mit einer Spalte mit Testdaten. Die Daten stammen aus der Frage und aus DForck42s Antwort :

CREATE TABLE TestData (
  ID INT NOT NULL PRIMARY KEY,
  String VARCHAR(50) NOT NULL
);

INSERT INTO TestData (
  ID,
  String
)
VALUES
  (1, 'textàè containing éìòaccentsç''''` and things-'),
  (2, 'aèàç=.32s df');

Wenn diese Objekte vorhanden sind, verarbeitet die folgende SELECT-Anweisung die Testdaten in einer relationalen Weise, außer für den nicht relationalen Hack, um die Zeichen wieder miteinander zu verketten. Die "Blackbox-XML-Methode" beruht auf Anith Sen :

WITH CharacterWise (ID, Symbol, Position) AS (
  SELECT
    ID,
    SUBSTRING(TestData.String, Sequence.Number, 1),
    Sequence.Number
  FROM TestData
  INNER JOIN Sequence ON
    Sequence.Number <= LEN(TestData.String)
),
Stripped (ID, Symbol, Position) AS (
  SELECT
    ID,
    CASE 
      WHEN UndiacriticMap.DiacriticCharacter IS NOT NULL
      THEN UndiacriticMap.UndiacriticCharacter
      ELSE CASE 
        WHEN CharacterWise.Symbol LIKE '[a-z]' COLLATE Latin1_General_BIN
        THEN CharacterWise.Symbol
        ELSE ''
      END
    END,
    CharacterWise.Position
  FROM CharacterWise
  LEFT OUTER JOIN UndiacriticMap ON
    UndiacriticMap.DiacriticCharacter = CharacterWise.Symbol
)
SELECT
  TestData.ID,
  TestData.String,
  (
    SELECT Stripped.Symbol AS [text()]
    FROM Stripped
    WHERE TestData.ID = Stripped.ID
    ORDER BY Stripped.Position
    FOR XML PATH('')
  ) AS StrippedString
FROM TestData;

Die Abfrage erzeugt die folgende Ergebnismenge:

ID          String                                             StrippedString
----------- -------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1           textàè containing éìòaccentsç''` and things-       textaecontainingeioaccentscandthings
2           aèàç=.32s df                                       aeacsdf

Nur zwei Cent von mir

select * From XXX  
    where cast(Word as varchar(max)) collate SQL_Latin1_General_CP1253_CI_AI = 'sluiten' collate SQL_Latin1_General_CP1253_CI_AI
0
Tschallacka

in postgres 10:

create extension unaccent;# as root in Your db, for each db
select unaccent("ąęśłóŻŹŁÓĄĘ");

:)

0
blackmoon