Làm cách nào để loại bỏ tất cả các ký tự không phải là chữ cái khỏi chuỗi trong SQL Server?


Câu trả lời:


362

Hãy thử chức năng này:

Create Function [dbo].[RemoveNonAlphaCharacters](@Temp VarChar(1000))
Returns VarChar(1000)
AS
Begin

    Declare @KeepValues as varchar(50)
    Set @KeepValues = '%[^a-z]%'
    While PatIndex(@KeepValues, @Temp) > 0
        Set @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    Return @Temp
End

Gọi nó như thế này:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Khi bạn hiểu mã, bạn sẽ thấy rằng việc thay đổi nó để loại bỏ các ký tự khác cũng tương đối đơn giản. Bạn thậm chí có thể làm cho điều này đủ năng động để vượt qua trong mẫu tìm kiếm của bạn.

Hy vọng nó giúp.


9
Mã này loại bỏ các ký tự không phải alpha (vì vậy các số cũng bị xóa). Nếu bạn muốn để lại các số (loại bỏ các ký tự số không phải là alpha), thì ... thay ^ az bằng ^ az ^ 0-9 Chuỗi tìm kiếm đó xuất hiện trong mã ở hai vị trí khác nhau. Hãy chắc chắn để thay thế cả hai.
George Mastros

26
Từ nhận xét của Jeff: Tôi nghĩ rằng nếu muốn loại bỏ tất cả các chữ cái và không phải số, bạn sẽ muốn '^ a-z0-9' (so với '^ az ^ 0-9', sẽ để lại ^ trong chuỗi) .
Ngay cả Miên

1
+1 George. Đây là một trong những nơi mà mã "Dựa trên tập hợp" và việc sử dụng Hàm vô hướng nội tuyến gặp khó khăn rất lớn trong việc đánh bại Row-By-Row. Làm rất tốt Tôi cũng đã sử dụng chức năng "Mũ ban đầu" của bạn, có dạng cơ bản tương tự, trong một vài năm nay.
Jeff Moden

6
@Lynchie Thay đổi '% [^ az]%' thành '% [^ az]%' Về cơ bản, chỉ cần đặt một ký tự khoảng trắng sau z.
George Mastros

8
Tên biến KeepValues ​​thực sự trái ngược với những gì nó có nghĩa là làm. KeepValues ​​liệt kê các ký tự cần được loại trừ ..
nee21

167

Phiên bản tham số của G Mastros ' câu trả lời tuyệt vời :

