设置具有不同数据类型的外键

时间:2015-08-28 09:31:27

标签: sql postgresql

如果我创建了两个表,并且我想将一列作为外键设置为另一个表列为什么我可以设置外键列数据类型?

它没有任何意义,或者我错过了什么?是否存在具有外键的列具有不同数据类型的情况?

对我的担忧更加深入,我尝试使用pgadmin构建一些简单的Postgres DB。我用主键serial数据类型创建了第一个表。然后我试着创建外键但是什么数据类型?我见过某处serialbigint unsigned。但是这个选项在pgadmin中甚至不存在。当然我可以使用sql但是为什么我使用gui?所以我尝试了Navicat,同样的问题。我觉得在每次选择时我都会在数据库设计中犯下另一个错误......

编辑:

也许我错误地问了这个问题。 我被允许做构建结构:

CREATE TABLE user
(
  id bigint NOT NULL,
  CONSTRAINT user_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

CREATE TABLE book
(
  user integer,
  CONSTRAINT dependent_user_fkey FOREIGN KEY (user)
      REFERENCES user (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);

我向表用户插入一些数据:

INSERT INTO user(id)
    VALUES (5000000000);

但是我无法在插入后投射:

INSERT INTO book(user)
    VALUES (5000000000);

ERROR: integer out of range这是可以理解的,但设计错误明显。

我的问题是:为什么我们设置CONSTRAINT时,数据类型未经过验证。如果我错了,答案应该包含有不同数据类型有用的场景。

2 个答案:

答案 0 :(得分:6)

实际上这有道理是为什么:

在表格中,您实际上可以将任何列设置为其主键。所以它可以是整数,双精度,字符串等。尽管如今,我们大多使用整数或者最近使用字符串作为表中的主键。

由于外键指向另一个表的主键,因此您需要指定外键的数据类型。它显然需要是相同的数据类型。

修改

我们可以看到SQL实现在这种情况下是松散的:它们确实允许兼容类型(INT和BIG INT,Float或DECIMAL和DOUBLE),但风险自负。正如我们在下面的示例中看到的那样。

但是,SQL规范确实指定两种数据类型必须相同。 如果数据类型是字符,则它们必须具有相同的长度,否则,如果它是整数,则它们必须具有相同的大小,并且必须两者 已签名或两者都未签名

你可以自己看看over here,这是2003年出版的MySQL书的一章。

希望这能回答你的问题。

答案 1 :(得分:0)

要回答您为什么要为外键和主键使用不同类型的问题...这里是一种情况:

我的情况是,一个非常大的 postgres 表的 id 序列的 integer 值用完了。许多其他同样大的表都有指向该父表的外键。

我们将父表和所有子表中的 ID 从 integer 升格为 bigint。这需要全表重写。由于表的大小以及我们的正常运行时间承诺和维护窗口大小,我们无法在一个窗口中重写所有这些表。我们还有大约三个月的时间才能爆发。

因此在维护窗口之间,我们将拥有具有相同数值但不同大小列的主键和外键。根据我们的经验,这很有效。

即使在像这样的主动迁移策略之外,我也可以看到创建一个带有 bigint 外键的新子表,并期望“有一天”父表的主键从 integer 升级到 bigint。

我不知道列大小不匹配是否有任何性能损失。这个问题实际上是让我来到这个页面的原因,因为我一直无法在网上找到相关指南。

(切线:永远不要创建任何带有整数 ID 的表。使用 bigint,无论您认为十年后您的数据会是什么样子。不客气。)