【问题标题】:Setting up foreign key with different datatype设置不同数据类型的外键
【发布时间】:2015-08-28 09:31:26
【问题描述】:

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

这没有任何意义还是我错过了什么?是否存在任何情况下具有外键的列故意具有不同的数据类型?

关于我的担忧更深入一点,我尝试使用 pgadmin 构建一些简单的 Postgres 数据库。我用主键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 时,数据类型没有得到验证。如果我错了,答案应该包含使用不同数据类型很有用的场景。

【问题讨论】:

  • 我不知道你在说什么。 “设置外键列类型”是什么意思? SQL 语言要求表定义中的每一列都有一个数据类型。编写设置架构的 SQL 脚本要好得多。你靠 GUI 活着 - 你死在 GUI 上
  • 恕我直言,serial不是数据类型,说int4 default nexval('sequence')是个捷径
  • @greg thx 这实际上很有帮助。我发现了这个:postgresql.org/message-id/42A091A7.4050802@commandprompt.com
  • @a_horse_with_no_name 我同意每一列都应该有自己的数据类型,但是为什么将任何列设置为外键并不会强制更改该列的数据类型?因为你想要它,不是吗?
  • 因为这是在 SQL 标准中定义 CREATE TABLE 语句的方式。另外:您可以在以后随时定义外键约束,它不必是 CREATE TABLE 语句的一部分。 serialbigserial“快捷方式”的含义(和后果)在手册中有明确记录:postgresql.org/docs/current/static/…

标签: sql postgresql


【解决方案1】:

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

我处于一个非常大的 postgres 表的 id 序列的integer 值用完的情况。许多其他同样大的表都具有该父表的外键。

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

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

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

我不知道列大小不匹配是否会降低性能。正是这个问题将我带到了这个页面,因为我一直无法在网上找到有关它的指导。

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

【讨论】:

    【解决方案2】:

    其实这确实是有道理的,原因如下:

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

    由于外键指向另一个表的主键,所以需要指定外键的数据类型。而且它显然需要是相同的数据类型。

    编辑:

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

    但是,SQL 规范确实指定两种数据类型必须相同。 如果数据类型是字符,它们必须具有相同的长度,否则,如果它是整数,它们必须具有相同的 size 并且必须 bothsigned 或都是 unsigned

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

    希望这能回答你的问题。

    【讨论】:

    • 我同意,我想要相同的数据类型。但是在设置约束时无法控制数据类型是否相同。这就是问题所在。 SQL 允许我意外出错(人为错误),所以我正在寻找需要不同数据类型的场景。
    • 当我为主键选择“sequence”数据类型时,我很可能会犯这个错误,因为我不确定它是什么数据类型。
    • @EntityBlack 我之前的回答已经改进了,请再看一遍。
    • @EntityBlack:Postgres 中没有“序列”数据类型。但是,如果您指的是 serialbigserial,那么它们是什么以及它们是如何工作的都有很好的记录:postgresql.org/docs/current/static/…
    • @a_horse_with_no_name 是serial,抱歉打错了。谢谢这个链接解释了很多;)
    猜你喜欢
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    相关资源
    最近更新 更多