CREATE FUNCTION [dbo].[fn_StripCharacters]
(
    @String NVARCHAR(MAX), 
    @MatchExpression VARCHAR(255)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
    SET @MatchExpression =  '%['+@MatchExpression+']%'

    WHILE PatIndex(@MatchExpression, @String) > 0
        SET @String = Stuff(@String, PatIndex(@MatchExpression, @String), 1, '')

    RETURN @String

END

Chỉ chữ cái:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^a-z')

Chỉ số:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^0-9')

Chỉ chữ và số:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', '^a-z0-9')

Không chữ và số:

SELECT dbo.fn_StripCharacters('a1!s2@d3#f4$', 'a-z0-9')

3
Tôi thích phiên bản này và tạo ra bản phóng tác câu trả lời của G Mastros trước khi cuộn xuống để bỏ phiếu!
Earnshavian

Mẫu regex dường như không hoạt động với tất cả các khoảng trắng. Nếu tôi muốn loại bỏ tất cả các ký tự đặc biệt ngoại trừ các ký tự chữ và số và khoảng trắng tôi muốn sử dụngSELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s') để loại bỏ các khoảng trắng. Tôi cũng đã thử sử dụng [[:blank:]]nhưng điều đó phá vỡ chức năng và không có gì bị xóa khỏi chuỗi. Ive gần nhất nhận được là bằng cách sử dụng: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(mã hóa một khoảng trắng trong mẫu biểu thức chính quy). Tuy nhiên, điều đó không loại bỏ ngắt dòng.
Billy McKee

2
@BillyMcKee Thêm khoảng trắng ở đầu thay vì thêm nó vào cuối biểu thức thông thường. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Mike

8

Dù bạn có tin hay không, trong hệ thống của tôi, chức năng xấu xí này hoạt động tốt hơn so với G Mastros thanh lịch.

CREATE FUNCTION dbo.RemoveSpecialChar (@s VARCHAR(256)) 
RETURNS VARCHAR(256) 
WITH SCHEMABINDING
    BEGIN
        IF @s IS NULL
            RETURN NULL
        DECLARE @s2 VARCHAR(256) = '',
                @l INT = LEN(@s),
                @p INT = 1

        WHILE @p <= @l
            BEGIN
                DECLARE @c INT
                SET @c = ASCII(SUBSTRING(@s, @p, 1))
                IF @c BETWEEN 48 AND 57
                   OR  @c BETWEEN 65 AND 90
                   OR  @c BETWEEN 97 AND 122
                    SET @s2 = @s2 + CHAR(@c)
                SET @p = @p + 1
            END

        IF LEN(@s2) = 0
            RETURN NULL

        RETURN @s2

Còn dấu phẩy, dấu chấm, dấu cách, v.v?
sojim

khác nhau bao nhiêu nếu bạn không sử dụng ASCIIsố nguyên ở đây và so sánh trực tiếp đầu ra của SUBSTRINGmột số ký tự, ví dụ: SET @ch=SUBSTRING(@s, @p, 1)IF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan

Thêm VỚI SCHEMABINDING vào chức năng của mình giống như chức năng của bạn. Bạn đang sử dụng VARCHAR, chức năng của anh ấy là sử dụng NVARCHAR. Nếu các tham số bạn truyền vào hàm của anh ấy là VARCHAR, bạn nên sử dụng VARCHAR thay vì NVARCHAR trong hàm của anh ấy, hệ thống của bạn sẽ cần truyền các giá trị chuỗi từ VARCHAR sang NVARCHAR trước khi nó có thể thực hiện chức năng đắt hơn. Ngay cả với những thay đổi đó, chức năng của bạn vẫn có thể nhanh hơn, nhưng đó là một vài ví dụ tôi có thể thấy chức năng của anh ta có thể hoạt động chậm hơn trong tình huống của bạn.
EricI

1
Chức năng của anh ta cũng đang sử dụng NVARCHAR (MAX) và chức năng của bạn đang sử dụng VARCHAR (256). Nếu 256 là tất cả những gì bạn cần, hãy thay đổi chức năng của anh ấy để sử dụng VARCHAR (256) và chức năng của anh ấy sẽ hoạt động nhanh hơn cho bạn.
EricI

5

Tôi biết rằng SQL rất tệ trong việc thao tác chuỗi, nhưng tôi không nghĩ nó sẽ khó đến thế. Đây là một hàm đơn giản để loại bỏ tất cả các số từ một chuỗi. Sẽ có cách tốt hơn để làm điều này, nhưng đây là một sự khởi đầu.

CREATE FUNCTION dbo.AlphaOnly (
    @String varchar(100)
)
RETURNS varchar(100)
AS BEGIN
  RETURN (
    REPLACE(
      REPLACE(
        REPLACE(
          REPLACE(
            REPLACE(
              REPLACE(
                REPLACE(
                  REPLACE(
                    REPLACE(
                      REPLACE(
                        @String,
                      '9', ''),
                    '8', ''),
                  '7', ''),
                '6', ''),
              '5', ''),
            '4', ''),
          '3', ''),
        '2', ''),
      '1', ''),
    '0', '')
  )
END
GO

-- ==================
DECLARE @t TABLE (
    ColID       int,
    ColString   varchar(50)
)

INSERT INTO @t VALUES (1, 'abc1234567890')

SELECT ColID, ColString, dbo.AlphaOnly(ColString)
FROM @t

Đầu ra

ColID ColString
----- ------------- ---
    1 abc1234567890 abc

Vòng 2 - Danh sách đen hướng dữ liệu

-- ============================================
-- Create a table of blacklist characters
-- ============================================
IF EXISTS (SELECT * FROM sys.tables WHERE [object_id] = OBJECT_ID('dbo.CharacterBlacklist'))
  DROP TABLE dbo.CharacterBlacklist
GO
CREATE TABLE dbo.CharacterBlacklist (
    CharID              int         IDENTITY,
    DisallowedCharacter nchar(1)    NOT NULL
)
GO
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'0')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'1')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'2')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'3')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'4')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'5')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'6')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'7')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'8')
INSERT INTO dbo.CharacterBlacklist (DisallowedCharacter) VALUES (N'9')
GO

