我的项目需要从用户与左边和间距就一个字右边的间距开始输入,例如“苹果”。 如果在“苹果”或“苹果”的用户类型,无论是一个空间或在字的左边或右边多的空间,我需要存储这种方式。
该字段具有独特的属性,但我试图在左侧距插入单词,并能正常工作。 但是,当我试图与右侧间距插入单词它剪掉所有从词的适当的间距。
所以我想加入一个特殊字符的字间距后的权利。 但我希望有此问题的更好的解决方案。
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
问题是,MySQL的做字符串比较时忽略尾随空白。 见http://dev.mysql.com/doc/refman/5.7/en/char.html
所有MySQL归类为类型PADSPACE的。 这意味着所有CHAR,VARCHAR,并在MySQL TEXT值不考虑任何尾随空格比较。
...
对于其中拖尾填充字符被剥离或比较忽略它们,如果列具有需要的唯一值,插入只在尾随填充字符将导致重复键错误的数目上不同的列值的索引的那些情况下。 例如,如果一个表中包含“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有归类其是类型NO PAD的,根据https://dev.mysql.com/doc/refman/8.0/en/char.html :
大多数MySQL归类在垫空间垫属性。 唯一的例外是基于UCA 9.0.0和更高的Unicode排序规则,它们没有什么PAD垫属性。
和https://dev.mysql.com/doc/refman/8.0/en/charset-unicode-sets.html
基于UCA版本高于4.0.0的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;
你可以有和没有尾随空格插入值
你可以找到所有可用的无PAD的排序规则:
show collation where Pad_attribute='NO PAD';
这不是CHAR VS VARCHAR。 SQL Server不考虑尾随空格,当涉及到字符串比较,检验唯一键约束时也适用。 因此,这不是你不能用尾随空格插入值,但一旦你插,你不能用更多或更少的空间插入另一个值。
作为解决你的问题,你可以添加保持字符串的长度一列,使长度和字符串值作为组合唯一键约束。
在SQL Server 2012中 ,你甚至可以使长度列计算列,这样你就不必担心价值可言。 见http://sqlfiddle.com/#!6/32e94与SQL Server 2012的一个例子(我敢打赌,类似的东西可能是在MySQL。)
你可能需要阅读有关VARCHAR和CHAR类型之间的差异。
CHAR和VARCHAR类型
当被存储CHAR值,它们是右填充空格以指定的长度。 当检索CHAR值,尾随空格被删除,除非启用PAD_CHAR_TO_FULL_LENGTH SQL模式。
对于VARCHAR列,在过量列长度的尾随空格到插入之前截断,生成警告,而不管所使用的模式SQL的。 为CHAR列,被默默地不管SQL模式的执行从插入的值过量尾随空格的截断。
存放时,他们VARCHAR值不填充。 当值被存储和检索,与标准的SQL一致性尾部空格被保留。
结论:如果你想保留的文本字符串的右侧空格,使用CHAR类型(而不是VARCHAR)。
由于@kennethc。 他的回答对我的作品。 字符串长度字段添加到表,并以独特的密钥。
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,
string_length int(3),
PRIMARY KEY (id), UNIQUE KEY string (string,string_length) )
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
在MySQL中它可能与夫妇这样的触发器来更新字符串长度字段:
CREATE TRIGGER `string_length_insert` BEFORE INSERT ON `strings` FOR EACH ROW SET NEW.string_length = char_length(NEW.string);
CREATE TRIGGER `string_length_update` BEFORE UPDATE ON `strings` FOR EACH ROW SET NEW.string_length = char_length(NEW.string);