Bir sütundaki özel karakterleri boşlukla değiştirme


10

Özel karakterler ile yer değiştiren bir sorgu yazmaya çalışıyorum. Aşağıdaki kod satırları tanımlamaya yardımcı olur. (alfa-sayısal karakterler, virgül ve boşluk geçerlidir):

SELECT columnA
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

Sonuç kümesindeki alfasayısal, virgül ve boşluk dışındaki tüm karakterlerin '' (boşluk) ile değiştirilmeleri için replace işlevini select deyimine nasıl entegre edebilirim. Bu işe yaramaz:

SELECT replace(columnA,'%[^a-Z0-9, ]%',' ')
FROM tableA
WHERE columnA like '%[^a-Z0-9, ]%'

Yanıtlar:


11

ABD İngilizcesi alfabesinin 26 harfini (hem büyük hem de küçük harf versiyonları) kullanmanız garanti edilirse, emin olun LIKEve / veya PATINDEXbasit aralık gösterimi ile [a-z]( büyük / küçük harfe duyarlı olmayan bir Harmanlama kullanırken büyük harf "Z" kullanmanız gerekir).

Eğer tr bulunmayan karakterler alabilirsiniz Ama eğer, çeşitli kod Sayfaları / Harmanlamalar henüz mevcut alfabe VARCHARveri (örn Þ= Latince sermaye "Thorn" = SELECT CHAR(0xDE)), o zaman karakter sınıfında olanlar dahil etmek gerekebilir: [a-z0-9, Þ]. Elbette, bu ekstra karakterlerin ne olacağı Kod Başına Sayfa bazındadır.

Ayrıca, hem Harmanlama türünün (SQL Server vs Windows) hem de duyarlılık ayarlarının (büyük / küçük harf duyarlı, duyarlı olmayan ve hassas olmayan) belirli bir aralıkta hangi karakterlerin dahil edileceğini etkileyeceğini unutmayın. Örneğin, SQL Server Harmanlamaları, büyük ve küçük harfleri Windows Harmanlamalarının tersi sırada sıralar. Yani, her iki Harmanlama türü için büyük / küçük harfe duyarlı bir Harmanlama varsayarak biri yapar AaBb..., diğeri yapar aAbB.... Etkisi olduğunu olacak aaralığında olacak A-Zbunlardan diğeri, ancak diğer değil. Ve değeri , 65 değerinin 65 ve üzeri olması a-Zkoşuluyla, bir ikili Harmanlamadaki herhangi bir karakterle eşleşmez (bunlardan biriyle biten _BINveya _BIN2kullanmayın _BIN).Aa97 olduğu için 97 ile 65 ;-) arasında geçersiz bir aralıktır. Burada örnek vermek için çok fazla varyasyon var, bu yüzden yakında blogumda ayrıntılı bir açıklama yayınlamaya çalışacağım (ve daha sonra bunu bağlantıyla güncelleyeceğim). Bununla birlikte, yalnızca ABD İngilizcesi karakterlerini kabul etme konusunda katılacaksanız (diğer dillerden geçerli mektuplar alsanız bile), en iyi seçeneğiniz muhtemelen aşağıdaki deseni ve Harmanlamayı kullanmak olacaktır :

LIKE '%[^A-Za-z0-9, ]%' COLLATE Latin1_General_100_BIN2

Şimdi, NVARCHARverileri destekliyorsanız ve çeşitli dillerden "kelime" karakterleri alabiliyorsanız, T-SQL bu şeyleri ayırt etmenin gerçek bir yolu olmadığından çok yardımcı olmayacaktır. Bu durumda, Düzenli İfade (RegEx) - özellikle Replaceyöntem / işlev - kullanmalısınız ve bunlar yalnızca SQLCLR aracılığıyla kullanılabilir. Aşağıda, birkaç "özel" karakterin değiştirilmesine, ancak geçerli harfler olan tüm karakterlerin en az bir dilde bırakılmasına ilişkin bir örnek gösterilmektedir:

DECLARE @Test NVARCHAR(500);
SET @Test = N'this$is%a<>TEST,;to}⌡↕strip╞╟╚══¶out_ç_ƒ▀ special-ij-೫-chars-舛-დ-א-B';
SELECT SQL#.RegEx_Replace4k(@Test, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL); 

İadeler:

