Alfabetik olmayan tüm karakterleri SQL Server'daki dizeden nasıl şeritleyebilirim?


Yanıtlar:


362

Bu işlevi deneyin:

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

Buna şöyle deyin:

Select dbo.RemoveNonAlphaCharacters('abc1234def5678ghi90jkl')

Kodu anladıktan sonra, diğer karakterleri de kaldırmak için değiştirmenin nispeten basit olduğunu görmelisiniz. Hatta bunu arama düzeninize geçecek kadar dinamik hale getirebilirsiniz.

Umarım yardımcı olur.


9
Bu kod alfa olmayan karakterleri kaldırır (böylece sayılar da kaldırılır). Sayıları bırakmak istiyorsanız (alfa olmayan sayısal karakterleri kaldırın), ... ^ az yerine ^ az ^ 0-9 yazın Bu arama dizesi kodda iki farklı yerde görüntülenir. Her ikisini de değiştirdiğinizden emin olun.
George Mastros

26
Jeff'in yorumundan: Tüm harf olmayan ve sayı olmayanları çıkarmak isteseydiniz, '^ a-z0-9' ('^ az ^ 0-9' yerine 'dizede ^ bırakacaksınız') .
Hatta Mien

1
+1 George. Burası "Set Tabanlı" kodun ve Satır İçi Skaler Fonksiyonların kullanımının Satır Sıraya yenilmesinde büyük zorluk yaşadığı yerlerden biridir. Güzel yapılmış. Ben de birkaç yıldır aynı temel forma sahip "İlk Caps" işlevini kullanıyorum.
Jeff Moden

6
@Lynchie '% [^ az]%' değerini '% [^ az]%' olarak değiştirin. Temelde, z'den sonra bir boşluk karakteri koymanız yeterlidir.
George Mastros

8
Değişken adı KeepValues ​​aslında yapması gerekenin tam tersidir. KeepValues ​​hariç tutulması gereken karakterleri listeler ..
nee21

167

Parametreleştirilmiş versiyonu G Mastros ' müthiş cevap :

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

Yalnızca alfabetik:

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

Yalnızca sayısal:

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

Yalnızca alfasayısal:

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

Sigara alfanümerik:

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

3
Bu sürümü tercih ettim ve oy vermek için aşağı kaydırmadan önce G Mastros'un cevabını uyarladım!
earnshavian

Normal ifade kalıbı tüm boşluklarla çalışmıyor gibi görünüyor. Alfasayısal karakterler ve boşluk hariç tüm özel karakterleri çıkarmak istersem, SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9\s')hangisinin boşluk bıraktığını düşünürdüm . Ben de kullanmaya çalıştım [[:blank:]]ama bu işlevi bozar ve hiçbir şey dizeden kaldırılır. Elde ettiğim en yakın şey: SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^a-z0-9 ')(normal ifade düzeninde bir boşluğu kodlamak). Ancak bu satır sonlarını kaldırmaz.
Billy McKee

2
@BillyMcKee Boşluğu, normal ifadenin sonuna eklemek yerine başında ekleyin. SELECT dbo.fn_StripCharacters('a1!s2 spaces @d3# f4$', '^ a-z0-9')
Miguel

8

İster inanın ister inanmayın, sistemimde bu çirkin işlev G Mastros zarif işlevinden daha iyi performans gösterir.

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

ortak virgül, nokta, boşluk vb.
sojim

ASCIIburada tamsayı kullanmazsanız ve çıktısını doğrudan SUBSTRINGbazı karakterlerle karşılaştırırsanız ne kadar farklıdır , örneğin: SET @ch=SUBSTRING(@s, @p, 1)andIF @ch BETWEEN '0' AND '9' OR @ch BETWEEN 'a' AND 'z' OR @ch BETWEEN 'A' AND 'Z' ...
S.Serpooshan

