我有一个带有字符串[16]键字段的表的现有数据库。 有些行的关键结尾有一个空格:" 16"。 我需要允许用户从" 16"例如" 16"但也要做一个唯一的密钥检查(即表中没有密钥=" 16")的记录。 我运行以下查询:
select * from plu__ where store=100 and plu_num = '16'
它返回带有键的行=" 16"! 如何检查唯一键以便不包含带尾随空格的键?
编辑:DDL和char_length
CREATE TABLE PLU__
(
PLU_NUM Varchar(16),
CAPTION Varchar(50),
...
答案 0 :(得分:3)
string[16]
- Firebird中没有这样的数据类型。有CHAR(16)
和VARCHAR(16)
(和BLOB SUBTYPE TEXT
,但这里不太可能。所以你省略了一些关于你的系统的关键点。你不使用Firebird,但是有一些未公开的中间层,没有人知道它是多么透明或透明。我怀疑您或您的系统选择CHAR
数据类型而不是VARCHAR
,其中所有数据都用空格填充到最大值。或者列/表/数据库的COLLATION
可能是尾随空格无关紧要。
另外,你可能错了。您声称被选中的行确实包含尾随空白,但我没有看到它。例如,将CHAR_LENGTH(plu_num)
添加到SELECT中的列,并查看其中的内容。
此外,如果plu_num
是数字 - 是不是integer
或int64
而不是文字?
屏幕截图的底部显示"(无)"。我怀疑那是"连接charset"。这可以与20年前制作的程序向后兼容,但今天非常危险。您必须查阅系统文档,如何将连接字符集设置为URF-8或Windows-1250或其他有意义的内容。
"如何检查唯一键,以便不包含带有尾随空格的键?" 您没有。你不能可靠地做到这一点,因为不同的交易和不同的程序同时进行连接。你会检查它,确定你是清楚的,但在你插入行之前 - 其他一些计算机也会插入它。在你的两个检查和插入命令之间,这个差距不能以这种方式交叉 - 其他人也可以这样做。它被称为种族条件。
您必须要求服务器进行检查。
例如,您必须在UNIQUE CONSTRAINT
列上引入(store, plu_num)
。这样,服务器将拒绝在这些列中存储具有相同值的两行,在同一transaction
中可见。
此外,拥有空格值是否正常?将字段转换为整数数据类型并且是安全的。 或者如果你想保持文本和非数字,你仍然可以
CHECK CONSTRAINT
{或trim(plu_num) is not distinct from plu_num
声明为plu_num
列的NOT NULL
引入trim(plu_num) = plu_num
,然后('+' || trim(plu_num) || '+') = ('+' || plu_num || '+')
)。这样,服务器将拒绝在文本之前或之后存储任何带空格的值。 如果数据类型或列的排序规则对于使用和不包含尾随空格的文本进行比较没有区别(如果您无法更改该数据类型或排序规则),您可以尝试添加标记,例如{{1} }
CHECK CONSTRAINT
,您可以主动删除这些空格:在表格中设置新的before update or insert
TRIGGER
,就像NEW.plu_num = TRIM(NEW.plu_num)
文档:
另外,通过http://www.translate.ru更详细一点:
您也可以查看http://www.firebirdfaq.org/cat3/
此外,如果您在引入这些检查之前使用先前输入的无效数据将约束添加到现有表中,您可能会将自己陷入"非可恢复备份"情况。您必须检查它,并清理旧数据以遵守新引入的约束。
选项#4详细说明如下。这似乎是数据库设计的一个坏主意!一个人不应该只是#34;让人们编辑数字来删除尾随空白",应该进行数据库设计,以便不会任何尾随空白的数字,将是没有以任何方式将它们插入数据库。
CREATE TABLE "_NEW_TABLE" (
ID INTEGER NOT NULL,
TXT VARCHAR(10)
);
Select id, txt, '_'||txt||'_', char_length(txt) from "_NEW_TABLE"
ID TXT CONCATENATION CHAR_LENGTH
1 1 _1_ 1
2 2 _2_ 1
4 1 _1 _ 2
5 2 _2 _ 2
7 1 _ 1_ 2
8 2 _ 2_ 2
Select id, txt, '_'||txt||'_', char_length(txt) from "_NEW_TABLE"
where txt = '2'
ID TXT CONCATENATION CHAR_LENGTH
2 2 _2_ 1
5 2 _2 _ 2
Select id, txt, '_'||txt||'_', char_length(txt) from "_NEW_TABLE"
where txt || '+' = '2+' -- WARNING - this PROHIBITS index use on txt column, if there is any
ID TXT CONCATENATION CHAR_LENGTH
2 2 _2_ 1
Select id, txt, '_'||txt||'_', char_length(txt) from "_NEW_TABLE"
where txt = '2' and char_length(txt) = char_length('2')