web-dev-qa-db-ja.com

Unicode文字の詳細をvarchar DBに挿入する方法は?

照合順序をSQL_Latin1_General_CP1_CI_ASとして設定したMSSQLデータベースのVARCHAR列にこの文字 '●'を挿入する必要があります(または、少なくとも私のモックアップPython + Windows MSSQLドライバーが完了した可能性があります。これをクライアントから挿入しようとしましたが、?として挿入されます。

Python=でチェックされる16進値は\xe2\x97\x8fで、これはバイナリ226、151、143です。

照合 spec は、226が定義されているが、143と151は未定義であることを示しています。私のベストは226を挿入することでしょうか?

私がこの演習を行っているのは、私たちのアプリが以前にこのキャラクターをDBに挿入していたためです。この時点では、それがどのように行われたかはわかりませんが、Python Windows MSSQLドライバーを使用したアプリを実行し、DBチームがそれを修正するためのスクリプトを作成しました。 「?」.

今、私はこのシナリオを再現して、なぜ「?」に置き換えられるのかを尋ねようとしています。アプリでは空として置き換えているためです。私のアプリには既にこの問題の修正が含まれているため(127より大きいものは削除されます)、これをバックエンドから直接モックして、「?」に置き換えられることを証明しようとしています。これは実際には私の主張であり、更新クエリで「COLLATE」と表示されているために行われたと思います。

UPDATE pr_response
SET nur_respon =
REPLACE (nur_respon,
     SUBSTRING(nur_respon, PATINDEX('%[^ !-~]%' COLLATE Latin1_General_BIN, nur_respon), 1),
         '')
WHERE PATINDEX('%[^ !-~]%' COLLATE Latin1_General_BIN, nur_respon) > 0

これは、非ASCIIデータ> 127を削除するための素晴らしいスクリプトですか?誰かがこのクエリを分かりやすい英語で説明できますか?

2
Nishant

この文字「●」をVARCHAR列に挿入する必要があります...照合をSQL_Latin1_General_CP1_CI_ASに設定します...この演習を行っている理由は、アプリがこの文字をDBに挿入していたためですついさっき。

いいえ、アプリは[SQL_]Latin1_General...照合順序を使用してVARCHAR列にこの文字( Black Circle U + 25CF )を挿入していませんでした。 Latin1_General Collat​​ionsは Code Page 1252 を使用しますが、そのような文字はなく、「最適な」マッピングが存在しないように見えるため、類似したものに変換することもできません。

その文字は、次のクエリが示すように、韓国語と日本語の照合で使用されるものなど、一部のコードページに存在します(どちらも2バイト文字セットであるため、VARBINARYへの変換では2バイトが表示されますひとつの):

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Korean_100_CI_AS),
       CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Korean_100_CI_AS));
-- ●    0xA1DC

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Japanese_XJIS_100_CI_AS),
       CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Japanese_XJIS_100_CI_AS));
-- ●    0x819C

SELECT CONVERT(VARCHAR(10), N'●' COLLATE Latin1_General_100_CI_AS),
       CONVERT(VARBINARY(10), CONVERT(VARCHAR(10), N'●' COLLATE Latin1_General_100_CI_AS));
-- ?    0x3F

ただし、アプリが '•'( Bullet U + 2022 )を挿入していた可能性があります。 「弾丸」文字はコードページ1252(12月149または16進0x95)で使用できます。

私たちのDBチームはそれを修正するスクリプトを書いて、どうやら "?"に置き換えられました。

さて、「●」を「?」に置き換えてそれを修正するようには聞こえません;-)。

今、私はこのシナリオを再現して、なぜ「?」に置き換えられるのかを尋ねようとしています。アプリでは空として置き換えているためです。私のアプリにはすでにこの問題の修正が含まれているため(127を超えるものはすべて削除されます)

専門性に関係なく、両方のステートメントが同時にtrueになることはあり得ないことはかなり明白です。「?」で置き換えることはできません。 およびは、SQL Serverにアクセスする前に削除されます。明らかにアプリのコードはこれを修正ししないであり、しない127を超える値を持つすべてを削除します。「?」に変換されますSQL Serverでは、その文字がまだ挿入されているため、コードページ1252には存在しません。

更新クエリで「COLLATE」と表示されているので、完了したと思います。

いいえ、COLLATEキーワードを介してバイナリ照合を強制しても、この文字は「?」に変更されません。列の照合順序(SQL_Latin1_General_CP1_CI_AS)と明示的な照合順序(Latin1_General_BIN)はどちらもコードページ1252を使用するため、これにより文字が変更されることはありません。

「●」文字は「?」に置き換えられますVARCHAR列に挿入されているためです。また、クエスチョンマークとして挿入されると、クリーンアップするものは何もありません。また、クエスチョンマークを、意図されたクエスチョンマークではなく、他の何かに由来するものとして識別する方法はありません。

これは、非ASCIIデータ> 127を削除するための素晴らしいスクリプトですか?誰かがこのクエリを分かりやすい英語で説明できますか?

このクエリは、ASCII値が127を超える文字(つまり、PATINDEXが行うこと)をすべて検出し、そのような文字(つまり、SUBSTRINGは)、次に列内のその文字のすべての出現を空の文字列で置き換えます(これはREPLACEが行うことです)。クエリはUPDATEを実行しません。 ASCII 127を超える値を持つ文字が見つかりました。

このクエリは、一度に1つの文字に対してのみ機能します。したがって、列にASCII 127を超える値があり、同じでないASCII値を持つ2つ以上の文字がある場合、スクリプトは複数実行する必要があります。回。

その変換は途中で行われているため、このクエリはこの特定のケース(つまり、「●」を「?」で置き換える)では役に立ちません。このクエリは、ASCII値が128の文字のみを処理します-255、まだ "●"はこれらの文字の1つではありません。そもそもこの列には決してないからです。

2
Solomon Rutzky