在外键中拥有 "常数 "列的实例介绍

刚才有人在Twitter上问我一个非常有趣的问题:

@lukaseder快速问:在PG中,我可以有一个复合外键,其中一个值是常数......还是我必须在表中存储常数? constraint foreign key (foo_id, 'bar_subtype') references foo(foo_id,foo_type) ?

- 看!皇帝没穿衣服 V⃝(@connolly_s)2020年9月10

我们可以在(PostgreSQL)表中设置 "常量 "外键列吗?幸运的是,是的,我们可以。使用一个很好的标准功能,即"计算列 "或 "生成列"有时,无论出于什么原因,你不能完全规范化你的模式。可能有这样一种情况:你有一个带有复合主键的表,像这样:

CREATE TABLE t1 (
  a int,
  b int,
  t1 int,
  PRIMARY KEY (a, b)
)

当然,你可以创建一个带有CHECK约束的表t2,确保b=1:

CREATE TABLE t2 (
  a int,
  b int NOT NULL DEFAULT 1 CHECK (b = 1),
  t2 int,
  FOREIGN KEY (a, b) REFERENCES t1
)

但为什么不使用一个生成的列来代替呢?

CREATE TABLE t2 (
  a int,
  b int GENERATED ALWAYS AS (1) STORED,
  t2 int,
  FOREIGN KEY (a, b) REFERENCES t1
)

在我看来,这甚至更强大。从PostgreSQL 12开始,只支持STORED(意味着数值存储在磁盘上),而在这种情况下,VIRTUAL会更好(意味着数值只在读取行时产生)。 插入一些测试数据:

INSERT INTO t1 (a, b, t1) 
VALUES(1, 1, 1), (1, 2, 2), (2, 1, 3);

INSERT INTO t2 (a, t2) 
VALUES (1, 11), (2, 12);

SELECT * 
FROM t1
NATURAL LEFT JOIN t2

产生了预期的结果。我们只能将(b=1)插入到t2中:

a|b|t1|t2|
-|-|--|--|
1|1| 1|11|
2|1| 3|12|
1|2| 2|  |

一个很好的技巧,可以保留在袖子里。 计算或生成的列在各种RDBMS中可用,至少包括:

  • Db2
  • MySQL
  • Oracle
  • PostgreSQL
  • SQL服务器

猜你喜欢

转载自juejin.im/post/7126376815819489317