• 理解Oracle Property Graph:以账户转账示例完成图特性最小测试


    Oracle Property Graph 让关系型数据也能用图的方式查询。本文用一组转账数据,走一遍建表、建图、单跳与多跳查询的完整流程,并整理 ORA-40954: unknown label 的常见原因。

    01 | 准备测试表与数据

    建议在空白 schema 中执行。若对象已存在,先手工删除或更换名称。

    CREATE TABLE money_accounts (
    account_id NUMBER CONSTRAINT money_accounts_pk PRIMARY KEY,
    account_name VARCHAR2(50) NOT NULL
    );
    CREATE TABLE money_transfers (
    transfer_id NUMBER CONSTRAINT money_transfers_pk PRIMARY KEY,
    from_account_id NUMBER NOT NULL,
    to_account_id NUMBER NOT NULL,
    amount NUMBER(12,2),
    transfer_time TIMESTAMP,
    CONSTRAINT money_transfer_from_fk
    FOREIGN KEY (from_account_id)
    REFERENCES money_accounts(account_id),
    CONSTRAINT money_transfer_to_fk
    FOREIGN KEY (to_account_id)
    REFERENCES money_accounts(account_id)
    );

    插入 6 个账户:

    INSERT INTO money_accounts VALUES (1, '账户A');
    INSERT INTO money_accounts VALUES (2, '账户B');
    INSERT INTO money_accounts VALUES (3, '账户C');
    INSERT INTO money_accounts VALUES (4, '账户D');
    INSERT INTO money_accounts VALUES (5, '账户E');
    INSERT INTO money_accounts VALUES (6, '账户F');

    构造一条连续转账链,并增加一条捷径:

    快捷路径

    A

    B

    C

    D

    E

    F

    INSERT INTO money_transfers
    VALUES (101, 1, 2, 1000, TIMESTAMP '2026-09-01 09:00:00');
    INSERT INTO money_transfers
    VALUES (102, 2, 3, 900, TIMESTAMP '2026-09-01 10:00:00');
    INSERT INTO money_transfers
    VALUES (103, 3, 4, 800, TIMESTAMP '2026-09-01 11:00:00');
    INSERT INTO money_transfers
    VALUES (104, 4, 5, 700, TIMESTAMP '2026-09-01 12:00:00');
    INSERT INTO money_transfers
    VALUES (105, 5, 6, 600, TIMESTAMP '2026-09-01 13:00:00');
    -- B 直接转到 E,形成另一条路径
    INSERT INTO money_transfers
    VALUES (106, 2, 5, 500, TIMESTAMP '2026-09-01 14:00:00');
    COMMIT;

    02 | 创建属性图

    显式声明两个标签:ACCOUNT 是顶点标签,TRANSFER 是边标签。

    CREATE PROPERTY GRAPH money_graph
    VERTEX TABLES (
    money_accounts
    KEY (account_id)
    LABEL account
    PROPERTIES (
    account_id,
    account_name
    )
    )
    EDGE TABLES (
    money_transfers
    KEY (transfer_id)
    SOURCE KEY (from_account_id)
    REFERENCES money_accounts (account_id)
    DESTINATION KEY (to_account_id)
    REFERENCES money_accounts (account_id)
    LABEL transfer
    PROPERTIES (
    transfer_id,
    amount,
    transfer_time
    )
    );

    未加双引号的标识符会被 Oracle 规范化为大写,因此 LABEL account 可以通过 IS ACCOUNT 匹配。

    03 | 单跳查询

    SELECT *
    FROM GRAPH_TABLE(
    money_graph
    MATCH (a IS ACCOUNT)-[t IS TRANSFER]->(b IS ACCOUNT)
    COLUMNS (
    a.account_id AS source_account,
    a.account_name AS source_name,
    t.amount AS amount,
    b.account_id AS target_account,
    b.account_name AS target_name
    )
    )
    ORDER BY source_account, target_account;

    它应返回 6 条直接转账关系。

    04 | 1~5 跳查询

    SELECT *
    FROM GRAPH_TABLE(
    money_graph
    MATCH (a IS ACCOUNT)-[IS TRANSFER]->{1,5}(b IS ACCOUNT)
    COLUMNS (
    a.account_id AS source_account,
    a.account_name AS source_name,
    b.account_id AS target_account,
    b.account_name AS target_name
    )
    )
    WHERE source_account = 1
    ORDER BY target_account;

    从账户 A 出发,可以匹配到:

    • A→B:1 跳
    • A→B→C:2 跳
    • A→B→C→D:3 跳
    • A→B→C→D→E:4 跳
    • A→B→C→D→E→F:5 跳
    • A→B→E:另一条 2 跳路径
    • A→B→E→F:另一条 3 跳路径

    因此 E 和 F 可能出现多次,因为查询匹配的是“路径”,而不只是去重后的终点。如果只想看可达账户,可以在外层去重:

    SELECT DISTINCT target_account, target_name
    FROM GRAPH_TABLE(
    money_graph
    MATCH (a IS ACCOUNT)-[IS TRANSFER]->{1,5}(b IS ACCOUNT)
    COLUMNS (
    a.account_id AS source_account,
    b.account_id AS target_account,
    b.account_name AS target_name
    )
    )
    WHERE source_account = 1
    ORDER BY target_account;

    05 | ORA-40954 常见原因

    ① 把表名当成标签名

    图定义是 LABEL account,正确匹配是 (a IS ACCOUNT),而不是 (a IS MONEY_ACCOUNTS)。IS 后面填的是 Label,不是底层表名。

    ② 没有显式声明预期标签

    如果图定义没有 LABEL account,却查询 (a IS ACCOUNT),Oracle 就可能找不到该标签。建议在教学和生产 DDL 中显式声明 Label。

    ③ 双引号导致大小写敏感

    若创建时写 LABEL "Account",标签名就是大小写敏感的 Account,查询必须写 (a IS "Account"),(a IS ACCOUNT) 无法匹配。最佳实践是标签不使用双引号。

    ④ 标签存在,但元素类型用错

    TRANSFER 只定义在边上,却写成 (a IS TRANSFER);或 ACCOUNT 只定义在顶点上,却写成 -[e IS ACCOUNT]->,都会出现标签无法用于当前位置的问题。

    快速定位是哪一个标签有问题

    先单独测试顶点标签:

    SELECT *
    FROM GRAPH_TABLE(
    money_graph
    MATCH (a IS ACCOUNT)
    COLUMNS (a.account_id AS account_id)
    );

    再单独测试边标签:

    SELECT *
    FROM GRAPH_TABLE(
    money_graph
    MATCH (a)-[t IS TRANSFER]->(b)
    COLUMNS (t.transfer_id AS transfer_id)
    );

    第一个失败说明 ACCOUNT 标签有问题;第二个失败说明 TRANSFER 标签有问题。

    关注我,和AI一起成长~

  • 相关阅读:
    维度转换的艺术:Kylin Cube设计的自定义魔法
    【毕业设计】远程智能浇花灌溉系统 - stm32 单片机 嵌入式 物联网
    springboot(ssm 经方药食两用服务平台 Java(code&LW)
    linux-crontab每分钟定时执行/定时任务调度
    设置Oracle数据库默认为spfle启动,并且设置数据库SGA大小和PGA大小
    Django和jQuery,实现Ajax表格数据分页展示
    写一个简单的网站步骤
    Sping源码(九)—— Bean的初始化(非懒加载)— doGetBean
    LLVM 文档收集
    docker常用命令与jenkins安装
  • 原文地址:https://www.cnblogs.com/jyzhao/p/22953898