-- ====================================
IF EXISTS (SELECT * FROM sys.objects WHERE [object_id] = OBJECT_ID('dbo.StripBlacklistCharacters'))
  DROP FUNCTION dbo.StripBlacklistCharacters
GO
CREATE FUNCTION dbo.StripBlacklistCharacters (
    @String nvarchar(100)
)
RETURNS varchar(100)
AS BEGIN
  DECLARE @blacklistCt  int
  DECLARE @ct           int
  DECLARE @c            nchar(1)

  SELECT @blacklistCt = COUNT(*) FROM dbo.CharacterBlacklist

  SET @ct = 0
  WHILE @ct < @blacklistCt BEGIN
    SET @ct = @ct + 1

    SELECT @String = REPLACE(@String, DisallowedCharacter, N'')
    FROM dbo.CharacterBlacklist
    WHERE CharID = @ct
  END

  RETURN (@String)
END
GO

-- ====================================
DECLARE @s  nvarchar(24)
SET @s = N'abc1234def5678ghi90jkl'

SELECT
    @s                  AS OriginalString,
    dbo.StripBlacklistCharacters(@s)   AS ResultString

Đầu ra

OriginalString           ResultString
------------------------ ------------
abc1234def5678ghi90jkl   abcdefghijkl

Thách thức của tôi với độc giả: Bạn có thể làm điều này hiệu quả hơn? Điều gì về việc sử dụng đệ quy?


bạn có thể có thể viết một dbo tốt hơn .StripBlacklistChar character () không có vòng lặp sử dụng sommarskog.se/arrays-in-sql-2005.html#tblnum bảng số được tham gia vào bảng danh sách đen của bạn, nhưng hôm nay tôi quá lười để thử nó mình ....
KM.

4

Nếu bạn giống như tôi và không có quyền truy cập chỉ thêm các chức năng vào dữ liệu sản xuất của bạn nhưng vẫn muốn thực hiện loại lọc này, thì đây là một giải pháp SQL thuần túy sử dụng bảng PIVOT để đặt các phần được lọc lại với nhau.

NB Tôi đã mã hóa bảng tối đa 40 ký tự, bạn sẽ phải thêm nhiều hơn nếu bạn có chuỗi dài hơn để lọc.

SET CONCAT_NULL_YIELDS_NULL OFF;

with 
    ToBeScrubbed
as (
    select 1 as id, '*SOME 222@ !@* #* BOGUS !@*&! DATA' as ColumnToScrub
),

Scrubbed as (
    select 
        P.Number as ValueOrder,
        isnull ( substring ( t.ColumnToScrub , number , 1 ) , '' ) as ScrubbedValue,
        t.id
    from
        ToBeScrubbed t
        left join master..spt_values P
            on P.number between 1 and len(t.ColumnToScrub)
            and type ='P'
    where
        PatIndex('%[^a-z]%', substring(t.ColumnToScrub,P.number,1) ) = 0
)

SELECT
    id, 
    [1]+ [2]+ [3]+ [4]+ [5]+ [6]+ [7]+ [8] +[9] +[10]
    +  [11]+ [12]+ [13]+ [14]+ [15]+ [16]+ [17]+ [18] +[19] +[20]
    +  [21]+ [22]+ [23]+ [24]+ [25]+ [26]+ [27]+ [28] +[29] +[30]
    +  [31]+ [32]+ [33]+ [34]+ [35]+ [36]+ [37]+ [38] +[39] +[40] as ScrubbedData
FROM (
    select 
        *
    from 
        Scrubbed
    ) 
    src
    PIVOT (
        MAX(ScrubbedValue) FOR ValueOrder IN (
        [1], [2], [3], [4], [5], [6], [7], [8], [9], [10],
        [11], [12], [13], [14], [15], [16], [17], [18], [19], [20],
        [21], [22], [23], [24], [25], [26], [27], [28], [29], [30],
        [31], [32], [33], [34], [35], [36], [37], [38], [39], [40]
        )
    ) pvt

Giải pháp này nhanh hơn 2,3 lần đối với tôi so với việc sử dụng một hàm trên một tập hợp các hàng 235K. Tôi cũng đã phải thay thế 2 lần và sử dụng tổng cộng bốn CTE. Làm việc như một nhà vô địch.
JJS

4

