在 Firebird SQL 中比较带有尾随空格的字符串?
Compare strings with trailing spaces in Firebird SQL?
我有一个现有的数据库,其中 table 带有一个字符串 [16] 键字段。
有些行的键以 space: "16 " 结尾。
我需要允许用户从“16”更改为例如“16”,但也做一个唯一的键检查(即 table 没有已经有键 =“16”的记录)。
我运行以下查询:
select * from plu__ where store=100 and plu_num = '16'
它returns 键为“16”的行!
如何检查唯一密钥,以便不包含尾随 space 的密钥?
编辑:DDL 和 char_length
CREATE TABLE PLU__
(
PLU_NUM Varchar(16),
CAPTION Varchar(50),
...
string[16]
- Firebird 中没有这样的数据类型。有CHAR(16)
和VARCHAR(16)
(还有BLOB SUBTYPE TEXT
,但这里不太可能)。所以你忽略了一些关于你的系统的关键点。你不使用 Firebird,而是使用一些未公开的中间层,没有人知道它有多不透明或透明。
我怀疑您或您的系统选择了 CHAR
数据类型而不是 VARCHAR
,其中所有数据都用 space 右填充到最大值。或者 column/table/database 的 COLLATION
是这样的,所以尾随的 space 并不重要。
另外,你可能错了。您声称被选中的行确实包含尾随空白,但我没有看到它。例如,将 CHAR_LENGTH(plu_num)
添加到 SELECT 中的列,然后查看那里有什么。
此外,如果 plu_num
是数字 - 它不应该是 integer
或 int64
而不是文本吗?
屏幕截图底部显示“(NONE)”。我怀疑是"connection charset"。允许与 20 年前制作的程序向后兼容,但在今天这是相当危险的。您必须查阅您的系统文档,如何将连接字符集设置为 URF-8 或 Windows-1250 或其他有意义的内容。
"How do I check for unique key so that keys with trailing spaces are not included?" 你没有。你只是不能可靠地做到这一点,因为不同的交易和不同的程序同时建立连接。你会检查它,确定你是清楚的,但就在你插入你的行之前 - 其他一些计算机也会插入它。在您的检查和插入两个命令之间,无法以这种方式跨越该差距 - 其他任何人也可以这样做。它被称为竞争条件。
您必须要求服务器进行检查。
例如,你必须在 (store, plu_num)
这对列上引入 UNIQUE CONSTRAINT
。这样服务器将拒绝在这些列中存储具有相同值的两行,在相同的 transaction
.
中可见
此外,space 值是否正常?将字段转换为整数数据类型并确保安全。
或者如果你想保持文本和非数字你仍然可以
- 引入
CHECK CONSTRAINT
即 trim(plu_num) is not distinct from plu_num
(或者如果 plu_num
被声明为服务器的 NOT NULL
列,则 trim(plu_num) = plu_num
)。这样服务器将拒绝在文本之前或之后存储带有 spaces 的任何值。
如果列的数据类型或排序规则对于比较带有和不带有尾随 spaces 的文本没有区别(如果您无法更改该数据类型或排序规则),您可以尝试添加令牌,例如 ('+' || trim(plu_num) || '+') = ('+' || plu_num || '+')
- 或者您可以主动删除那些 space 而不是
CHECK CONSTRAINT
:在 table 上设置新的 before update or insert
TRIGGER
,这样喜欢 NEW.plu_num = TRIM(NEW.plu_num)
文档:
- https://www.firebirdsql.org/refdocs/langrefupd20-distinct.html
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-constraints
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-altradd
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-trgr.html
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-chartypes.html
此外,通过 http://www.translate.ru 更详细一点:
您也可以查看 http://www.firebirdfaq.org/cat3/
此外,如果您将约束添加到现有 table 中,并且在引入这些检查之前输入了无效数据,您可能会陷入 "non-restorable backup" 的境地。您必须检查它,并清理旧数据以遵守新引入的约束。
选项 #4 的详细解释如下。这似乎是数据库设计的一个坏主意!不应该只是 "let people edit number to remove trailing blanks",应该进行数据库设计,使得 没有 任何带尾随空白的数字,并且 没有 以任何方式将它们插入数据库。
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')
我有一个现有的数据库,其中 table 带有一个字符串 [16] 键字段。 有些行的键以 space: "16 " 结尾。 我需要允许用户从“16”更改为例如“16”,但也做一个唯一的键检查(即 table 没有已经有键 =“16”的记录)。 我运行以下查询:
select * from plu__ where store=100 and plu_num = '16'
它returns 键为“16”的行! 如何检查唯一密钥,以便不包含尾随 space 的密钥?
编辑:DDL 和 char_length
CREATE TABLE PLU__
(
PLU_NUM Varchar(16),
CAPTION Varchar(50),
...
string[16]
- Firebird 中没有这样的数据类型。有CHAR(16)
和VARCHAR(16)
(还有BLOB SUBTYPE TEXT
,但这里不太可能)。所以你忽略了一些关于你的系统的关键点。你不使用 Firebird,而是使用一些未公开的中间层,没有人知道它有多不透明或透明。
我怀疑您或您的系统选择了 CHAR
数据类型而不是 VARCHAR
,其中所有数据都用 space 右填充到最大值。或者 column/table/database 的 COLLATION
是这样的,所以尾随的 space 并不重要。
另外,你可能错了。您声称被选中的行确实包含尾随空白,但我没有看到它。例如,将 CHAR_LENGTH(plu_num)
添加到 SELECT 中的列,然后查看那里有什么。
此外,如果 plu_num
是数字 - 它不应该是 integer
或 int64
而不是文本吗?
屏幕截图底部显示“(NONE)”。我怀疑是"connection charset"。允许与 20 年前制作的程序向后兼容,但在今天这是相当危险的。您必须查阅您的系统文档,如何将连接字符集设置为 URF-8 或 Windows-1250 或其他有意义的内容。
"How do I check for unique key so that keys with trailing spaces are not included?" 你没有。你只是不能可靠地做到这一点,因为不同的交易和不同的程序同时建立连接。你会检查它,确定你是清楚的,但就在你插入你的行之前 - 其他一些计算机也会插入它。在您的检查和插入两个命令之间,无法以这种方式跨越该差距 - 其他任何人也可以这样做。它被称为竞争条件。
您必须要求服务器进行检查。
例如,你必须在 (store, plu_num)
这对列上引入 UNIQUE CONSTRAINT
。这样服务器将拒绝在这些列中存储具有相同值的两行,在相同的 transaction
.
此外,space 值是否正常?将字段转换为整数数据类型并确保安全。 或者如果你想保持文本和非数字你仍然可以
- 引入
CHECK CONSTRAINT
即trim(plu_num) is not distinct from plu_num
(或者如果plu_num
被声明为服务器的NOT NULL
列,则trim(plu_num) = plu_num
)。这样服务器将拒绝在文本之前或之后存储带有 spaces 的任何值。
如果列的数据类型或排序规则对于比较带有和不带有尾随 spaces 的文本没有区别(如果您无法更改该数据类型或排序规则),您可以尝试添加令牌,例如 ('+' || trim(plu_num) || '+') = ('+' || plu_num || '+')
- 或者您可以主动删除那些 space 而不是
CHECK CONSTRAINT
:在 table 上设置新的before update or insert
TRIGGER
,这样喜欢NEW.plu_num = TRIM(NEW.plu_num)
文档:
- https://www.firebirdsql.org/refdocs/langrefupd20-distinct.html
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-constraints
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-tbl.html#fblangref25-ddl-tbl-altradd
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-ddl-trgr.html
- http://www.firebirdtest.com/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-datatypes-chartypes.html
此外,通过 http://www.translate.ru 更详细一点:
您也可以查看 http://www.firebirdfaq.org/cat3/
此外,如果您将约束添加到现有 table 中,并且在引入这些检查之前输入了无效数据,您可能会陷入 "non-restorable backup" 的境地。您必须检查它,并清理旧数据以遵守新引入的约束。
选项 #4 的详细解释如下。这似乎是数据库设计的一个坏主意!不应该只是 "let people edit number to remove trailing blanks",应该进行数据库设计,使得 没有 任何带尾随空白的数字,并且 没有 以任何方式将它们插入数据库。
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')