web-dev-qa-db-ja.com

[0-9]は数字用で、[a-z]は文字用なので、句読点に相当するT-SQLはありますか?

句読点を含む列から値をプルできる[0-9]および[a-z]パターンに相当するT-SQLはありますか?

例えば:

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

これは、最初の3文字が0から9までの数字で、最後の文字がaからzまでの文字になる値を返すため、123a456bなどを返しますが、aは返しません。 12ABCの値。

[0-9]は数字を表し、[a-z]は文字を表すので、AB!23およびC?D789を返すので、句読点に相当するものがあるかどうかを知りたいです。

正規表現を使用できる場合、^[a-zA-Z0-9]*$という表現を使用して、文字列内の英数字に一致させることができます。

Where       Value like '^[a-zA-Z0-9]*$'

これに相当するSQLはありますか?

RegExで実行できるこのようなことは知っていますが、T-SQLでそれが必要です。このサーバーにカスタムアセンブリを読み込むことができないため、正規表現を使用できません。

実際の列はvarchar(200)です。照合順序は、Latin1_General_CI_ASです。 SQL Server 2012 Standard Editionを使用しています。

8
pix1985

正確なソリューションに到達する際の最大の困難は、どの文字を含める(または除外するか、どちらの方向が操作にとって意味があるか)を正確に定義することです。意味:

  • VARCHAR/ASCII dataまたはNVARCHAR/Unicode data?について話しているのですか?ASCII dataの句読文字のリスト照合に依存するコードページに依存します(この質問では、ASCII data)を扱っています)。
  • 大文字と小文字を区別する検索または大文字と小文字を区別しない検索を扱っていますか?
  • 列にはどの照合順序が設定されていますか?照合は、コードページと大文字と小文字の区別の両方を教えてくれます。 (この質問ではLatin1_General_CI_ASを扱っています)
  • 「句読点」という用語は、標準の句読文字(.,;:など)だけを意味するのか、それとも非英数字を意味するのか?
  • 空白文字は含まれていますか?
  • 制御文字は含まれていますか?
  • ¢£¥などの通貨記号はどうですか?
  • ©などの記号はどうですか?
  • 「アルファ」と見なされる文字は何ですか? ÂÉÑßÞなどの英語以外の文字が含まれていますか?
  • この質問は英国のキーボードを扱っているため(この質問については ディスカッション を参照)、Æ/æ文字はどうですか?

予想される動作をわかりやすくするために、次のクエリは、Latin1文字セットのすべての256文字(つまり、コードページ1252)と、@ Shaneisの2つのバリエーション 提案されたソリューション がどのように動作するかを示します。最初のフィールド(Latin1_General_CI_ASとラベルが付いている)は、@ Shaneisが提案したLIKE句を示し(執筆時点)、2番目のフィールド(Latin1_General_100_BIN2とラベルが付いている)は、照合順序をオーバーライドして、バイナリ照合順序を指定します(つまり、末尾が_BIN2である照合順序。_BIN照合順序は廃止されているため、_BIN2バージョンへのアクセス権がある場合は使用しないでください)。現在の照合順序では大文字と小文字が区別されないため、大文字を除外するためにA-Zの範囲を追加する必要もありました。

;WITH nums AS
(
  SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
  FROM   [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
       CHAR(nm.[Decimal]) AS [Character],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
               THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
               THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM   nums nm;

[〜#〜]更新[〜#〜]

[〜#〜] if [〜#〜]「句読点」(「通貨記号」ではなく)として分類されている文字を本当に探している、「数学記号」など)、および[〜#〜] if [〜#〜]SQLCLRの使用/カスタムアセンブリのロード(SQLCLRは、 SQL Server 2005では、(Azure SQL Database V12がSAFEアセンブリをサポートしているため、特に)これを許可しない良い理由にまだ遭遇していないため、次のことができます。正規表現を使用しますが、ほとんどの人が推測する理由ではありません。

正規表現を使用してより機能的な文字範囲を構築するのではなく、\w(「Word」文字を意味する)などを使用するのではなく、フィルタリングする文字のUnicodeカテゴリを指定できます。いくつかの定義されたカテゴリがあります:

https://www.regular-expressions.info/unicode.html#category

「InBengali」、「InDingbats」、「InOptical_Character_Recognition」など、フィルタリングするUnicodeブロックを指定することもできます。

https://www.regular-expressions.info/unicode.html#block

SQL Server用のRegEx関数を作成する例は多数ありますが(ほとんどの例はSQLCLRのベストプラクティスに従っていません)、無料の SQL# ライブラリ(私が作成したもの)をダウンロードできます。次のようにスカラーRegEx_IsMatch関数を使用します。

SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)

\p{P}式は、\p = Unicodeカテゴリ、および{P} =すべての句読点を意味します(「コネクタ句読点」などの特定の種類の句読点とは対照的)。また、「句読点」カテゴリには、すべての言語の句読点がすべて含まれています。 Unicode.orgサイトの完全なリストは、次のリンクから参照できます(現在、そのカテゴリには717のコードポイントがあります)。

http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D

上記のテストクエリの更新バージョン。\p{P}を使用したSQL#.RegEx_IsMatchを使用する別のフィールドと、3つすべての結果が含まれます。コードページ1252の256文字すべて(つまり、Latin1_General)のテストは、Pastebin.comの次の場所に投稿されています。

文字のタイプをフィルタリングするためのT-SQLクエリと結果


[〜#〜]更新[〜#〜]
関連するディスカッションで以下が言及されました:

アクセント記号付きの文字について良い点を説明しました。世界中のホテル名で、名前にアクセント記号付きの文字が含まれています。私の問題では、これらを有効なアルファ文字として分類したいと思います。

この場合:

  1. Latin1文字セット/コードページに含まれる英語以外の11文字があり、a-zの範囲と一致しません。それらはð Ð Þ þ œ Œ š Š ž Ž Ÿです。これらはワイルドカードに追加する必要があります。現時点では必要ありませんが、A-Zを追加してもパターンは大文字と小文字を区別する照合で同じように機能します。最終結果は次のとおりです。
    LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'

  2. このデータに「世界中のホテル名」が含まれる可能性があることを考慮して、保存できるように、列のデータ型をNVARCHARに変更することを強くお勧めしますすべての言語のすべての文字。これをVARCHARとして維持すると、ラテン語ベースの言語しか表現できず、ラテン語に関連する追加の文字を提供する6つの補足的なUnicodeカテゴリを完全に表すことができないため、最終的にデータ損失のリスクが非常に高くなります。

12
Solomon Rutzky

私はこれを少し単純化しすぎているかもしれませんが、英数字の値が削除されたときに句読点が残っていると言う場合、次は非英数字を含む文字列を検索します。

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

-- Original
Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

-- Non Alpha-numeric
SELECT * FROM #Test WHERE Value LIKE '%[^a-z0-9]%';

DROP TABLE #Test;
5
Shaneis