Khi xem xét tất cả các giải pháp đã cho, tôi nghĩ rằng phải có một phương thức SQL thuần túy không yêu cầu hàm hoặc truy vấn CTE / XML và không liên quan đến việc duy trì các câu lệnh REPLACE lồng nhau. Đây là giải pháp của tôi:

SELECT 
  x
  ,CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 1, 1) + '%' THEN '' ELSE SUBSTRING(x, 1, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 2, 1) + '%' THEN '' ELSE SUBSTRING(x, 2, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 3, 1) + '%' THEN '' ELSE SUBSTRING(x, 3, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 4, 1) + '%' THEN '' ELSE SUBSTRING(x, 4, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 5, 1) + '%' THEN '' ELSE SUBSTRING(x, 5, 1) END
    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, 6, 1) + '%' THEN '' ELSE SUBSTRING(x, 6, 1) END
-- Keep adding rows until you reach the column size 
    AS stripped_column
FROM (SELECT 
        column_to_strip AS x
        ,'ABCDEFGHIJKLMNOPQRSTUVWXYZ' AS a 
      FROM my_table) a

Ưu điểm của việc làm theo cách này là các ký tự hợp lệ được chứa trong một chuỗi trong truy vấn phụ giúp dễ dàng cấu hình lại cho một bộ ký tự khác.

Nhược điểm là bạn phải thêm một hàng SQL cho mỗi ký tự theo kích cỡ cột của bạn. Để làm cho nhiệm vụ đó dễ dàng hơn, tôi chỉ sử dụng tập lệnh Powershell bên dưới, ví dụ này nếu cho VARCHAR (64):

1..64 | % {
  "    + CASE WHEN a NOT LIKE '%' + SUBSTRING(x, {0}, 1) + '%' THEN '' ELSE SUBSTRING(x, {0}, 1) END" -f $_
} | clip.exe

3
Lúng túng trong trường hợp chung, nhưng dễ dàng và hữu ích cho truy vấn một lần với một cột hẹp.
Eric J.

3

Đây là một cách khác để loại bỏ các ký tự không phải là chữ cái bằng cách sử dụng một iTVF. Đầu tiên, bạn cần một bộ chia chuỗi dựa trên mẫu. Đây là một bài trích từ bài viết của Dwain Camp :

-- PatternSplitCM will split a string based on a pattern of the form 
-- supported by LIKE and PATINDEX 
-- 
-- Created by: Chris Morris 12-Oct-2012 
CREATE FUNCTION [dbo].[PatternSplitCM]
(
       @List                VARCHAR(8000) = NULL
       ,@Pattern            VARCHAR(50)
) RETURNS TABLE WITH SCHEMABINDING 
AS 

RETURN
    WITH numbers AS (
        SELECT TOP(ISNULL(DATALENGTH(@List), 0))
            n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
        (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
    )

    SELECT
        ItemNumber = ROW_NUMBER() OVER(ORDER BY MIN(n)),
        Item = SUBSTRING(@List,MIN(n),1+MAX(n)-MIN(n)),
        [Matched]
    FROM (
        SELECT n, y.[Matched], Grouper = n - ROW_NUMBER() OVER(ORDER BY y.[Matched],n)
        FROM numbers
        CROSS APPLY (
            SELECT [Matched] = CASE WHEN SUBSTRING(@List,n,1) LIKE @Pattern THEN 1 ELSE 0 END
        ) y
    ) d
    GROUP BY [Matched], Grouper

Bây giờ bạn có bộ chia dựa trên mẫu, bạn cần chia các chuỗi khớp với mẫu:

[a-z]

và sau đó nối chúng lại để có kết quả mong muốn:

SELECT *
FROM tbl t
CROSS APPLY(
    SELECT Item + ''
    FROM dbo.PatternSplitCM(t.str, '[a-z]')
    WHERE Matched = 1
    ORDER BY ItemNumber
    FOR XML PATH('')
) x (a)

MẪU VẬT

Kết quả:

| Id |              str |              a |
|----|------------------|----------------|
|  1 |    testte d'abc |     testtedabc |
|  2 |            anr¤a |           anra |
|  3 |  gs-re-C“te d'ab |     gsreCtedab |
|  4 |         Mfe, DF |          MfeDF |
|  5 |           Rtemd |          Rtemd |
|  6 |          jadji |          jadji |
|  7 |      Cje y ret¢n |       Cjeyretn |
|  8 |        Jklbalu |        Jklbalu |
|  9 |       lene-iokd |       leneiokd |
| 10 |   liode-Pyrnie |    liodePyrnie |
| 11 |         Vs Gta |          VsGta |
| 12 |        Sƒo Paulo |        SoPaulo |
| 13 |  vAstra gAtaland | vAstragAtaland |
| 14 |  ¥uble / Bio-Bio |     ubleBioBio |
| 15 | Upln/ds VAsb-y |    UplndsVAsby |

Có bất kỳ lợi thế để sử dụng này hơn các câu trả lời khác?
S.Serpoo Sơn

2

Giải pháp này, lấy cảm hứng từ giải pháp của ông Allen, yêu cầu một Numbersbảng số nguyên (bạn nên có trong tay nếu bạn muốn thực hiện các hoạt động truy vấn nghiêm túc với hiệu suất tốt). Nó không yêu cầu CTE. Bạn có thể thay đổi NOT IN (...)biểu thức để loại trừ các ký tự cụ thể hoặc thay đổi nó thành biểu thức IN (...)OR LIKEđể chỉ giữ lại một số ký tự nhất định.

SELECT (
    SELECT  SUBSTRING([YourString], N, 1)
    FROM    dbo.Numbers
    WHERE   N > 0 AND N <= CONVERT(INT, LEN([YourString]))
        AND SUBSTRING([YourString], N, 1) NOT IN ('(',')',',','.')
    FOR XML PATH('')
) AS [YourStringTransformed]
FROM ...

Giải pháp thú vị cho một vấn đề không liên quan.
TaterJuice

2

Đây là một giải pháp không yêu cầu tạo chức năng hoặc liệt kê tất cả các trường hợp ký tự để thay thế. Nó sử dụng một câu lệnh VỚI đệ quy kết hợp với một PATINDEX để tìm các ký tự không mong muốn. Nó sẽ thay thế tất cả các ký tự không mong muốn trong một cột - tối đa 100 ký tự xấu duy nhất có trong bất kỳ chuỗi nào. (EG "ABC123DEF234" sẽ chứa 4 ký tự xấu 1, 2, 3 và 4) Giới hạn 100 là số lần thu hồi tối đa được phép trong câu lệnh VỚI, nhưng điều này không áp đặt giới hạn về số lượng hàng cần xử lý, chỉ bị giới hạn bởi bộ nhớ có sẵn.
Nếu bạn không muốn kết quả DISTINCT, bạn có thể xóa hai tùy chọn khỏi mã.

-- Create some test data:
SELECT * INTO #testData 
FROM (VALUES ('ABC DEF,K.l(p)'),('123H,J,234'),('ABCD EFG')) as t(TXT)

-- Actual query:
-- Remove non-alpha chars: '%[^A-Z]%'
-- Remove non-alphanumeric chars: '%[^A-Z0-9]%'
DECLARE @BadCharacterPattern VARCHAR(250) = '%[^A-Z]%';

WITH recurMain as (
    SELECT DISTINCT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM #testData
    UNION ALL
    SELECT CAST(TXT AS VARCHAR(250)) AS TXT, PATINDEX(@BadCharacterPattern, TXT) AS BadCharIndex
    FROM (
        SELECT 
            CASE WHEN BadCharIndex > 0 
                THEN REPLACE(TXT, SUBSTRING(TXT, BadCharIndex, 1), '')
                ELSE TXT 
            END AS TXT
        FROM recurMain
        WHERE BadCharIndex > 0
    ) badCharFinder
)
SELECT DISTINCT TXT
FROM recurMain
WHERE BadCharIndex = 0;

1

Tôi đặt cái này ở cả hai nơi mà Pat Index được gọi.

PatIndex('%[^A-Za-z0-9]%', @Temp)

cho chức năng tùy chỉnh ở trên RemoveNonAlphaChar character và đổi tên thành RemoveNonAlphaNumericChar character


1

--Đầu tiên tạo một chức năng

CREATE FUNCTION [dbo].[GetNumericonly]
(@strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
     DECLARE @intAlpha INT
     SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric)
BEGIN
     WHILE @intAlpha > 0
   BEGIN
          SET @strAlphaNumeric = STUFF(@strAlphaNumeric, @intAlpha, 1, '' )
          SET @intAlpha = PATINDEX('%[^0-9]%', @strAlphaNumeric )
   END
END
RETURN ISNULL(@strAlphaNumeric,0)
END

Bây giờ gọi hàm này như

select [dbo].[GetNumericonly]('Abhi12shek23jaiswal')

Kết quả của nó như

1223

1

Từ góc độ hiệu suất, tôi sẽ sử dụng chức năng Inline:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[udf_RemoveNumericCharsFromString]
(
@List NVARCHAR(4000)
)
RETURNS TABLE 
AS RETURN

    WITH GetNums AS (
       SELECT TOP(ISNULL(DATALENGTH(@List), 0))
        n = ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
        FROM
          (VALUES (0),(0),(0),(0)) d (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f (n),
          (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g (n)
            )

    SELECT StrOut = ''+
        (SELECT Chr
         FROM GetNums
            CROSS APPLY (SELECT SUBSTRING(@List , n,1)) X(Chr)
         WHERE Chr LIKE '%[^0-9]%' 
         ORDER BY N
         FOR XML PATH (''),TYPE).value('.','NVARCHAR(MAX)')


   /*How to Use
   SELECT StrOut FROM dbo.udf_RemoveNumericCharsFromString ('vv45--9gut')
   Result: vv--gut
   */

Tôi biết chủ đề này là cũ nhưng, một chức năng có giá trị bảng nội tuyến là cách để đi. Vấn đề với giải pháp của bạn là, vì bạn chỉ trả về số, mã này :), TYPE) .value ('.', 'NVARCHAR (MAX)') không cần thiết và sẽ làm chậm chức năng xuống ~ 50%
Alan Burstein

1

Đây là một giải pháp CTE đệ quy khác, dựa trên câu trả lời của @Gerhard Weiss tại đây . Bạn sẽ có thể sao chép và dán toàn bộ khối mã vào SSMS và chơi với nó ở đó. Kết quả bao gồm một vài cột bổ sung để giúp chúng tôi hiểu những gì đang diễn ra. Phải mất một thời gian cho đến khi tôi hiểu tất cả những gì đang diễn ra với cả PATINDEX (RegEx) và CTE đệ quy.

DECLARE @DefineBadCharPattern varchar(30)
SET @DefineBadCharPattern = '%[^A-z]%'  --Means anything NOT between A and z characters (according to ascii char value) is "bad"
SET @DefineBadCharPattern = '%[^a-z0-9]%'  --Means anything NOT between a and z characters or numbers 0 through 9 (according to ascii char value) are "bad"
SET @DefineBadCharPattern = '%[^ -~]%'  --Means anything NOT between space and ~ characters (all non-printable characters) is "bad"
--Change @ReplaceBadCharWith to '' to strip "bad" characters from string
--Change to some character if you want to 'see' what's being replaced. NOTE: It must be allowed accoring to @DefineBadCharPattern above
DECLARE @ReplaceBadCharWith varchar(1) = '#'  --Change this to whatever you want to replace non-printable chars with 
IF patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, @ReplaceBadCharWith) > 0
    BEGIN
        RAISERROR('@ReplaceBadCharWith value (%s) must be a character allowed by PATINDEX pattern of %s',16,1,@ReplaceBadCharWith, @DefineBadCharPattern)
        RETURN
    END
