AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 196969
Accepted
Narann
Narann
Asked: 2018-02-04 06:18:55 +0800 CST2018-02-04 06:18:55 +0800 CST 2018-02-04 06:18:55 +0800 CST

条件表参考

  • 772

我有一张桌子tree:

+------+-------+
| id   | name  |
+------+-------+
| 0    | tree1 |
| 1    | tree2 |
| 2    | tree3 |
| 3    | tree4 |
+------+-------+

一张桌子pen:

+------+------+
| id   | name |
+------+------+
| 0    | pen1 |
| 1    | pen2 |
| 2    | pen3 |
| 3    | pen4 |
+------+------+

第三个表task将任务“附加”到树或笔:

+------+------+-------+
| type | id   | name  |
+------+------+-------+
| 0    | 1    | foo   |
| 0    | 2    | bar   |
| 1    | 1    | fee   |
| 1    | 2    | beer  |
+------+------+-------+

当type为 0 时,表示id引用 a tree。当type为 1 时,它引用 a pen(以此类推许多不同的表)。

我怎样才能做到这一点并确保参照完整性?

postgresql referential-integrity
  • 2 2 个回答
  • 1017 Views

2 个回答

  • Voted
  1. Fabrizio Caldarelli
    2018-02-04T06:54:01+08:002018-02-04T06:54:01+08:00

    创建一个表任务,为每个被引用的表添加一个引用 id 字段,以这种方式:

    • 类型:我更喜欢“树”、“笔”之类的东西。为此使用枚举:ENUM('tree', 'pen');
    • tree_id : int(可以为NULL),表示树表;
    • pen_id : int(可以为NULL),表示笔表;
    • 名称:可变字符;

    部分测试数据:

    +------+---------+--------+-------+
    | type | tree_id | pen_id | name  |
    +------+---------+--------+-------+
    | tree | 1       | NULL   | foo   |
    | tree | 2       | NULL   | bar   |
    | pen  | NULL    | 1      | fee   |
    | pen  | NULL    | 2      | beer  |
    +------+---------+--------+-------+
    
    • 2
  2. Best Answer
    McNets
    2018-02-04T10:05:33+08:002018-02-04T10:05:33+08:00

    我会为任务树建议一个桥接表,为任务笔建议另一个桥接表。

    create table tree 
    (
        tree_id int primary key,
        name text
    );
    
    create table pen
    (
        pen_id int primary key,
        name text
    );
    
    create table task
    (
        task_id int primary key,
        name text
    );
    
    create table task_tree
    (
        task_id int references task (task_id) on update cascade,
        tree_id int references tree (tree_id) on update cascade, 
        primary key (task_id, tree_id)
    );
    
    create table task_pen
    (
        task_id int references task (task_id) on update cascade,
        pen_id int references pen (pen_id) on update cascade,
        primary key (task_id, pen_id)
    );
    
    insert into tree values (1, 'tree1'),(2, 'tree2'),(3, 'tree3');
    insert into pen values (1, 'pen1'),(2, 'pen2'),(3, 'pen3');
    insert into task values (1, 'task1'),(2, 'task2');
    insert into task_tree values (1, 1),(2, 3),(1,2);
    insert into task_pen values (1, 2),(2, 2);
    
    select   tk.task_id, 
             tk.name, 
             array_agg(tr.name) as tree, 
             array_agg(pn.name) as pen
    from     task tk
    join     task_tree tkt
    on       tkt.task_id = tk.task_id
    join     task_pen tkp
    on       tkp.task_id = tk.task_id
    join     tree tr
    on       tr.tree_id = tkt.tree_id
    join     pen pn
    on       pn.pen_id = tkp.pen_id
    group by tk.task_id, tk.name
    
    任务编号 | 姓名 | 树 | 笔        
    ------: | :---- | :------------ | :------------
          1 | 任务 1 | {tree1,tree2} | {pen2,pen2}
          2 | 任务2 | {树3} | {笔2}     
    

    dbfiddle在这里

    更新

    如果根据评论,您更喜欢使用具有两个字段 tree_id 和 pen_id 的单个任务表,则可以通过这种方式设置参照完整性:

    我添加了一个检查约束,确保 tree_id、pen_id 之一为空:

    alter table task 
        add constraint ck_one_in_two_must_be_null check(tree_id is null or pen_id is null);
    
    create table tree 
    (
        tree_id int primary key,
        name text
    );
    
    create table pen
    (
        pen_id int primary key,
        name text
    );
    
    create table task
    (
        task_id int primary key,
        name text,
        tree_id int references tree (tree_id) on update cascade on delete restrict,
        pen_id int references pen (pen_id) on update cascade on delete restrict
    );
    
    alter table task 
    add constraint ck_one_in_two_must_be_null check(tree_id is null or pen_id is null);
    
    insert into tree values (1, 'tree1'),(2, 'tree2'),(3, 'tree3');
    insert into pen values (1, 'pen1'),(2, 'pen2'),(3, 'pen3');
    insert into task values (1, 'task1', 1, null),(3, 'task3', null, 3);
    
    select    tk.task_id, 
              tk.name,
              tr.tree_id,
              tr.name as tree_name,
              pn.pen_id,
              pn.name as pen_name
    from      task tk
    left join tree tr
    on        tr.tree_id = tk.tree_id
    left join pen pn
    on        pn.pen_id = tk.pen_id;
    
    任务编号 | 姓名 | 树编号 | 树名 | 笔号 | 笔名
    ------: | :---- | ------: | :-------- | -----: | :--------
          1 | 任务 1 | 1 | 树1 |   空| 空    
          3 | 任务 3 |    空| 空      | 3 | 笔3    
    
    insert into task values (2, 'task2', 2, 3);
    
    错误:关系“任务”的新行违反检​​查约束“ck_one_in_two_must_be_null”
    详细信息:失败行包含 (2, task2, 2, 3)。
    
    
    insert into task values (4, 'task4', 4, null);
    
    错误:插入或更新表“任务”违反外键约束“task_tree_id_fkey”
    详细信息:表“树”中不存在键 (tree_id)=(4)。
    
    
    insert into task values (5, 'task5', null, 6);
    
    错误:插入或更新表“task”违反了外键约束“task_pen_id_fkey”
    详细信息:键 (pen_id)=(6) 不存在于表“pen”中。
    
    

    dbfiddle在这里

    • 2

相关问题

  • 我可以在使用数据库后激活 PITR 吗?

  • 运行时间偏移延迟复制的最佳实践

  • 存储过程可以防止 SQL 注入吗?

  • PostgreSQL 中 UniProt 的生物序列

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve