【问题标题】:Primary key violation for Oracle table with temporal validity具有时间有效性的 Oracle 表的主键违规
【发布时间】:2020-11-02 04:36:29
【问题描述】:

能否请您分享一些关于 Oracle 中具有临时有效性的表的主键操作的信息?

我创建了一个具有以下架构的表

Create table TemporalTable_1 (
    Customer_ID number(8),
    Customer_name varchar2(100),
    valid_period_start timestamp, 
    valid_period_end timestamp, 
    period for valid_period(valid_period_start, valid_period_end),
    constraint TemporalTable_1_PK primary key (Customer_ID , VALID_PERIOD)
)

我有来自另一个表“OtherTable”的以下记录,我需要复制到 TemporalTable_1

客户ID |客户名称 |有效周期开始 | Valid_Period_end ------------------+------------------------+-------- -----------------+------------------------ 00001 |约翰·陈 | 2020 年 6 月 1 日 00:00:00 | 2020 年 6 月 9 日 23:59:59 00001 |强尼陈 | 2020 年 6 月 10 日 00:00:00 |空值

以下是我的脚本:

insert into TemporalTable_1 select * from OtherTable;

ORA-00001:违反了唯一约束 (TemporalTable_1)

在执行插入语句之前,表是空白的。所以我的问题是为什么我不允许将行复制到 TemporalTable_1 即使行有不同的valid_period。

是不是因为Oracle其实并不关心主键上的有效期列?

提前致谢!

【问题讨论】:

  • 为什么 PK 中有一个空值?这在语义上是什么意思?
  • @OldProgrammer,空值就是空值。但最重要的是它不是因为那里的“null”值,否则,我期待看到“ORA-01400 : cannot insert null into primary key”。
  • @SayanMalakshinov,是的,我愿意。它们看起来都像我的例子。

标签: sql oracle indexing primary-key temporal-tables


【解决方案1】:

可以肯定的是,暂时的有效性还没有配备来本地处理主键等。

SQL> Create table TemporalTable_1 (
  2      Customer_ID number(8),
  3      Customer_name varchar2(100),
  4      valid_period_start timestamp,
  5      valid_period_end timestamp,
  6      period for valid_period(valid_period_start, valid_period_end),
  7      constraint TemporalTable_1_PK primary key (Customer_ID , VALID_PERIOD)
  8  );

Table created.

SQL> select column_name, hidden_column
  2  from   user_tab_cols
  3  where  table_name = 'TEMPORALTABLE_1'
  4  order by column_id;

COLUMN_NAME                    HID
------------------------------ ---
CUSTOMER_ID                    NO
CUSTOMER_NAME                  NO
VALID_PERIOD_START             NO
VALID_PERIOD_END               NO
VALID_PERIOD                   YES 

VALID_PERIOD 列是隐藏的,这意味着我们使用它来协助我们实现该功能所需的查询转换,而不是添加主键。

【讨论】:

  • 嗨康纳!很高兴在这里见到你! :)
【解决方案2】:

期间名称(在您的情况下为 VALID_PERIOD)列仅包含您的期间的 ID。 检查此脚本及其输出:

--drop table TemporalTable purge;
-- formatting for sqlplus:
col periodname for a20;
col constraint_name for a20;
col search_condition_vc for a80;
col valid_period_start for a16;
col valid_period_end   for a16;
col PERIODSTART for a20;
col PERIODEND   for a20;
alter session set nls_timestamp_format='yyyy-mm-dd hh24:mi';
-- end of formatting

Create table TemporalTable (
    Customer_ID number(8),
    Customer_name varchar2(10)
);

alter table TemporalTable add (
    valid_period_start timestamp, 
    valid_period_end   timestamp,
    period for valid_period(valid_period_start, valid_period_end)
);

ALTER TABLE TemporalTable ADD (
    vt_start DATE,
    vt_end DATE,
    PERIOD FOR vt (vt_start, vt_end)
);
-- inserting overlapping records:
insert into TemporalTable
select 1, 'A' , date'2020-01-01', date'2020-01-10', date'2020-01-01', date'2020-01-10' from dual union all
select 1, 'B' , date'2020-01-05', date'2020-01-08', date'2020-01-01', date'2020-01-10' from dual
/
commit;
-- check valid_period and vt hidden columns:
select tt.*,valid_period,vt from TemporalTable tt
/
select * 
from TemporalTable 
       AS OF PERIOD FOR valid_period DATE '2020-01-06'
/
select 
 constraint_name,
 constraint_type,
 search_condition_vc
from user_constraints c 
where table_name='TEMPORALTABLE';

select * from sys.SYS_FBA_PERIOD 
where obj#=(select object_id from user_objects where object_name='TEMPORALTABLE');

如您所见,我添加了 2 个有效期:在您的情况下为 VALID_PERIOD 和 VT。 请注意,隐藏列 VALID_PERIOD 和 VT 仅包含它们的 ID。它们对于表中的所有行都是相同的。此外,在the following presentation by Philipp Salvisberg 中,您可以看到 Oracle 中的 Temporal Validity 还不支持时间完整性约束,而且它甚至不支持对重叠期间的检查。 所以你还不能创建这样的约束。但是您可以阅读此类事情的旧方法(例如,外键约束 START_DATE -> prev(END_DATE) 和 ID 的唯一约束,START_DATE)

输出:

CUSTOMER_ID CUSTOMER_N VALID_PERIOD_STA VALID_PERIOD_END VT_START            VT_END              VALID_PERIOD         VT
----------- ---------- ---------------- ---------------- ------------------- ------------------- ------------ ----------
          1 A          2020-01-01 00:00 2020-01-10 00:00 2020-01-01 00:00:00 2020-01-10 00:00:00    726847999  726848005
          1 B          2020-01-05 00:00 2020-01-08 00:00 2020-01-01 00:00:00 2020-01-10 00:00:00    726847999  726848005



CUSTOMER_ID CUSTOMER_N VALID_PERIOD_STA VALID_PERIOD_END VT_START            VT_END
----------- ---------- ---------------- ---------------- ------------------- -------------------
          1 A          2020-01-01 00:00 2020-01-10 00:00 2020-01-01 00:00:00 2020-01-10 00:00:00
          1 B          2020-01-05 00:00 2020-01-08 00:00 2020-01-01 00:00:00 2020-01-10 00:00:00



CONSTRAINT_NAME      C SEARCH_CONDITION_VC
-------------------- - --------------------------------------------------------------------------------
VALID_PERIOD52D1FF   C (VALID_PERIOD_START < VALID_PERIOD_END) and (VALID_PERIOD > 0)
VT52D205             C (VT_START < VT_END) and (VT > 0)



      OBJ# PERIODNAME                FLAGS PERIODSTART          PERIODEND                 SPARE
---------- -------------------- ---------- -------------------- -------------------- ----------
     89220 VALID_PERIOD                  0 VALID_PERIOD_START   VALID_PERIOD_END
     89220 VT                            0 VT_START             VT_END

https://www.doag.org/formes/pubfiles/5217205/2013-DEV-Philipp_Salvisberg-Multi-temporal_Database_Features_in_Oracle_12c-Praesentation.pdf

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-03
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多