在 Firebird SQL 中比较字符串和尾随空格?

 2022-01-08 

Compare strings with trailing spaces in Firebird SQL?

我有一个现有的数据库,其中包含一个带有字符串 [16] 键字段的表。
有些行的键以空格结尾:"16"。
我需要允许用户从"16"更改为例如"16",但也做一个唯一的键检查(即表还没有键="16"的记录)。
我运行以下查询:

1
SELECT * FROM plu__ WHERE store=100 AND plu_num = '16'

返回key="16"的行!
如何检查唯一键以便不包括带有尾随空格的键?

enter

1
2
3
4
5
CREATE TABLE PLU__
(
  PLU_NUM VARCHAR(16),
  CAPTION VARCHAR(50),
...

enter


  • string[16] - Firebird 中没有这样的数据类型。有 CHAR(16)VARCHAR(16)(还有 BLOB SUBTYPE TEXT,但在这里不太可能)。所以你忽略了一些关于你的系统的关键点。您不使用 Firebird,而是使用一些未公开的中间层,即没有人知道它是多么不透明或透明。
  • 我怀疑您或您的系统选择了 CHAR 数据类型而不是 VARCHAR,其中所有数据都以最大空间右填充。或者,列/表/数据库的 COLLATION 可能导致尾随空格无关紧要。

    另外,你可能错了。您声称被选中的行确实包含尾随空白,但我没有看到它。例如,将 CHAR_LENGTH(plu_num) 添加到 SELECT 中的列中,看看里面有什么。

    另外,如果 plu_num 是数字 - 它不应该是 integerint64 而不是文本吗?

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

  • "如何检查唯一键,以便不包括带有尾随空格的键?"你不。你只是不能可靠地做到这一点,因为不同的事务和不同的程序同时连接。你会检查它,确定你是清楚的,但是在你插入你的行之前 - 其他一些计算机也会插入它。在您的检查和插入两个命令之间,这种差距无法跨越 - 其他任何人也可以做到。它被称为竞争条件。

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

    例如,您必须在 (store, plu_num) 列对上引入 UNIQUE CONSTRAINT。这样,服务器将拒绝在这些列中存储具有相同值的两行,在相同的 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 || '+')

  • 或者代替那个 CHECK CONSTRAINT,您可以主动删除这些空格:在桌子上设置新的 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://firebirdsql.su/doku.php?id=constraint
    • http://firebirdsql.su/doku.php?id=alter_table

    您也可以查看 http://www.firebirdfaq.org/cat3/

    此外,如果您在引入这些检查之前将约束添加到具有先前输入的无效数据的现有表中,您可能会陷入"不可恢复备份"的境地。您必须检查它,并清理旧数据以遵守新引入的约束。

    选项#4 详细解释如下。这似乎是数据库设计的一个坏主意!一个人不应该只是"让人们编辑数字以删除尾随空格",一个应该使数据库设计使得没有任何尾随空格的数字,并且没有任何方法将它们插入数据库。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    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')