【问题标题】:DDL date data type in check constraint manipulation in oracleoracle 中检查约束操作中的 DDL 日期数据类型
【发布时间】:2015-03-02 10:45:47
【问题描述】:

我正在创建一个应该检查各种日期约束的表,但是 oracle 对这个参数有点挑剔。我的目标是预留一个空间让我们说一个讲座,所以我坚持这样的事情:

.... prenotation_date 日期不为空, 开始日期日期不为空, 结束日期日期不为空,

check (/starting_date > prenotation_date+3gg/ ) -> 您只能在要求预订的 3 天后预订房间

检查 (/* starting_date = ending_date */ ) 关于您预订的日期,这意味着您可以预订一天的房间

检查 (/* starting_date 时间,这意味着您开始使用房间的时间必须早于您打算的时间离开房间(假设您想在上午 8:00 到上午 10:00 期间预订房间

问题是我不知道如何只考虑数据的一部分,但我想有一种方法可以做到这一点,否则你应该创建 4 列而不是 2 列并使用几个虚拟日期和另一个是愚蠢的时间,这对我来说似乎很笨拙。所以我想问题是,我如何考虑单个组件中的日期类型?这甚至可能吗?感谢您的关注,很抱歉发了这么长的帖子。

【问题讨论】:

  • 检查约束就足够了。我为每个检查的条件提供了一个完整的测试用例。看我的回答。
  • 这里的答案是正确的,但逻辑容易出错。当老板说“现在预订房间”时会发生什么?您是否要告诉他们“我必须更改生产数据库上的代码?”考虑一个单独的表格,其中“这些永远不会改变”数字作为值。然后在触发器中引用这些而不是硬编码值。

标签: oracle date constraints ddl


【解决方案1】:

您可以在以下条件下使用 CHECK 约束:

  1. starting_date > prenotation_date + 3
  2. 开始日期
  3. TRUNC(starting_date) = TRUNC(ending_date)

starting_date > prenotation_date + 3 将确保在预订 3 天后允许预订

starting_date < ending_date 将确保预订的时间总是在离开时间之前

TRUNC(starting_date) = TRUNC(ending_date) 将确保在同一天完成预订。 即预订窗口只有一天。

测试用例:

创建表

SQL> CREATE TABLE t(
  2  prenotation_date DATE NOT NULL, starting_date DATE NOT NULL, ending_date DATE NOT NULL);

Table created.

SQL>

添加检查约束

SQL> ALTER TABLE t ADD CONSTRAINT t_chk CHECK(
  2  (starting_date > prenotation_date + 3)
  3  AND (starting_date < ending_date)
  4  AND (TRUNC(starting_date) = TRUNC(ending_date))
  5  );

Table altered.

SQL>

插入:检查starting_date &gt; prenotation_date + 3。下面的插入应该会失败。

SQL> INSERT
  2  INTO t VALUES
  3    (
  4      to_date('03/01/2015 00:00:00','mm/dd/yyyy hh24:mi:ss'),
  5      to_date('03/02/2015 08:00:00','mm/dd/yyyy hh24:mi:ss'),
  6      to_date('03/02/2015 10:00:00','mm/dd/yyyy hh24:mi:ss')
  7    );
INSERT
*
ERROR at line 1:
ORA-02290: check constraint (LALIT.T_CHK) violated


SQL>

插入:检查开始日期

SQL> INSERT
  2  INTO t VALUES
  3    (
  4      to_date('02/01/2015 00:00:00','mm/dd/yyyy hh24:mi:ss'),
  5      to_date('03/02/2015 10:00:00','mm/dd/yyyy hh24:mi:ss'),
  6      to_date('03/02/2015 08:00:00','mm/dd/yyyy hh24:mi:ss')
  7    );
INSERT
*
ERROR at line 1:
ORA-02290: check constraint (LALIT.T_CHK) violated


SQL>

INSERT :检查预订在同一天完成。下面的插入应该失败。注意时间08:00:0010:00:00 分别表示开始和结束时间。

SQL>   INSERT
  2  INTO t VALUES
  3    (
  4      to_date('02/01/2015 00:00:00','mm/dd/yyyy hh24:mi:ss'),
  5      to_date('03/02/2015 08:00:00','mm/dd/yyyy hh24:mi:ss'),
  6      to_date('04/02/2015 10:00:00','mm/dd/yyyy hh24:mi:ss')
  7    );
  INSERT
*
ERROR at line 1:
ORA-02290: check constraint (LALIT.T_CHK) violated


SQL>

INSERT :所有值都满足要求,下面的插入应该通过。

SQL> INSERT
  2  INTO t VALUES
  3    (
  4      to_date('02/01/2015 00:00:00','mm/dd/yyyy hh24:mi:ss'),
  5      to_date('03/02/2015 08:00:00','mm/dd/yyyy hh24:mi:ss'),
  6      to_date('03/02/2015 10:00:00','mm/dd/yyyy hh24:mi:ss')
  7    );

1 row created.

SQL>

【讨论】:

  • 很好的观察,非常感谢。尽管我不明白 TRUNC 是如何工作的。是否默认截断日期以缩短时间跨度?我的解决方案是使用 to_date - to_char 嵌套函数来隔离感兴趣的参数;顺便说一句,我不能去上班。
  • 显然我的想法在逻辑上是正确的,但仍然很糟糕。我很难比较字符串域中的日期以实现第一次检查 -> to_char(starting_date,'mm/dd/yyyy') = to_char(ending_date,'mm/dd/yyyy')
  • Trunc 从 DATE 中删除时间元素。因此,截断值的日期时间值为 DATE+00:00:00 小时。
【解决方案2】:

通常,您应该只是学习如何在 Oracle 和 SQL 中处理日期:) 有几种方法可以做到这一点。例如:

-- Check whether room was booked timely
alter table Reservations add constraint RC1
  check (trunc(starting_date, 'DD') >= trunc(prenotation_date, 'DD') + 3);

-- Disable booking ranges around midnight
alter table Reservations add constraint RC2
  check (trunc(starting_date, 'DD') = trunc(ending_date, 'DD'));

-- Check whether booked range exists
alter table Reservations add constraint RC3
  check (starting_date < ending_date);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    相关资源
    最近更新 更多