大数跨境
0
0

你知道Oracle还有嵌套表吗?这个号称‘上古神器’的功能,如今是宝刀未老还是已然过时?

你知道Oracle还有嵌套表吗?这个号称‘上古神器’的功能,如今是宝刀未老还是已然过时? 老苏畅谈运维
2025-11-17
4
导读:项目上遇到了一张表,通过pl/sql developer查看其表结构,发现列显示空,一番探究之后发现它是一张嵌

项目上遇到了一张表,通过pl/sql developer查看其表结构,发现列显示空,一番探究之后发现它是一张嵌套表的子表,这种表确实少见,今天来说说oracle的嵌套表。

一、什么是嵌套表?

面对需要存储一对多数据的场景,你是选择创建子表,还是忍受字段冗余?Oracle 提供了一种独特的解决方案——嵌套表,却为何在市面上鲜有踪影?今天,我们将全面剖析这一特性。

简单来说,嵌套表允许你将一个完整的表作为另一个表的列

想象一下经典的「员工-地址」场景。在传统数据库设计中,你至少需要两张表:employees 和 addresses,并通过外键关联。而使用嵌套表,你可以在 employees 表中直接创建一个 address_list 列,这个列的类型就是一个可以存储多条地址记录的「表」。

嵌套表的本质是:在父表的单行记录内,嵌入一个完整的子表数据集合。

二、实战演练:从创建到查询

理论说得再多,不如动手一试。让我们通过一个完整的案例,感受嵌套表的运作方式。

1. 定义类型:构建数据模型的基石

首先,我们需要定义要“嵌套”的数据结构。

-- 1. 创建对象类型:定义单条地址的结构
CREATE TYPE address_type AS OBJECT (
    street      VARCHAR2(100),
    city        VARCHAR2(50),
    province    VARCHAR2(50),
    postal_code VARCHAR2(10)
);
/

-- 2. 创建嵌套表类型:基于对象类型定义一个“表类型”
CREATE TYPE address_list_type AS TABLE OF address_type;
/

2. 创建表:嵌入式的数据模型

接下来,创建包含嵌套表列的主表。

-- 3. 创建主表,其中一列是嵌套表类型
CREATE TABLE employees_nested (
    employee_id   NUMBER PRIMARY KEY,
    name          VARCHAR2(50),
    -- 关键在此:列的数据类型是一个表
    address_list  address_list_type
NESTED TABLE address_list STORE AS employee_addresses_nt;

关键说明:

  • NESTED TABLE ... STORE AS 语句是必须的,它告诉 Oracle 为嵌套表数据分配物理存储空间。
  • employee_addresses_nt 是一个由系统维护的存储表,对用户基本透明。

3. 插入数据:使用构造函数

向嵌套表插入数据需要使用特定的构造函数语法。

-- 插入数据:使用构造函数初始化嵌套表
INSERT INTO employees_nested VALUES (
    1,
    '张三',
    address_list_type(  -- 初始化嵌套表
        address_type('科技园路1号''深圳市''广东省''518000'),  -- 第一条记录
        address_type('中山大道100号''广州市''广东省''510000'-- 第二条记录
    )
);

INSERT INTO employees_nested VALUES (
    2,
    '李四',
    address_list_type(
        address_type('南京路200号''上海市''上海市''200000')
    )
);

COMMIT;

4. 查询数据:解锁嵌套数据的正确姿势

子表是无法单独查询数据的,强行查询会返回错误:ORA-22812:无法参考嵌套表列的存储表;

szr@orcl(2524)> SELECT * FROM EMPLOYEE_ADDRESSES_NT;
SELECT * FROM EMPLOYEE_ADDRESSES_NT
              *
第 1 行出现错误:
ORA-22812: 无法参考嵌套表列的存储表

只能通过主表查看数据,直接 SELECT * 无法直观显示嵌套表内容,可使用 TABLE() 函数进行展平。

szr@orcl(2524)> col address_list for a100;
szr@orcl(2524)> select * from employees_nested;

EMPLOYEE_ID NAME                 ADDRESS_LIST(STREET, CITY, PROVINCE, POSTAL_CODE)
----------- -------------------- ----------------------------------------------------------------------------------------------------
          1 张三                 ADDRESS_LIST_TYPE(ADDRESS_TYPE('科技园路1号''深圳市''广东省''518000'), ADDRESS_TYPE('中山大道1
                                 00号'
'广州市''广东省''510000'))

          2 李四                 ADDRESS_LIST_TYPE(ADDRESS_TYPE('南京路200号''上海市''上海市''200000'))

查询所有员工及其所有地址:

SELECT e.employee_id,
       e.name,
       a.street,
       a.city,
       a.province,
       a.postal_code
FROM   employees_nested e,
       TABLE(e.address_list) a;  -- 关键:将嵌套表展平为关系行

查询结果:

EMPLOYEE_ID
NAME
STREET
CITY
PROVINCE
POSTAL_CODE
1
张三
科技园路1号
深圳市
广东省
518000
1
张三
中山大道100号
广州市
广东省
510000
2
李四
南京路200号
上海市
上海市
200000

查询特定城市的员工:

SELECT e.employee_id, e.name
FROM   employees_nested e,
       TABLE(e.address_list) a
WHERE  a.city = '广州市';

EMPLOYEE_ID NAME
----------- --------------------
          1 张三

嵌套表的特性

查看嵌套表的相关信息(查看dba_nested_tables视图):

select owner,table_name,table_type_owner,table_type_name,parent_table_name,parent_table_column from dba_nested_tables where owner='SZR';

OWNER           TABLE_NAME           TABLE_TYPE_OWNER     TABLE_TYPE_NAME      PARENT_TABLE_NAME    PARENT_TABLE_COLUMN
--------------- -------------------- -------------------- -------------------- -------------------- --------------------
SZR             EMPLOYEE_ADDRESSES_N SZR                  ADDRESS_LIST_TYPE    EMPLOYEES_NESTED     ADDRESS_LIST

嵌套表的列数据无法在user_tab_columns中查到:

szr@orcl(2524)> select owner,table_name,column_name,data_type from dba_tab_columns  where OWNER='SZR' AND TABLE_NAME IN ('EMPLOYEE_ADDRESSES_NT','EMPLOYEES_NESTED');

OWNER           TABLE_NAME           COLUMN_NAME          DATA_TYPE
--------------- -------------------- -------------------- --------------------
SZR             EMPLOYEES_NESTED     EMPLOYEE_ID          NUMBER
SZR             EMPLOYEES_NESTED     NAME                 VARCHAR2
SZR             EMPLOYEES_NESTED     ADDRESS_LIST         ADDRESS_LIST_TYPE

总结

嵌套表作为早期解决方案,其应用场景在很大程度上已经被更灵活、更通用的 JSON 特性所覆盖。Oracle 在 12c(12.1.0.2)版本中引入了对JSON的支持,如果您正在使用 Oracle 19c,那么您已经拥有了一个非常强大且成熟的 JSON 功能集,完全足以应对绝大多数业务场景。

关注我学习更多的数据库知识!

【声明】内容源于网络
0
0
老苏畅谈运维
1234
内容 122
粉丝 0
老苏畅谈运维 1234
总阅读764
粉丝0
内容122