即使你的问题很模糊,也很有趣。我会尽量给你一个可能的解释。
A||','||B 是唯一的,如果您可以保证对于 (A,B) 的 2 个不同值,函数 A||','||B 不会返回相同的值。
您需要保证 TO_CHAR(A) ||','|| TO_CHAR(B) 是唯一的。
- 我正在考虑 A 和 B 不是 NULL。
- 如果 A 和 B 是 VARCHAR,A||','||B 是唯一的,但如果您有 DATE 或 TIMESTAMP 数据类型,则情况并非如此。这不是 TRUE,因为 TO_CHAR 函数的默认参数取决于会话中的 nls_parameters。
测试用例 - 执行相同的查询,但更改 nls_date_format 并尝试创建唯一索引
drop table test;
create table test (a DATE, b VARCHAR2(10), C VARCHAR2(10));
alter session set nls_date_format= 'dd/mm/yyyy hh24:mi:ss';
drop index test;
truncate table test;
insert into test(a,b,c) values(sysdate+(1/60),'1','c1');
insert into test(a,b,c) values(sysdate+(1/160),'1','c1');
insert into test(a,b,c) values(sysdate+(1/80),'2','c2');
insert into test(a,b,c) values(sysdate+(1/180),'2','c2');
commit;
create unique index test on test (case when c is not null then a||','||b||','||c end);
select (case when c is not null then a||','||b||','||c end) valfn from test order by B;
alter session set nls_date_format= 'dd/mm/yyyy';
truncate table test;
drop index test;
insert into test(a,b,c) values(sysdate+(1/60),'1','c1');
insert into test(a,b,c) values(sysdate+(1/160),'1','c1');
insert into test(a,b,c) values(sysdate+(1/80),'2','c2');
insert into test(a,b,c) values(sysdate+(1/180),'2','c2');
create unique index test on test (case when c is not null then a||','||b||','||c end);
select (case when c is not null then a||','||b||','||c end) valfn from test order by B;
使用 nls_date_format= 'dd/mm/yyyy hh24:mi:ss' 输出
Index TEST created.
VALFN
------------------------
15/05/2021 08:40:35,1,c1
15/05/2021 08:25:35,1,c1
15/05/2021 08:34:35,2,c2
15/05/2021 08:24:35,2,c2
使用 nls_date_format= 'dd/mm/yyyy' 输出
ORA-01452: cannot CREATE UNIQUE INDEX; duplicate keys found
VALFN
---------------
15/05/2021,1,c1
15/05/2021,1,c1
15/05/2021,2,c2
15/05/2021,2,c2
然后我们可以看到创建索引时发生了什么。我们将查询索引定义来解释这种行为。
使用 nls_date_format= 'dd/mm/yyyy hh24:mi:ss' 输出
alter session set nls_date_format= 'dd/mm/yyyy hh24:mi:ss';
drop table test;
create table test (a DATE, b VARCHAR2(10), C VARCHAR2(10));
create unique index test on test (case when c is not null then a||','||b||','||c end);
select index_name, column_expression from all_ind_expressions where table_name = 'TEST'
INDEX_NAME COLUMN_EXPRESSION
---------- ---------------------------------------------------------------------------------------------
TEST CASE WHEN "C" IS NOT NULL THEN TO_CHAR("A",'dd/mm/yyyy hh24:mi:ss')||','||"B"||','||"C" END
使用 nls_date_format= 'dd/mm/yyyy' 输出
alter session set nls_date_format= 'dd/mm/yyyy';
drop table test;
create table test (a DATE, b VARCHAR2(10), C VARCHAR2(10));
create unique index test on test (case when c is not null then a||','||b||','||c end);
select index_name, column_expression from all_ind_expressions where table_name = 'TEST'
INDEX_NAME COLUMN_EXPRESSION
---------- ----------------------------------------------------------------------------------
TEST CASE WHEN "C" IS NOT NULL THEN TO_CHAR("A",'dd/mm/yyyy')||','||"B"||','||"C" END
如您所见,索引并不相同,因为它取决于您创建索引时的 nls_date_format。我总是建议验证 Oracle 在创建对象时使用的表达式。
创建虚拟列时也是这样
alter session set nls_date_format= 'dd/mm/yyyy hh24:mi:ss';
drop table test;
create table test (a DATE, b VARCHAR2(10), C VARCHAR2(10)
,idx varchar2(50) generated always as (case when c is not null then a||','||b||','||c end) virtual
);
select DATA_DEFAULT from all_tab_cols where table_name = 'TEST' and column_name = 'IDX';
DATA_DEFAULT
---------------------------------------------------------------------------------------------
CASE WHEN "C" IS NOT NULL THEN TO_CHAR("A",'dd/mm/yyyy hh24:mi:ss')||','||"B"||','||"C" END
alter session set nls_date_format= 'dd/mm/yyyy';
drop table test;
create table test (a DATE, b VARCHAR2(10), C VARCHAR2(10)
,idx varchar2(50) generated always as (case when c is not null then a||','||b||','||c end) virtual
);
select DATA_DEFAULT from all_tab_cols where table_name = 'TEST' and column_name = 'IDX';
DATA_DEFAULT
----------------------------------------------------------------------------------
CASE WHEN "C" IS NOT NULL THEN TO_CHAR("A",'dd/mm/yyyy')||','||"B"||','||"C" END
现在,您可以将 C 添加到此等式并验证您的情况的原因:CASE WHEN C IS NOT NULL THEN A||','||B||','||C END is not unique
大多数时候,默认情况下 nls_date_format 不包括时间。