--A table of values to play with:
DECLARE @temp TABLE (OriginalString varchar(100))
INSERT @temp SELECT ' 1hello' + char(13) + char(10) + 'there' + char(30) + char(9) + char(13) + char(10)
INSERT @temp SELECT '2hello' + char(30) + 'there' + char(30)
INSERT @temp SELECT ' 3hello there'
INSERT @temp SELECT ' tab' + char(9) + ' character'
INSERT @temp SELECT 'good bye'

--Let the magic begin:
;WITH recurse AS (
    select
    OriginalString,
    OriginalString as CleanString,
    patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString) as [Position],
    substring(OriginalString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString),1) as [InvalidCharacter],
    ascii(substring(OriginalString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN, OriginalString),1)) as [ASCIICode]
    from @temp
   UNION ALL
    select
    OriginalString,
    CONVERT(varchar(100),REPLACE(CleanString,InvalidCharacter,@ReplaceBadCharWith)),
    patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) as [Position],
    substring(CleanString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString),1),
    ascii(substring(CleanString,patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString),1))
    from recurse
    where patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) > 0
)
SELECT * FROM recurse
--optionally comment out this last WHERE clause to see more of what the recursion is doing:
WHERE patindex(@DefineBadCharPattern COLLATE Latin1_General_BIN,CleanString) = 0

