正確なソリューションに到達する際の最大の困難は、どの文字を含める(または除外するか、どちらの方向が操作に意味があるか)を正確に定義することです。意味:
- 私たちは話している
VARCHAR
/ ASCIIデータまたはNVARCHAR
/ Unicodeデータ?ASCIIデータの句読文字のリストは、照合に依存するコードページに依存します。(この質問では、ASCIIデータを扱っています)。
- 大文字と小文字を区別する検索または大文字と小文字を区別しない検索を扱っていますか?
- 列にはどの照合順序が設定されていますか?照合は、コードページと大文字と小文字の区別の両方を教えてくれます。(この質問では私たちが扱っています
Latin1_General_CI_AS
)
- ただ、標準の句読点文字を意味する用語「句読点」(例えばある
.
、,
、;
、:
、など)か、英数字以外の文字を意味するのでしょうか?
- 空白文字は含まれていますか?
- 制御文字は含まれていますか?
- どのような通貨記号について
¢
、£
、¥
、など?
©
およびなどの記号はどう™
ですか?
- 「アルファ」と見なされる文字は何ですか?など、英語以外の文字がある
Â
、É
、Ñ
、ß
、Þ
付属?
- この質問は英国のキーボードを扱っているため(この質問の説明を参照)、
Æ
/ æ
文字はどうですか?
予想される動作をわかりやすくするために、次のクエリでは、Latin1文字セットのすべての256文字(つまりコードページ1252)と、@ Shaneisが提案するソリューションの2つのバリエーションがどのように動作するかを示します。最初のフィールド(ラベルはLatin1_General_CI_AS
)はLIKE
@Shaneisが提案した句(この記事の執筆時点Latin1_General_100_BIN2
)を示し、2番目のフィールド(ラベルは)は、照合をオーバーライドしてバイナリ1を指定する変更を示します(つまり、末尾が_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 1は、真に「句読点」(とない「通貨記号」、「数学記号」など)に分類されている文字を見つけるために求めている、とのIF 1は、カスタムのロード/ SQLCLRを使用してから禁止されていませんアセンブリ(SQLCLRはSQL Server 2005で導入されましたが、特にAzure SQL Database V12がアセンブリをサポートしているため、これを許可しない正当な理由はまだありませんSAFE
)なら、正規表現を使用できますが、ほとんどの人はそうではありません。推測します。
正規表現を使用してより機能的な文字範囲を構築するのではなく、または\w
(「単語」文字を意味する)などを使用するのではなく、フィルタリングする文字の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
上記のテストクエリの更新されたバージョン(SQL#.RegEx_IsMatchを\p{P}
で使用する別のフィールドを含む)、およびコードページ1252のすべての256文字にわたるすべての3つのテストの結果(Latin1_General)が、PasteBin.comの次の場所に投稿されています。
文字のタイプをフィルタリングするためのT-SQLクエリと結果
更新
以下は関連する議論で言及されました:
アクセント記号付きの文字について良い点を説明しました。世界中のホテル名であり、名前にアクセント記号付きの文字が含まれています。私の問題では、これらを有効なアルファ文字として分類したいと思います。
この場合:
Latin1文字セット/コードページに含まれる英語以外の11文字があり、a-z
範囲と一致しません。彼らは以下の通りですð Ð Þ þ œ Œ š Š ž Ž Ÿ
。これらはワイルドカードに追加する必要があり、現時点では必要ありませんA-Z
が、パターンを大文字と小文字を区別する照合で正しく機能させるために追加しても問題ありません。最終結果は次のとおりです。
LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'
このデータには「世界中のホテル名」を含めることができるので、すべての言語のすべての文字を格納できるように列のデータ型を変更することを強くお勧めNVARCHAR
します。これをそのままにしVARCHAR
ておくと、ラテン語ベースの言語しか表現できず、ラテン語関連の追加の文字を提供する6つの補足的なUnicodeカテゴリが指定された言語では完全に表現できないため、最終的にデータ損失のリスクが非常に高くなります。