Oracle:带有日期列的复合唯一键
Oracle: Composite unique key with Date column
我创建了一个 table 复合唯一键如下--
create table test11
(
aa number,
bb varchar2(10),
cc DATE,
dd number,
ee NUMBER
);
CREATE UNIQUE INDEX TEST11_IDX ON TEST11 (AA,BB,CC);
现在,每当我尝试插入数据时,都会收到此错误:
ORA-00001: unique constraint (CDUREFDB.TEST11_IDX) violated
INSERT INTO TEST11 VALUES (1, 'AA', SYSDATE, 1, 1);
commit;
INSERT INTO TEST11 VALUES (1, 'AA', SYSDATE, 1, 1);
commit;
那是因为 DATE
列正在考虑 Date
秒之前的值吗?
因为我可以看到下面的查询返回的是结果--
select to_char(CC,'DD-Mon-YY HH:Mi:SS AM') from test11;
TO_CHAR(CC,'DD-MON-YYHH:MI:SSAM')
---------------------------------
17-Mar-16 04:28:37 PM
17-Mar-16 04:28:43 PM
那么,为了仅将日期值(而不是小时、分钟、秒精度)视为唯一键成员,可以做些什么。
此外,上面的 DATE
列 (CC) 上有分区。
更新::
在此 table 中,我们在 DATE 列 (CC) 上有 RANGE 分区。
并且我们计划定期删除分区(即每隔几天)。
因此,如果我不在唯一索引中使用直接 CC(而不是像 Justin 建议的那样制作 trunc),那么如果我尝试在一些旧分区被删除后插入数据,我会收到 ORA-01502: index 'CDUREFDB.TEST111_IDX' or partition of such index is in unusable state
错误。
UPDATE_1
根据下面的@Justin 建议,此问题已解决,创建如下所示的虚拟列:
CREATE TABLE TEST11
(
AA NUMBER,
BB VARCHAR2(10),
CC DATE,
DD NUMBER ,
EE NUMBER,
FF DATE generated always AS (TRUNC(CC)) virtual
)
PARTITION BY RANGE
(
FF
)
INTERVAL
(
NUMTODSINTERVAL(1,'DAY')
)
(
PARTITION partition_test_1 VALUES LESS THAN (TO_DATE('01-APR-2006','dd-MON-yyyy'))
);
CREATE UNIQUE INDEX TEST111_IDX ON TEST11 (AA,BB,FF) LOCAL; -- creating unique local index
A date
总是有一个时间部分,所以你的两行有不同的 cc
值。您可以根据 trunc(cc)
值创建一个基于函数的索引,这会将时间组件设置为午夜。
CREATE UNIQUE INDEX TEST11_IDX
ON TEST11 (AA,BB,trunc(CC));
当然,这意味着如果您希望查询使用索引,您需要确保您的谓词在 trunc(cc)
而不是 cc
.
我创建了一个 table 复合唯一键如下--
create table test11
(
aa number,
bb varchar2(10),
cc DATE,
dd number,
ee NUMBER
);
CREATE UNIQUE INDEX TEST11_IDX ON TEST11 (AA,BB,CC);
现在,每当我尝试插入数据时,都会收到此错误:
ORA-00001: unique constraint (CDUREFDB.TEST11_IDX) violated
INSERT INTO TEST11 VALUES (1, 'AA', SYSDATE, 1, 1);
commit;
INSERT INTO TEST11 VALUES (1, 'AA', SYSDATE, 1, 1);
commit;
那是因为 DATE
列正在考虑 Date
秒之前的值吗?
因为我可以看到下面的查询返回的是结果--
select to_char(CC,'DD-Mon-YY HH:Mi:SS AM') from test11;
TO_CHAR(CC,'DD-MON-YYHH:MI:SSAM')
---------------------------------
17-Mar-16 04:28:37 PM
17-Mar-16 04:28:43 PM
那么,为了仅将日期值(而不是小时、分钟、秒精度)视为唯一键成员,可以做些什么。
此外,上面的 DATE
列 (CC) 上有分区。
更新::
在此 table 中,我们在 DATE 列 (CC) 上有 RANGE 分区。
并且我们计划定期删除分区(即每隔几天)。
因此,如果我不在唯一索引中使用直接 CC(而不是像 Justin 建议的那样制作 trunc),那么如果我尝试在一些旧分区被删除后插入数据,我会收到 ORA-01502: index 'CDUREFDB.TEST111_IDX' or partition of such index is in unusable state
错误。
UPDATE_1 根据下面的@Justin 建议,此问题已解决,创建如下所示的虚拟列:
CREATE TABLE TEST11
(
AA NUMBER,
BB VARCHAR2(10),
CC DATE,
DD NUMBER ,
EE NUMBER,
FF DATE generated always AS (TRUNC(CC)) virtual
)
PARTITION BY RANGE
(
FF
)
INTERVAL
(
NUMTODSINTERVAL(1,'DAY')
)
(
PARTITION partition_test_1 VALUES LESS THAN (TO_DATE('01-APR-2006','dd-MON-yyyy'))
);
CREATE UNIQUE INDEX TEST111_IDX ON TEST11 (AA,BB,FF) LOCAL; -- creating unique local index
A date
总是有一个时间部分,所以你的两行有不同的 cc
值。您可以根据 trunc(cc)
值创建一个基于函数的索引,这会将时间组件设置为午夜。
CREATE UNIQUE INDEX TEST11_IDX
ON TEST11 (AA,BB,trunc(CC));
当然,这意味着如果您希望查询使用索引,您需要确保您的谓词在 trunc(cc)
而不是 cc
.