在 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),
...

  1. 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 是数字 - 它不应该是 integerint64 而不是文本吗?

  1. 屏幕截图底部显示“(NONE)”。我怀疑是"connection charset"。允许与 20 年前制作的程序向后兼容,但在今天这是相当危险的。您必须查阅您的系统文档,如何将连接字符集设置为 URF-8 或 Windows-1250 或其他有意义的内容。

  2. "How do I check for unique key so that keys with trailing spaces are not included?" 你没有。你只是不能可靠地做到这一点,因为不同的交易和不同的程序同时建立连接。你会检查它,确定你是清楚的,但就在你插入你的行之前 - 其他一些计算机也会插入它。在您的检查和插入两个命令之间,无法以这种方式跨越该差距 - 其他任何人也可以这样做。它被称为竞争条件

您必须要求服务器进行检查。

例如,你必须在 (store, plu_num) 这对列上引入 UNIQUE CONSTRAINT。这样服务器将拒绝在这些列中存储具有相同值的两行,在相同的 transaction.

中可见

此外,space 值是否正常?将字段转换为整数数据类型并确保安全。 或者如果你想保持文本和非数字你仍然可以

  1. 引入 CHECK CONSTRAINTtrim(plu_num) is not distinct from plu_num(或者如果 plu_num 被声明为服务器的 NOT NULL 列,则 trim(plu_num) = plu_num)。这样服务器将拒绝在文本之前或之后存储带有 spaces 的任何值。

如果列的数据类型或排序规则对于比较带有和不带有尾随 spaces 的文本没有区别(如果您无法更改该数据类型或排序规则),您可以尝试添加令牌,例如 ('+' || trim(plu_num) || '+') = ('+' || plu_num || '+')

  1. 或者您可以主动删除那些 space 而不是 CHECK CONSTRAINT:在 table 上设置新的 before update or insert TRIGGER,这样喜欢 NEW.plu_num = TRIM(NEW.plu_num)

文档:

此外,通过 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')