0

Sử dụng bảng số được tạo CTE để kiểm tra từng ký tự, sau đó FOR XML để nối với một chuỗi các giá trị được giữ mà bạn có thể ...

CREATE FUNCTION [dbo].[PatRemove](
    @pattern varchar(50),
    @expression varchar(8000) 
    )
RETURNS varchar(8000)
AS
BEGIN
    WITH 
        d(d) AS (SELECT d FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) digits(d)),
        nums(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM d d1, d d2, d d3, d d4),
        chars(c) AS (SELECT SUBSTRING(@expression, n, 1) FROM nums WHERE n <= LEN(@expression))
    SELECT 
        @expression = (SELECT c AS [text()] FROM chars WHERE c NOT LIKE @pattern FOR XML PATH(''));

    RETURN @expression;
END

0
DECLARE @vchVAlue NVARCHAR(255) = 'SWP, Lettering Position 1: 4 Ω, 2: 8 Ω, 3: 16 Ω, 4:  , 5:  , 6:  , Voltage Selector, Solder, 6, Step switch, : w/o fuseholder '


WHILE PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))) > 0
  BEGIN
    SELECT @vchVAlue = STUFF(@vchVAlue,PATINDEX('%?%' , CAST(@vchVAlue AS VARCHAR(255))),1,' ')
  END 

SELECT @vchVAlue

0

cách này không hiệu quả với tôi vì tôi đã cố giữ các chữ cái Ả Rập mà tôi đã cố thay thế biểu thức thông thường nhưng nó cũng không hoạt động. tôi đã viết một phương pháp khác để làm việc ở cấp độ ASCII vì đó là lựa chọn duy nhất của tôi và nó đã hoạt động.

 Create function [dbo].[RemoveNonAlphaCharacters] (@s varchar(4000)) returns varchar(4000)
   with schemabinding
begin
   if @s is null
      return null
   declare @s2 varchar(4000)
   set @s2 = ''
   declare @l int
   set @l = len(@s)
   declare @p int
   set @p = 1
   while @p <= @l begin
      declare @c int
      set @c = ascii(substring(@s, @p, 1))
      if @c between 48 and 57 or @c between 65 and 90 or @c between 97 and 122 or @c between 165 and 253 or @c between 32 and 33
         set @s2 = @s2 + char(@c)
      set @p = @p + 1
      end
   if len(@s2) = 0
      return null
   return @s2
   end

ĐI


-1

Mặc dù bài viết hơi cũ, tôi muốn nói như sau. Vấn đề tôi gặp phải với giải pháp trên là nó không lọc được các ký tự như ç, ë, ï, v.v.

create FUNCTION dbo.udf_Cleanchars (@InputString varchar(80)) 
RETURNS varchar(80) 
AS 

BEGIN 
declare @return varchar(80) , @length int , @counter int , @cur_char char(1) 
SET @return = '' 
SET @length = 0 
SET @counter = 1 
SET @length = LEN(@InputString) 
IF @length > 0 
BEGIN WHILE @counter <= @length 

BEGIN SET @cur_char = SUBSTRING(@InputString, @counter, 1) IF ((ascii(@cur_char) in (32,44,46)) or (ascii(@cur_char) between 48 and 57) or (ascii(@cur_char) between 65 and 90) or (ascii(@cur_char) between 97 and 122))
BEGIN SET @return = @return + @cur_char END 
SET @counter = @counter + 1 
END END 

RETURN @return END

Cảm ơn bạn vì điều này, Eric. Như bạn nói, bài trả lời được đánh dấu là rất tốt, nhưng nó không loại bỏ các ký tự "số" ngớ ngẩn như.
troy

-3

Tôi chỉ tìm thấy cái này tích hợp vào Oracle 10g nếu đó là những gì bạn đang sử dụng. Tôi đã phải loại bỏ tất cả các ký tự đặc biệt để so sánh số điện thoại.

regexp_replace(c.phone, '[^0-9]', '')

5
"Máy chủ SQL" đề cập cụ thể đến sản phẩm của Microsoft.
không ai vào
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.