10

私のプロジェクトでは、'apple' のように単語の左側と右側に間隔を空けてユーザーからの入力を開始する必要があります。ユーザーが「apple」または「apple」と入力した場合、単語の左右に 1 つのスペースまたは複数のスペースがあるかどうかにかかわらず、そのように保存する必要があります。

このフィールドにはUnique属性がありますが、左側にスペースを空けて単語を挿入しようとしましたが、うまくいきました。しかし、右側にスペースのある単語を挿入しようとすると、単語の右側からすべてのスペースが削除されます。

そこで、スペーシングの後の単語の右側に特殊文字を追加することを考えています。しかし、この問題に対するより良い解決策があることを願っています。

CREATE TABLE strings
( id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
string varchar(255) COLLATE utf8_bin NOT NULL,
created_ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id), UNIQUE KEY string (string) )
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
4

4 に答える 4

17

問題は、MySQL が文字列比較を行うときに末尾の空白を無視することです。http://dev.mysql.com/doc/refman/5.7/en/char.htmlを参照してください 。

すべての MySQL 照合は PADSPACE 型です。これは、MySQL のすべての CHAR、VARCHAR、および TEXT 値が末尾のスペースに関係なく比較されることを意味します。

...

末尾の埋め込み文字が削除されるか、比較でそれらが無視される場合、列に一意の値を必要とするインデックスがある場合、末尾の埋め込み文字の数だけが異なる値を列に挿入すると、重複キー エラーが発生します。たとえば、テーブルに「a」が含まれている場合、「a」を格納しようとすると、重複キー エラーが発生します。

(この情報は 5.7 用です。8.0 ではこれが変更されました。以下を参照してください)

演算子のセクションでは、likeこの動作の例を示します (like末尾の空白を尊重することを示しています)。

mysql> SELECT 'a' = 'a ', 'a' LIKE 'a ';
+------------+---------------+
| 'a' = 'a ' | 'a' LIKE 'a ' |
+------------+---------------+
|          1 |             0 |
+------------+---------------+
1 row in set (0.00 sec)

残念ながら、UNIQUEインデックスは標準の文字列比較を使用してそのような値が既に存在するかどうかを確認しているように見えるため、末尾の空白は無視されます。VARCHARこれは、またはの使用とは無関係ですCHAR。どちらの場合も、一意のチェックが失敗するため、挿入は拒否されます。likeチェックにセマンティクスを使用する方法がある場合UNIQUE、私はそれを知りません。

あなたができることは、値を次のように保存することですVARBINARY

mysql> create table test_ws ( `value` varbinary(255) UNIQUE );
Query OK, 0 rows affected (0.13 sec)

mysql> insert into test_ws (`value`) VALUES ('a');
Query OK, 1 row affected (0.08 sec)

mysql> insert into test_ws (`value`) VALUES ('a ');
Query OK, 1 row affected (0.06 sec)

mysql> SELECT CONCAT( '(', value, ')' ) FROM test_ws;
+---------------------------+
| CONCAT( '(', value, ')' ) |
+---------------------------+
| (a)                       |
| (a )                      |
+---------------------------+
2 rows in set (0.00 sec)

代わりにバイト値でソートが行われ、それはユーザーが期待するものではないため、この列でアルファベット順にソートするようなことはしたくないでしょう (ほとんどのユーザーはとにかく)。

別の方法として、MySQL にパッチを適用し、タイプ NO PAD の独自の照合順序を記述します。誰かがそれをやりたいかどうかはわかりませんが、もしそうなら、私に知らせてください;)

編集: 一方、MySQL には、 https : //dev.mysql.com/doc/refman/8.0/en/char.html によると、タイプ NO PAD の照合順序があります。

ほとんどの MySQL 照合には、PAD SPACE のパッド属性があります。例外は、UCA 9.0.0 以降に基づく Unicode 照合であり、パッド属性が NO PAD です。

およびhttps://dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html

4.0.0 以降の UCA バージョンに基づく Unicode 照合には、照合名にバージョンが含まれます。したがって、utf8mb4_unicode_520_ci は UCA 5.2.0 の重みキーに基づいていますが、utf8mb4_0900_ai_ci は UCA 9.0.0 の重みキーに基づいています。

したがって、試してみると:

  create table test_ws ( `value` varbinary(255) UNIQUE )
    character set utf8mb4 collate utf8mb4_0900_ai_ci;

末尾の空白の有無にかかわらず値を挿入できます

利用可能なすべての NO PAD 照合は、次のように見つけることができます。

 show collation where Pad_attribute='NO PAD';
于 2015-01-07T15:56:13.227 に答える
1

おそらく、VARCHAR 型と CHAR 型の違いについて読む必要があります。

CHAR および VARCHAR 型

CHAR 値が格納されると、指定された長さになるまでスペースが右側に埋め込まれます。CHAR 値が取得されると、PAD_CHAR_TO_FULL_LENGTH SQL モードが有効になっていない限り、末尾のスペースは削除されます。

VARCHAR 列の場合、使用中の SQL モードに関係なく、列の長さを超える末尾のスペースは挿入前に切り捨てられ、警告が生成されます。CHAR 列の場合、SQL モードに関係なく、挿入された値からの余分な末尾スペースの切り捨てがサイレントに実行されます。

VARCHAR 値は、格納時にパディングされません。末尾のスペースは、標準 SQL に準拠して、値が保存および取得されるときに保持されます。

結論: テキスト文字列の右側に空白を保持したい場合は、VARCHAR ではなく CHAR 型を使用してください。

于 2012-07-30T01:50:48.260 に答える