Fonksiyonunuzda olduğu gibi onun işlevine SCHEMABINDING İLE ekleyin. VARCHAR kullanıyorsunuz, işlevi NVARCHAR kullanıyor. İşlevine ilettiğiniz parametreler VARCHAR ise, işlevi içinde NVARCHAR yerine VARCHAR kullanmalısınız, aksi takdirde sisteminizin dize değerlerini daha pahalı olan işlevi gerçekleştirebilmesi için VARCHAR'dan NVARCHAR'a aktarması gerekir. Bu değişikliklerle bile işleviniz hala daha hızlı olabilir, ancak bunlar, durumunuzda işlevinin sizin için nerede daha yavaş performans gösterebileceğini görebildiğim birkaç örnek.
EricI

1
Onun işlevi de NVARCHAR (MAX) ve işleviniz VARCHAR (256) kullanıyor. Eğer 256 ihtiyacınız varsa, VARCHAR'ı (256) kullanmak için işlevini değiştirin ve işlevi sizin için daha hızlı çalışacaktır.
EricI

5

SQL'in dize manipülasyonunda kötü olduğunu biliyordum, ama bunun zor olacağını düşünmemiştim. İşte bir dizeden tüm sayıları çıkarmak için basit bir işlev. Bunu yapmanın daha iyi yolları olurdu, ama bu bir başlangıç.

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

Çıktı

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

2. Tur - Veriye Dayalı Kara Liste

-- ============================================
-- 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

Çıktı

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

Okuyuculara meydan okumam: Bunu daha verimli hale getirebilir misiniz? Özyineleme kullanmaya ne dersiniz?


muhtemelen sommarskog.se/arrays-in-sql-2005.html#tblnum sayı tablosunu kullanarak bir döngü olmadan daha iyi bir dbo.StripBlacklistCharacters () yazabilirsiniz , ancak bugün bunu kara liste tablonuza katıldı. kendim ....
KM.

4

Benim gibiyseniz ve sadece üretim verilerinize işlev eklemek için erişiminiz yoksa, ancak yine de bu tür bir filtreleme yapmak istiyorsanız, işte filtre uygulanmış parçaları tekrar bir araya getirmek için bir PIVOT tablosu kullanan saf bir SQL çözümü.

Not: Tabloya 40 karaktere kadar kod yazdım, filtrelenecek daha uzun dizeleriniz varsa daha fazlasını eklemeniz gerekecek.

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

Bu çözüm benim için 235K satırlık bir sette bir fonksiyon kullanmaktan 2.3 kat daha hızlıydı. Ayrıca 2x değiştirme yapmak zorunda kaldım ve toplamda dört CTE kullandım. Bir şampiyon gibi çalıştı.
JJS

4

Verilen tüm çözümlere baktığımda, bir işlev veya CTE / XML sorgusu gerektirmeyen ve iç içe yerleştirilmiş REPLACE ifadelerinin bakımı zor olmayan saf bir SQL yöntemi olması gerektiğini düşündüm. İşte benim çözümüm:

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

Bunu yapmanın avantajı, geçerli karakterlerin alt sorgudaki bir dizede yer alması ve farklı karakter kümeleri için yeniden yapılandırmayı kolaylaştırmasıdır.

Dezavantajı, sütununuzun boyutuna kadar her karakter için bir SQL satırı eklemeniz gerektiğidir. Bu görevi kolaylaştırmak için aşağıdaki Powershell betiğini kullandım, bu örnek bir VARCHAR (64) için ise:

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

3
Genel durumda gariptir, ancak dar bir sütuna sahip bir kerelik sorgu için kolay ve kullanışlıdır.
Eric J.

3

Burada, alfabetik olmayan karakterleri bir iTVF. İlk olarak, desen tabanlı bir dize ayırıcıya ihtiyacınız var. İşte Dwain Camp'in makalesinden :

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

Artık desen tabanlı bir ayırıcıya sahip olduğunuza göre, desenle eşleşen dizeleri ayırmanız gerekir:

[a-z]

ve sonra istediğiniz sonucu elde etmek için bunları birleştirin:

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)

ÖRNEKLEM

Sonuç:

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

bunu diğer cevaplara göre kullanmanın bir avantajı var mı?
S.Serpooshan

2

