【问题标题】:Oracle UNIQUE constraint allows same value in different caseOracle UNIQUE 约束允许在不同情况下使用相同的值
【发布时间】:2021-01-05 03:24:33
【问题描述】:

我对 Oracle 数据库表中的列有一个 UNIQUE 约束。允许大小写保存相同的值。

例如; 首先,我将 M100 插入到表的 UNIQUE 列中。然后当我再次尝试插入 M100 时,我可以看到唯一约束违规错误。

但是当我尝试插入 m100 时,数据库接受并保存到表中。

我该如何解决这个问题。无论如何,我都需要限制该值。

我使用的是以下版本

"Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production
Version 18.4.0.0.0"

这里是Live SQL

【问题讨论】:

    标签: oracle oracle-apex unique-constraint oracle18c oracle-apex-20.1


    【解决方案1】:

    尝试将基于函数的索引添加到表中

    CREATE UNIQUE INDEX some_index_name
    ON tablename(UPPER(column_name));
    

    【讨论】:

      【解决方案2】:

      由于您使用的是 Oracle 18,因此您可以使用不可见列和虚拟列等新功能或collation

      虚拟不可见列+唯一约束: 例如,您有一个包含 STR 列的表 T:

      create table t(str varchar2(10));
      

      所以你可以添加不可见的虚拟列str_lower 生成为lower(str)

      alter table t add 
            str_lower varchar2(10) invisible generated always as (lower(str)) ;
      

      由于此列是不可见且虚拟的,因此不会破坏您现有的代码。 现在您可以在其上添加unique 约束:

      alter table t add
            constraint t_str_unique_lower
               unique(str_lower) using index;
      

      测试它:

      SQL> insert into t values('M100');
      
      1 row created.
      
      SQL> insert into t values('m100');
      insert into t values('m100')
      *
      ERROR at line 1:
      ORA-00001: unique constraint (XTENDER.T_STR_UNIQUE_LOWER) violated
      

      此外,它还允许您通过较低的值轻松找到值:

      SQL> select * from t where str_lower='m100';
      
      STR
      ----------
      M100
      
      SQL> select str,str_lower from t where str_lower='m100';
      
      STR        STR_LOWER
      ---------- ----------
      M100       m100
      

      如您所见,如果您未在选择列表中指定它,它不会返回 str_lower 列:

      另一种可能的解决方案是为您的列指定collation,但需要将数据库参数MAX_STRING_SIZE 设置为EXTENDED,否则您将得到ORA-43929: Collation cannot be specified if parameter MAX_STRING_SIZE=STANDARD is set.

      alter table t modify str COLLATE BINARY_CI;
      alter table t add constraint t_str_unique unique(str);
      

      更多信息: https://oracle-base.com/articles/12c/column-level-collation-and-case-insensitive-database-12cr2

      【讨论】:

      • 出色的解决方案和惊人的替代方案。
      • 感谢您的回答,这真的很有帮助。
      【解决方案3】:

      之前的两个答案都很好,但根据业务案例,还有另一个可能有意义的选项。有时您的数据不区分大小写(例如电子邮件地址),因此请始终使用触发器将其存储在相同的大小写中。

      然后唯一约束将起作用并且您的数据更干净。这种触发器的一个例子是:

      create or replace TRIGGER t_biu BEFORE
        INSERT OR UPDATE ON t
        FOR EACH ROW
      DECLARE
      BEGIN
        :NEW.column_name := UPPER(:NEW.column_name);
      END t_biu;
      

      【讨论】:

        猜你喜欢
        • 2015-12-23
        • 2016-02-05
        • 1970-01-01
        • 2019-02-02
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多