Oracle 数据库 23ai 新特性: Schema Annotations
Data Use Case Domain (数据用例域)和 Schema Annotation 都属于 Application Data Usage 的范畴。但Data Use Case Domain比Schema Annotation要简单得多,也重要得多。因此我们先讲解简单的。
本文介绍23ai的新特性,Schema Annotation,简称Annotation,中文为标注。
分为两部分,第一部分来自Database Concepts,讲概念;第二部分来自Database Development Guide,讲语法。
Database Concepts - Schema Annotations
对于许多应用程序来说,维护数据库对象(例如表、视图、表列、索引和域)的附加属性元数据非常重要。
虽然域包括内置使用属性(例如检查约束、排序规则、自定义排序顺序等),但为了实现可扩展性,Oracle 数据库还提供了通过 ANNOTATIONS 机制为数据库元数据(包括表列、表、索引等)添加自定义属性的功能。应用程序通常需要维护附加属性元数据,尤其是为了呈现用户界面或自定义应用程序逻辑。
列级使用属性的一些示例包括:
- 显示标签:这可能与列名不同(例如,显示名为 Employee_Salary 的列的标题“Salary”)
- 列组:在许多情况下,列“组”对于用户界面来说很重要(例如,将街道号、街道名称、城市和邮政编码列分组到地址组中)
- 格式掩码:例如,用户界面工具可以使用 $99,999.99 的显示掩码将 56434 呈现为 $56,434.00
- 隐藏:是否在用户界面中向最终用户显示列(例如,不向某一类最终用户显示包含敏感信息的列或系统添加的列)
- 突出显示:是否应使用特殊突出显示显示列
- 允许的操作:允许界面确定是否允许列支持排序、分组、显示值列表等。
表级使用属性同样可用于帮助应用程序记录表是否包含敏感信息、其显示名称应为什么、该表由应用程序中的哪些模块拥有或管理等。
大多数应用程序都会为此类使用元数据创建自己的存储库,从而增加开发人员的复杂性,并可能在应用程序、模块和微服务之间产生分歧(不一致性)。
Oracle 数据库模式标注是一种轻量级声明工具,开发人员可借此集中注册数据库模式对象的使用属性。标注与数据模型定义和数据本身一起直接存储在数据库内的字典表中,可供任何应用程序使用,以标准化通用数据的行为,但数据库不会以任何方式对其进行解释。它们应被视为数据库元数据的轻量级标准化标记,供应用程序用于注册和处理扩展和自定义使用属性。
Database Development Guide: 10.2 Schema Annotations
schema annotation,简称annotation。中文建议翻译为“标注”,以与表和列的comment(注释)区分。
对于许多应用程序来说,维护数据库对象(例如表、视图、表列、索引和域)的附加属性元数据非常重要。注释使您的应用程序能够存储和检索有关数据库对象和表列的附加用户特定元数据。应用程序可以使用此类元数据来帮助呈现有效的用户界面并自定义应用程序逻辑。
标注概述
标注是一种轻量级声明性工具,开发人员可以通过它集中注册数据库架构对象的使用属性。标注存储在字典表中,可供任何希望标准化相关应用程序中通用数据行为的应用程序使用。数据库不会以任何方式解释标注。它们是数据库元数据的自定义数据属性 - 包括表列、表和索引,应用程序可以将其用作附加属性元数据来呈现用户界面或自定义应用程序逻辑。
标注是一种在数据库中集中定义和存储应用程序元数据的机制,它使您能够跨应用程序、模块和微服务共享元数据信息。您可以在创建新对象(使用 CREATE 语句)或修改现有对象(使用 ALTER 语句)时向架构对象添加标注。
使用元数据标注数据模型提供了额外的数据完整性、一致性和数据模型文档优势。您的应用程序可以存储数据库对象和表列的用户定义元数据,其他应用程序或用户可以检索和使用。将元数据与数据一起存储可确保一致性和对使用数据的任何用户或应用程序的通用可访问性。
单个标注具有名称和可选值。名称和可选值是自由格式的文本字段。例如,您可以有一个具有名称和值对的标注,例如 Display_Label ‘Employee Salary’,或者您可以有一个仅具有名称的独立标注,例如 UI_Hidden,它不需要值,因为名称是不言自明的。
以下是有关标注的更多详细信息。
- 使用 CREATE DDL 语句为架构对象指定标注名称时,将自动创建标注。
- 标注是累加的,这意味着您可以为同一个架构对象指定多个标注。
- 您可以使用单个 DDL 语句一次向架构对象添加多个标注。同样,单个 DDL 语句可以从架构对象中删除多个标注。
- 标注表示为添加标注的数据库对象的从属元素。标注不会在数据库内创建新的对象类型。
- 只要您拥有或拥有架构对象的更改权限,您就可以向支持标注的任何架构对象添加标注。您不需要对标注名称进行架构限定。
- 您可以在字典视图上发出 SQL 查询以获取所有标注,包括它们的名称和值,以及它们与架构对象的用法。
标注与注释
您还可以使用 COMMENT 命令注释数据库对象(例如表和表列)。与架构对象关联的注释与对象的元数据一起存储在数据字典中。
标注比注释更易于使用且范围更广。以下是标注和注释之间的主要区别:
- 注释是一种机制,用于将元数据仅添加到某些架构对象(例如表和列)。注释不适用于其他架构对象,例如索引、过程、触发器和域。
- 注释没有名称,只有自由格式的值。
- 注释不是累加的,这意味着您不能为同一对象添加多个注释。指定新注释将覆盖相应表或列的先前注释。
- 您需要为注释使用单独的 DDL 语句,而您可以将多个标注组合成一个 DDL 语句。
- 不同的实体有一组单独的字典视图。例如,有一个用于表注释的视图,另一个用于列注释的视图。而标注在所有对象类型中都是统一的,这使其更易于查询和使用。
支持的数据库对象
以下数据库对象支持标注。
- 表和表列
- 视图和视图列
- 物化视图和物化视图列
- 索引
- 域和多列域列
使用标注所需的权限
要添加或删除标注,您需要对在 CREATE 或 ALTER DDL 语句中指定标注的架构对象具有 CREATE 或 ALTER 权限。
您无法明确创建或删除标注。标注在首次使用时会自动创建。由于标注作为从属元素存储在定义它们的数据库对象中,因此添加标注不会在数据库内创建新的对象类型。
标注的 DDL 语句
本节解释标注语法并提供用于定义或更改表、表列、视图、物化视图、索引和域的标注的 DDL 语句。
标注的语法
以下是详细的语法:
annotations
::= 'ANNOTATIONS' '(' annotations_list ')'
annotations_list
::= ( 'ADD' ('IF NOT EXISTS' | 'OR REPLACE' )? | 'DROP' 'IF EXISTS'? | REPLACE)?
annotation ( ',' ( 'ADD' ('IF NOT EXISTS' | 'OR REPLACE' )? | 'DROP' 'IF EXISTS'? | REPLACE)?
annotation )*
annotation
::= annotation_name annotation_value?
annotation_name
::= identifier
annotation_value
::= character_string_literal
<annotation_value> 是一个字符串常量值(literal),最多可容纳 4000 个字符。
<annotation_name> 是一个标识符,具有以下要求:
- 标识符最多可包含 1024 个字符。
- 如果标识符是保留字,则必须在双引号中提供注释名称。
- 带双引号的标识符可以包含空格字符。
- 不允许使用仅包含空格字符的标识符。
用于标注表的 DDL 语句
使用 CREATE TABLE 语句:
CREATE TABLE Table1 (
T NUMBER)
ANNOTATIONS(Operations '["Sort", "Group"]', Hidden);
-- ADD 是默认隐含操作,可以省略
CREATE TABLE Table2 (
T NUMBER)
ANNOTATIONS (ADD Hidden);
使用 ALTER TABLE 语句:
ALTER TABLE Table1
ANNOTATIONS(DROP Operations, DROP Hidden);
ALTER TABLE Table1
ANNOTATIONS(ADD JoinOperations 'Join', DROP Hidden);
可以在一个 DDL 语句中指定多个 ADD 和 DROP 关键字。
尝试为同一对象(对于对象级标注)或同一列(对于列级标注)重新添加具有不同值的标注会引发错误。
SQL>
ALTER TABLE Table1 ANNOTATIONS(ADD JoinOperations 'Join Ops');
ALTER TABLE Table1
*
ERROR at line 1:
ORA-11552: Annotation name 'JOINOPERATIONS' already exists for the object
'TABLE1'.
Help: https://docs.oracle.com/error-help/db/ora-11552/
作为替代方案,注释语法允许您使用 REPLACE 关键字替换注释值。以下语句将 JoinOperations 的值替换为“Join Ops”:
ALTER TABLE Table1
ANNOTATIONS(REPLACE JoinOperations 'Join Ops');
或者,为了避免注释已存在时出现错误,您可以使用 IF NOT EXISTS 子句。以下语句仅在不存在 JoinOperations 注释时才添加它。如果注释存在,则注释值保持不变,不会引发任何错误。
ALTER TABLE Table1
ANNOTATIONS(ADD IF NOT EXISTS JoinOperations 'Join Ops');
类似地,删除不存在的标注会引发错误:
SQL> ALTER TABLE Table1 ANNOTATIONS(DROP Title);
ALTER TABLE Table1 ANNOTATIONS(DROP Title)
*
ERROR at line 1:
ORA-11553: Annotation name 'TITLE' does not exist for the object 'TABLE1'.
Help: https://docs.oracle.com/error-help/db/ora-11553/
为了避免错误,可以使用 IF EXISTS 子句,如下所示:
ALTER TABLE Table1
ANNOTATIONS(DROP IF EXISTS Title);
用于标注表列的 DDL 语句
和表的类似,只是位置不同。
使用 CREATE TABLE 语句:
CREATE TABLE Table1
(T NUMBER ANNOTATIONS(Operations 'Sort', Hidden));
CREATE TABLE Table2
(T NUMBER ANNOTATIONS (Hidden));
使用 ALTER TABLE 语句:
ALTER TABLE Table1
MODIFY T ANNOTATIONS(Identity 'ID');
ALTER TABLE Table1
MODIFY T ANNOTATIONS(ADD Label, DROP Identity);
用于标注视图和物化视图的 DDL 语句
略。
用于标注索引的 DDL 语句
略。
用于标注域的 DDL 语句
这一部分建议了解了Domain的概念后再看。
您可以使用以下 DDL 语句来注释域。
您可以在域级别或列级别为域指定注释。在域上定义的注释将继承到引用该域的对象。注释仅适用于常规域,而不允许用于灵活域。
要为单列域指定域级注释,需要使用带括号的语法(用于多列域)来区分列级和对象级注释。否则,单列域的注释将被视为列级。
使用 CREATE DOMAIN 语句
以下示例通过为单列域指定列级标注来创建域标注。
CREATE DOMAIN dept_codes_1 AS NUMBER(3)
CONSTRAINT dept_chk_1 CHECK (dept_codes_1 > 99 AND dept_codes_1 != 200)
ANNOTATIONS (Title 'Column level annotation');
以下示例为单列域指定域级标注。这需要使用多列域的域语法(列用括号括起来)。
CREATE DOMAIN dept_codes_2 AS (
code AS NUMBER(3)
CONSTRAINT dept_chk_2 CHECK (code > 99 AND code != 200))
ANNOTATIONS (Title 'Domain Annotation');
CREATE DOMAIN HourlyWages AS Number(10)
DEFAULT ON NULL 15
CONSTRAINT MinimalWage CHECK (HourlyWages > = 7 and HourlyWages <=1000) ENABLE
DISPLAY TO_CHAR(HourlyWages, '$999.99')
ORDER ( -1*HourlyWages )
ANNOTATIONS (Title 'Column level annotation');
以下示例创建一个多列域,并在列和域级别带有标注。
CREATE DOMAIN US_City AS (
name AS VARCHAR2(50) ANNOTATIONS (Address),
state AS VARCHAR2(50) ANNOTATIONS (Address),
zip AS NUMBER ANNOTATIONS (Address)
)
CONSTRAINT City_CK CHECK(state in ('CA','AZ','TX') and zip < 100000)
DISPLAY name || ', ' || state || ' , ' || TO_CHAR(zip)
ORDER state || ', ' || TO_CHAR(zip) || ', ' || name
ANNOTATIONS (Title 'Domain Annotation');
使用 ALTER DOMAIN 语句
可以使用 ALTER 语句修改对象级标注。无法更改域的列级标注。只有删除域并重新创建新域,才能删除之前添加的列级标注。
以下示例更改了 dept_codes_2 域的域级注释。
ALTER DOMAIN dept_codes_2
ANNOTATIONS(DROP Title, ADD Name 'Domain');
字典表和视图
名为 ANNOTATIONS_USAGE$ 的字典表包含标注与架构对象(例如表和视图)的所有用法。当为架构对象指定新的标注名称、值或两者时,将在 ANNOTATIONS_USAGE$ 表中创建一个新条目。同样,当架构对象删除标注时,相应的条目将从 ANNOTATIONS_USAGE$ 表中删除。
以下字典视图跟踪标注列表及其在所有架构对象中的使用情况:
- {DBA|USER|ALL|CDB}_ANNOTATIONS:所有标注的名字
- {DBA|USER|ALL|CDB}_ANNOTATIONS_USAGE:最常用,标注的名字和值
- {DBA|USER|ALL|CDB}_ANNOTATIONS_VALUES:没找到,可能我23ai版本不够
获取表级标注
SELECT * FROM USER_ANNOTATIONS_USAGE
WHERE Object_Type = 'TABLE'
AND Column_Name IS NULL;
获取列级标注
SELECT * FROM USER_ANNOTATIONS_USAGE
WHERE Object_Type = 'TABLE'
AND Column_Name IS NOT NULL;
要获取“EMP”表的列级注释作为每列的单个 JSON 集合
SELECT U.Column_Name, JSON_ARRAYAGG(JSON_OBJECT(U.Annotation_Name, U.Annotation_Value))
FROM USER_ANNOTATIONS_USAGE U
WHERE Object_Name = 'EMPLOYEE' AND Object_Type = 'TABLE' AND Column_Name IS NOT NULL
GROUP BY Column_Name;
参考
- Schema Annotations - the new metadata
https://blogs.oracle.com/coretec/post/oracle-database-23c-free-developer-sql