外键参数化以处理不同的表

问题描述 投票:0回答:1

1。我的背景:

任何节点都有一个支撑......但这个支撑可以是墙或塔(实际上有大约7种不同类型的支撑)

重要:
type_support 列表示要处理哪个表(墙壁或塔架)。您可以将其视为“参数化多态性”的参数。

id_wall 从 0 开始到 n 堵墙。
id_pylon 从 0 开始直到 n 个塔。

2。数据库结构

                              +-------------+
                              |    wall     |
+-------------+            PK +-------------+
|    node     |      |--------|id_wall      |        Legend:
+-------------+      |        +-------------+        PK means Primary key
|id_node      |      |                               FK means Foreign key
|type_support | FK   |        +-------------+
|id_support   |------|        |   Pylon     |
+-------------+      |     PK +-------------+
                     |--------|id_pylon     |
                              +-------------+


3.代码(星号(*)之间的代码是幼稚/愚蠢的)

CREATE TABLE node (
    id_node             INTEGER NOT NULL PRIMARY KEY,
    type_support        INTEGER NOT NULL,
    id_support          INTEGER NOT NULL,
    FOREIGN KEY (id_support) REFERENCES *The_right_support_table(id_the_right_support)*;

如何做到这一点?

编辑:目前我使用 SQLite,稍后它将是 PostgreSQL)

sql data-modeling parametric-polymorphism
1个回答
0
投票

您有多种选择。


你可以做你已经做过的事情,有一个ID列和一个类型列。这就是 Rails 实现多态性的方式

缺点是缺乏引用完整性。您可以使用触发器强制执行此操作,而不是使用外键。

另一个缺点是公共支持数据必须在所有支持表中重复。例如,支撑可能都有一个“高度”,因此每个“支撑”表都必须有一个高度列。查询这些公共属性变得很困难。你可以用风景来弥补这一点。

create view node_support as
  select
    node.id,
    support_id,
    support_type,
    case when pylon.id is not null then pylon.height
         when wall.id is not null then wall.height
    end as height,
    case when pylon.id is not null then pylon.max_load
         when wall.id is not null then wall.max_load
    end as max_load
  from node
  left join wall on node.support_type = 'wall' and wall.id = node.support_id
  left join pylon on node.support_type = 'pylon' and pylon.id = node.support_id

示范.


如果你的数据库支持,你可以使用表继承

create table support (
  id serial primary key,
  height integer,
  max_load integer
);

create table wall (
  color text
) inherits(support);

create table pylon (
  shape text
) inherits(support);

create table node (
  -- Referential integrity must be handled with a trigger.
  support_id integer not null
);

您可以轻松查询所有支撑,或仅查询墙壁,或仅查询塔架。

表继承有一些注意事项,并且它是 Postgres 特定的。

最大的警告是,如果您尝试

support_id integer references support(id)
,这不适用于墙壁或塔架。因此,您又回到通过触发器强制引用完整性。

示范.


您可以为每种类型的支持创建一个连接表。

create table node_wall (
  node_id integer not null references node(id),
  wall_id integer not null references wall(id)
);

create table node_pylon (
  node_id integer not null references node(id),
  pylon_id integer not null references pylon(id)
);

缺点是...

  • N 个连接表,适用于需要支持的每种类型的事物
  • “支持”也没有统一的概念。
  • 每个只有一个支持的节点必须使用触发器来强制执行。

您可以创建一个视图来查询节点及其支持度。

create view node_support as
  select
    node.id,
    coalesce(pylon_id, wall_id) as support_id,
    case when pylon_id is not null then 'pylon'
         when wall_id is not null then 'wall'
    end as type
  from node
  left join node_wall on node_wall.node_id = node.id
  left join node_pylon on node_pylon.node_id = node.id

示范.


您可以拥有一张

support
桌子,然后是专门的桌子。

create table support (
  id integer primary key

  -- columns related to any support
);

create table wall (
  id integer primary key,
  support_id integer not null references support(id)

  -- columns only related to walls
);

create table pylon (
  id integer primary key,
  support_id integer not null references support(id)

  -- columns only related to pylons
);

现在

node
可以参考
support
。查询通用支持信息很容易。

缺点是:

  • 如果您想了解支持类型,您需要搜索所有表格。
    • 可以通过视图来缓解这种情况。
  • 强制支撑只能是一种类型必须使用触发器来完成(即支撑只能是墙壁或塔架,不能同时是两者)
© www.soinside.com 2019 - 2024. All rights reserved.