Oracle PL/SQL 中自定义生成的 ID/序列? [复制]

Posted

技术标签:

【中文标题】Oracle PL/SQL 中自定义生成的 ID/序列? [复制]【英文标题】:Custom Generated ID/Sequence in Oracle PL/SQL? [duplicate] 【发布时间】:2020-11-11 12:12:12 【问题描述】:

我有一个客户要求,需要每天唯一的 ID。我正在开发 Oracle 12c。

在这种情况下,表 (Client_Doc) 的结构如下:

Doc_ID (PK), Date(PK), Doc_Description, Other_Columns

样本数据如下:

Value_Date   Doc_ID   Doc_Description
01-11-2020   1        Test Doc
01-11-2020   2        User Info
01-11-2020   3        Customer Doc
02-11-2020   1        Live
02-11-2020   2        Region
03-11-2020   1        Test

所以如果我想生成 ID,我可以这样做:

SELECT NVL(MAX(Doc_ID), 0) + 1 
INTO V_ID
FROM Client_Doc
WHERE Value_Date = :P_DATE;

但由于脏读和大量表行的性能问题,这不是一个好的做法,并且由于要求也不能使用序列。满足要求的最佳方法是什么?

【问题讨论】:

如果您在任何给定日期允许在 DOC_ID 中出现空白,则在此处提出并回答了几乎相同的问题:***.com/q/38913246/5174436 【参考方案1】:

生成单个主键列(从序列或作为标识生成),然后使用ROW_NUMBER 分析函数创建一个生成复合键的视图:

CREATE TABLE client_doc (
  ID              INT
                  GENERATED ALWAYS AS IDENTITY
                  CONSTRAINT client_doc__id__pk PRIMARY KEY,
  Value_Date      DATE
                  NOT NULL,
  Doc_Description VARCHAR2(50)
);

CREATE VIEW client_doc_view ( id, value_date, doc_id, doc_description ) AS
SELECT id,
       value_date,
       ROW_NUMBER() OVER ( PARTITION BY value_date ORDER BY id ),
       doc_description
FROM   client_doc;

INSERT INTO client_doc ( value_date, doc_description )
SELECT DATE '2020-11-01', 'Test Doc'     FROM DUAL UNION ALL
SELECT DATE '2020-11-01', 'User Info'    FROM DUAL UNION ALL
SELECT DATE '2020-11-01', 'Customer Doc' FROM DUAL UNION ALL
SELECT DATE '2020-11-02', 'Live'         FROM DUAL UNION ALL
SELECT DATE '2020-11-02', 'Region'       FROM DUAL UNION ALL
SELECT DATE '2020-11-03', 'Test'         FROM DUAL;

然后,视图包含:

SELECT *
FROM   client_doc_view;
身份证 | VALUE_DATE |文档 ID |文档描述 -: | :--------- | -----: | :-------------- 1 | 20 年 11 月 1 日 | 1 |测试文件 2 | 20 年 11 月 1 日 | 2 |用户信息 3 | 20 年 11 月 1 日 | 3 |客户文件 4 | 20 年 11 月 2 日 | 1 |居住 5 | 20 年 11 月 2 日 | 2 |地区 6 | 20 年 11 月 3 日 | 1 |测试

然后,当您想向客户显示数据时,您可以向他们显示value_datedoc_id 的复合数据,但在后台您有一个唯一的列可用于由序列支持的连接和外键。

db小提琴here

【讨论】:

似乎必须做出很多假设才能确保安全。例如,不允许对表进行删除(否则它们会更改所有后续行的标识符)。 @MatthewMcPeak 见最后一段,这只是为了展示;所有引用约束都应该在主键上完成。 谢谢 - 这是有道理的。不过,我不会删除我的评论,因为我认为这是一个重要的压力点。此“密钥”的系统外使用仍可能导致错误。例如,用户查看显示的记录并认为“我需要调查和编辑第 01-NOV-20 / 2 行”。后来,他们回来进行编辑。如果他们查询 01-NOV-20 / 2 进行编辑,他们可能会犯错误。 (这也是我一直提倡将用户的大脑物理连接到系统中的部分原因,但我不断遭到反对)。 @MT0 mate 不幸的是,它不仅用于显示目的,而且 ROW_NUMBER() OVER ( PARTITION BY value_date ORDER BY id ) 将对超过 10M 的记录产生性能问题... @NafiPantha 你追求的东西并不真正存在。您希望将序列分区到另一列,但这样的结构不存在,并且您不想使用MAX,因为它不处理并行插入,并且您希望使用的任何解决方案都具有高性能......不会找到东西,因为它不存在。我试图提供一个替代方案,如果这还不够好,那么您可能会陷入困境,应该与客户讨论需求并要求他们更改需求。或者,您可以使用 MatthewMcPeak 对您的回答的评论。【参考方案2】:

当您使用 12c 时,请使用身份列。这是一个例子:

SQL> create table client_doc
  2    (doc_id  number generated always as identity,
  3     datum   date,
  4     doc_description varchar2(20),
  5     --
  6     constraint pk_clidoc primary key (doc_id, datum)
  7    );

Table created.

SQL> insert into client_doc (datum, doc_description) values (sysdate, 'Test');

1 row created.

SQL> select * From client_doc;

    DOC_ID DATUM    DOC_DESCRIPTION
---------- -------- --------------------
         1 11.11.20 Test

SQL>

【讨论】:

以上是关于Oracle PL/SQL 中自定义生成的 ID/序列? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 的用户自定义聚合函数可以定义为与两列一起使用吗?

在 PL/SQL Developer 中转义 & 符号

生成.txt文件并插入到oracle表pl/sql中

如何生成uuid oracle

从 Oracle PL/SQL 中的表生成 json 文件

自定义安装office