Bay Allen'ın çözümünden esinlenen bu çözüm, bir Numberstamsayı tablosu gerektirir (iyi performansla ciddi sorgu işlemleri yapmak istiyorsanız elinizde olması gerekir). CTE gerektirmez. NOT IN (...)Belirli karakterleri hariç tutmak için ifadeyi değiştirebilir veya yalnızca belirli karakterleri korumak için ifadeyi IN (...)OR LIKEifadesiyle değiştirebilirsiniz.

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 ...

İlgisiz bir konuya ilginç bir çözüm.
TaterJuice

2

İşte bir işlev oluşturmayı veya değiştirilecek tüm karakter örneklerini listelemeyi gerektirmeyen bir çözüm. İstenmeyen karakterleri bulmak için PATINDEX ile birlikte özyinelemeli WITH deyimi kullanır. Bir sütundaki tüm istenmeyen karakterlerin yerini alacaktır - herhangi bir dizede yer alan 100 benzersiz hatalı karakter. (EG "ABC123DEF234" 4 kötü karakter 1, 2, 3 ve 4 içerecektir) 100 sınırı, WITH deyiminde izin verilen maksimum yineleme sayısıdır, ancak bu, işlenecek satır sayısı için bir sınır oluşturmaz. yalnızca kullanılabilir bellekle sınırlıdır.
DISTINCT sonuçlarını istemiyorsanız, iki seçeneği koddan kaldırabilirsiniz.

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

Bunu PatIndex'in çağrıldığı her iki yere de koydum.

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

yukarıdaki özel işlev için RemoveNonAlphaCharacters ve yeniden adlandırıldı RemoveNonAlphaNumericCharacters


1

--İlk olarak bir işlev oluşturun

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

Şimdi bu işlevi şöyle adlandırın:

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

Sonuç şöyle

1223

1

Performans açısından Inline İşlevini kullanırdım:

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
   */

Bu iş parçacığının eski olduğunu biliyorum, ancak bir satır içi tablo değerli işlevi gitmek için bir yoldur. Çözümünüzle ilgili sorun, yalnızca sayı döndürüyorsanız, bu kod:), TYPE) .value ('.', 'NVARCHAR (MAX)') gerekli değildir ve işlevi ~% 50 oranında yavaşlatır
Alan Burstein

1

İşte @Gerhard Weiss'ın Yanıta göre başka özyinelemeli CTE çözümü var burada . Tüm kod bloğunu kopyalayıp SSMS'ye yapıştırabilmeli ve orada oynayabilirsiniz. Sonuçlar, neler olduğunu anlamamıza yardımcı olacak birkaç sütun daha içeriyor. Hem PATINDEX (RegEx) hem de özyinelemeli CTE ile olan her şeyi anlayana kadar biraz zaman aldı.

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

Her karakteri incelemek için CTE tarafından oluşturulan sayılar tablosunu kullanarak, daha sonra FOR XML için tutulan değerlerin bir dizisine katılabilir ...

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

Bu şekilde benim için işe yaramadı, çünkü normal ifadeyi değiştirmeye çalıştığım Arap harflerini tutmaya çalıştım ama aynı zamanda işe yaramadı. ASCII düzeyinde çalışmak için başka bir yöntem yazdım, çünkü bu benim tek tercihimdi ve işe yaradı.

 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

GİT


-1

Yazı biraz eski olmasına rağmen, aşağıdakileri söylemek istiyorum. Yukarıdaki çözüm ile vardı sorun ç, ë, ï, vb gibi karakterleri filtrelemek değil. Ben aşağıdaki gibi bir işlevi adapte (bellek tasarrufu için sadece 80 varchar dize kullandım):

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

Bunun için teşekkürler Eric. Dediğiniz gibi, yazı işaretli cevap çok iyi, ama ½ gibi aptal "sayısal" karakterleri şerit değil.
Troy

-3

Eğer kullandığınız buysa, Oracle 10g'de yerleşik olarak buldum. Bir telefon numarası karşılaştırması için tüm özel karakterleri çıkarmak zorunda kaldım.

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

5
"SQL Server" özellikle Microsoft'un ürününü ifade eder.
kimse
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.