this is a  TEST, to   strip      out ç ƒ  special ij ೫ chars 舛 დ א B

RegEx ifadesi şu anlama gelir:

  • \W= "herhangi bir kelime olmayan karakter" anlamına gelen bir RegEx "kaçış "
  • \p{Pc}= "Noktalama, Bağlayıcı" bir Unicode "kategorisi" (bu yalnızca "kategori" \Wkaçış tarafından hariç tutulduğu için eşleşme için gereklidir )
  • -[,]= sınıf çıkarma (virgüllerin çıkışa dahil oldukları için virgüllerin "özel" olarak eşlenmesini önlemek için bu gereklidir \W)

Bir tabloyu güncelleyerek aşağıdakileri yapabilirsiniz:

UPDATE tbl
SET    tbl.field = SQL#.RegEx_Replace4k(tbl.field, N'[\W\p{Pc}-[,]]', N' ', -1, 1, NULL)
FROM   tbl
WHERE  SQL#.RegEx_IsMatch4k(tbl.field, N'[\W\p{Pc}-[,]]', 1, NULL) = 1;

Bu örnekler için, oluşturduğum SQLCLR işlevlerinin Ücretsiz sürüm SQL # kitaplığında iki işlev kullandığımı unutmayın (ancak yine bunlar ücretsizdir). Ayrıca parametre türleri NVARCHAR(4000)yerine kullanımı nedeniyle daha hızlı "4k" sürümleri kullandığımı unutmayın NVARCHAR(MAX). Verileriniz kullanılıyorsa NVARCHAR(MAX)işlev adlarından "4k" yi kaldırın.

Lütfen ayrıca bakınız:


5

Burada benzer bir şey yapan bir yazı var .

Temelde tekrar tekrar döngü bir seferde bir "kötü" karakteri yerine tekrar tekrar gitmek için kullanıyorum. (Bir boşluk ile değiştirmek için kullanabilirsiniz) ve kaldırmak istediğiniz karakterin yerini bulmak için PATINDEX 1 karakter şerit STUFF kullanıyorum. Aradığınızı yapmak için biraz değiştirebilirsiniz. Ancak "iyi" bir liste oluşturur, mevcut listeyi güncellemez.

DECLARE @Pattern varchar(50) = '%[^A-Za-z0-9, ]%';

WITH FixBadChars AS (SELECT StringToFix, StringToFix AS FixedString, 1 AS MyCounter, Id
                FROM BadStringList
                UNION ALL
                SELECT StringToFix, Stuff(FixedString, PatIndex(@Pattern, 
                    FixedString COLLATE Latin1_General_BIN2), 1, ' ') AS FixedString, 
                    MyCounter + 1, Id
                FROM FixBadChars
                WHERE FixedString COLLATE Latin1_General_BIN2 LIKE @Pattern)
SELECT StringToFix, FixedString, MyCounter, Id
FROM FixBadChars
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

Sadece bir sorgu yerine güncelleme yapmak için alt kısmı değiştirebilmelisiniz, ama aslında denemedim. Bunun gibi bir şey olacağını oldukça eminim:

UPDATE FixBadChars
SET StringToFix = FixedString
WHERE MyCounter = 
        (SELECT MAX(MyCounter) 
        FROM FixBadChars Fixed
        WHERE Fixed.Id = FixBadChars.Id)
OPTION (MAXRECURSION 1000);

Ölçeklenebilirlik kadar 30 saniyenin altında ~ 170 bin temizlenmiş satır döndü. Yine bir güncelleme yapmak hakkında emin değilim ama bu sadece 6GB ram ile oldukça yavaş benim laptop oldu.


0
Declare @String nchar(2000)='hg$%^AB,.:23ab-=+'

Declare @NewString VARCHAR(2000)=''
Declare @Lenght int=LEN(@String)
Declare @Index int=1

WHILE (@Index <= @Lenght)
BEGIN
    Declare @Letter nchar(1)=Substring(@String,@Index,1);
    Declare @ASCII int=ASCII(@Letter);
    If((@ASCII >= 48 and @ASCII <= 57) or (@ASCII >= 97 and @ASCII <= 122) or (@ASCII >= 65 and @ASCII <= 90))
    BEGIN
        SET @NewString += @Letter
    END
    ELSE
    BEGIN
        SET @NewString += ' '
    END
    SET @Index+=1

END
Select @NewString
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.