Ganti karakter khusus dalam kolom dengan spasi

10

Saya mencoba menulis kueri yang menggantikan karakter khusus dengan spasi. Kode di bawah ini membantu mengidentifikasi baris. (karakter alfa-numerik, koma, dan spasi valid):

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

Bagaimana saya bisa mengintegrasikan fungsi ganti ke dalam pernyataan pilih sehingga semua karakter selain alfanumerik, koma dan spasi di set hasil diganti oleh '' (spasi). Yang ini tidak akan berfungsi:

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

Jawaban:

11

Jika Anda dijamin hanya akan menggunakan 26 huruf alfabet Inggris AS (baik versi huruf besar maupun kecil), tentu saja, Anda dapat menggunakan LIKEdan / atau PATINDEXdengan notasi rentang sederhana [a-z](Anda tidak akan perlu menggunakan huruf besar "Z" saat menggunakan Collation yang tidak peka huruf besar-kecil).

Tapi, jika Anda bisa mendapatkan karakter yang tidak ditemukan di en-US alfabet belum tersedia dalam berbagai Kode Pages / Collations untuk VARCHARdata (misalnya Þ= ibukota Latin "Thorn" = SELECT CHAR(0xDE)), maka Anda mungkin perlu menyertakan mereka dalam kelas karakter: [a-z0-9, Þ]. Tentu saja, karakter tambahan apa yang akan dibuat berdasarkan per-Kode Halaman.

Perlu diketahui juga bahwa tipe Collation (SQL Server vs Windows) dan pengaturan sensitivitas (case, accent, dll sensitif vs tidak sensitif) akan mempengaruhi karakter mana yang termasuk dalam kisaran tertentu. Sebagai contoh, SQL Server Collations mengurutkan huruf besar dan kecil dalam urutan yang berlawanan sebagai Windows Collations. Artinya, dengan asumsi Collation peka-huruf besar-kecil untuk kedua jenis Collations, satu akan melakukan AaBb...dan yang lain akan melakukannya aAbB.... Efeknya akan berada adalam kisaran A-Zuntuk salah satu dari mereka, tetapi tidak yang lain. Dan rentang dari a-Ztidak akan cocok dengan karakter apa pun dalam Kolasi biner (yang berakhir dengan salah satu _BINatau _BIN2, tetapi tidak menggunakan _BIN) mengingat bahwa nilai A65 danaadalah 97, maka itu adalah kisaran yang tidak valid dari 97 hingga 65 ;-). Ada terlalu banyak variasi untuk memberikan contoh di sini jadi saya akan mencoba memposting penjelasan terperinci di blog saya dalam waktu dekat (dan kemudian akan memperbarui ini dengan tautan ke sana). Namun, jika Anda akan ketat hanya menerima karakter bahasa Inggris AS (bahkan jika Anda mungkin mendapatkan huruf yang valid dari bahasa lain) maka opsi terbaik Anda mungkin akan menggunakan pola dan Kolasi berikut :

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

Sekarang, jika Anda mendukung NVARCHARdata dan bisa mendapatkan "kata" karakter dari berbagai bahasa, maka T-SQL tidak akan banyak membantu karena tidak memiliki cara nyata untuk membedakan hal-hal ini. Dalam hal ini, Anda harus menggunakan Ekspresi Reguler (RegEx) - khususnya Replacemetode / fungsi - dan itu hanya tersedia melalui SQLCLR. Berikut ini menunjukkan contoh mengganti beberapa karakter "khusus", namun meninggalkan semua yang merupakan huruf yang valid dalam setidaknya satu bahasa:

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); 

Pengembalian:

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

Ekspresi RegEx berarti:

  • \W= a RegEx "escape" yang berarti " karakter non- kata"
  • \p{Pc}= "kategori" Unicode dari "Tanda Baca, Konektor" (ini diperlukan untuk pertandingan hanya karena "kategori" ini dikecualikan secara spesifik oleh \Wpelarian)
  • -[,]= pengurangan kelas (ini diperlukan untuk mengecualikan koma dari pencocokan sebagai "spesial" karena mereka termasuk dalam \Wpelarian)

Anda dapat melakukan pembaruan tabel hanya dengan menerbitkan:

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;

Harap perhatikan bahwa untuk contoh-contoh ini, saya menggunakan dua fungsi yang tersedia di pustaka SQL # SQL versi gratis dari fungsi SQLCLR, yang saya buat (tapi sekali lagi, ini gratis). Perhatikan juga bahwa saya menggunakan versi "4k" yang lebih cepat karena menggunakan NVARCHAR(4000)bukan NVARCHAR(MAX)tipe parameter. Jika data Anda menggunakan NVARCHAR(MAX), maka hapus saja "4k" dari nama fungsi.

Silakan juga lihat:

Solomon Rutzky
sumber
5

Saya punya posting di sini yang melakukan hal serupa .

Pada dasarnya saya menggunakan CTE rekursif untuk berulang-ulang menggantikan karakter "buruk" sekaligus. Saya menggunakan STUFF untuk menghapus 1 karakter (walaupun Anda dapat menggunakannya untuk mengganti dengan spasi) dan PATINDEX untuk menemukan lokasi karakter yang ingin saya hapus. Anda dapat memodifikasinya sedikit untuk melakukan apa yang Anda cari. Namun itu membuat daftar "baik", itu tidak benar-benar memperbarui daftar yang ada.

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);

Anda harus dapat memodifikasi bagian bawah untuk melakukan pembaruan daripada hanya permintaan tetapi saya belum benar-benar mencobanya. Saya cukup yakin itu akan terlihat seperti ini:

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

Sejauh skala saya kembali ~ 170k baris dibersihkan dalam waktu kurang dari 30 detik. Sekali lagi tidak yakin tentang melakukan pembaruan tetapi ini di laptop saya yang cukup lambat dengan ram hanya 6GB.

Kenneth Fisher
sumber
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
William Mendoza
sumber