【问题标题】:Oracle constraint - compare two string like two timesOracle 约束 - 比较两个字符串两次
【发布时间】:2020-12-01 06:14:19
【问题描述】:

我想创建一个 witj 约束表,它将两个 varchar2(8 char) 列作为时间进行比较。 有可能吗?

我做了一些这样的想法,但它不起作用:(

CONSTRAINT "my_constraint" CHECK (to_number(to_char(to_date(window_stop, 'hh24:mi:ss'), 'sssss')) > to_number(to_char(to_date(window_start, 'hh24:mi:ss'), 'sssss'))) ENABLE

感谢所有帮助。 保罗。

【问题讨论】:

  • 究竟是什么不起作用?你有错误吗?错误的行为?
  • 这是一个非常糟糕的主意。始终使用日期字段来存储日期。时间基本上是格式为 hh:mi:ss 或 hh24:mi:ss 的日期。
  • 你得到的是 `ORA-02436 吗? ??
  • 如果值都是带前导零的 HH24:MI:SS,你不能把它们作为字符串比较吗?另外,“停止”总是与“开始”在同一天吗?如果它可以跨越午夜,那么这个约束无论如何都不会正确。
  • 是的,我有 ORA-02436

标签: oracle constraints string-comparison create-table


【解决方案1】:

您的约束将得到“ORA-02436:在 CHECK 约束中错误指定日期或系统变量”,因为如果您不提供日期元素,则 to_date() 默认为当月的第一天;因此,在插入数据后,评估约束检查的结果可能会发生变化,这是不允许的。在这种特定情况下它实际上无法更改,但正在应用一般规则,导致错误。

您可以改用名义上的固定日期:

CONSTRAINT "my_constraint"
  CHECK (
      to_number(to_char(to_date('2000-01-01 ' || window_stop, 'YYYY-MM-DD hh24:mi:ss'), 'sssss'))
    > to_number(to_char(to_date('2000-01-01 ' || window_start, 'YYYY-MM-DD hh24:mi:ss'), 'sssss'))
  ) ENABLE

db<>fiddle

不过,转换为数字没什么意义,只需比较日期即可:

CONSTRAINT "my_constraint"
  CHECK (
      to_date('2000-01-01 ' || window_stop, 'YYYY-MM-DD hh24:mi:ss')
    > to_date('2000-01-01 ' || window_start, 'YYYY-MM-DD hh24:mi:ss')
  ) ENABLE

db<>fiddle

或者 - 如果您确信值始终是有效时间并且会有前导零 - 只需比较字符串:

CONSTRAINT "my_constraint" CHECK (window_stop > window_start) ENABLE

db<>fiddle

您还可以将时间存储为名义日期、午夜过后的秒数或间隔,这样可以更轻松地防止使用完全无效的值(例如“99:00:00”)。但是您可能有一个可以使用的真实日期 - 取决于这些是否与真实日期相关,或者例如班次模式,或类似的 - 这将允许您处理跨越午夜的窗户。 (您应该做的是将相关的日期和时间存储为单独的字段,但没有表明您在此处所做的事情。)

【讨论】:

    【解决方案2】:

    正如我所说,将 varchar2 用于日期字段总是一个非常糟糕的主意。让我向您展示当字段是日期时,您的约束是多么容易

    SQL> create table t ( c1 date , c2 date ) ;
    
    Table created.
    
    SQL> alter session set nls_date_format='dd.mm.yyyy hh24:mi:ss' ;
    
    Session altered.
    
    SQL> insert into t values ( to_date('11.08.2020 14:00:00') , to_date('11.08.2020 14:10:00') ) ;
    
    1 row created.
    
    SQL> commit ;
    
    Commit complete.
    
    SQL> select * from t ;
    
    C1                  C2
    ------------------- -------------------
    11.08.2020 14:00:00 11.08.2020 14:10:00
    
    SQL> select ( c2 - c1 ) * 24 * 60 * 60 from t ;
    
    (C2-C1)*24*60*60
    ----------------
                 600
    

    现在,让我们添加约束

    SQL> alter table t add constraint chk_test check ( c2 > c1 ) ;
    
    Table altered.
    
    SQL> insert into t values ( to_date('11.08.2020 14:11:00') , to_date('11.08.2020 14:10:00') ) ;
    insert into t values ( to_date('11.08.2020 14:11:00') , to_date('11.08.2020 14:10:00') )
    *
    ERROR at line 1:
    ORA-02290: check constraint (SYS.CHK_TEST) violated
    

    您想要存储时间,即日期,并且您想要比较 window_stop 是否大于 window_start。无需进行如此复杂的转换,只需将字段存储为日期即可。尽管这是您要存储的数据的正确数据类型,但约束会更好地工作。

    【讨论】:

    • 谢谢罗伯托,但我表中的列是 varchar2(8 个字符),时间作为字符串插入,例如。五月表中的时间 12:34:55 是 123455。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-05
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多