【问题标题】:PostgreSQL - NULL ReferencesPostgreSQL - NULL 引用
【发布时间】:2020-05-12 23:24:19
【问题描述】:

我有一个任务和设备的数据模型。

有时Task 需要完成一些Equipment,有时则不需要。

任务表

create table task (
    id serial primary key
,   task_name varchar(80)
)

设备表

 create table equipment (
        id serial primary key
    ,   equipment_name varchar(80)
    )

我想做的是向Task table 添加一个空引用。

create table task (
    id serial primary key
,   task_name varchar(80)
,   equipment_id serial null references equipment(id) 
)

我收到一个错误

ERROR:  conflicting NULL/NOT NULL declarations for column "equipment_id" of table "task"
SQL state: 42601

如何在向表中添加外键的同时保持数据完整性,使其按预期工作?我以为你可以有空引用。

【问题讨论】:

  • 您的代码seems to work。我不确定您的实际问题是什么。
  • 更新了对 NULL 的引用
  • serial 暗示 NOT NULL 但这是 task.equipment_id 的错误选择(见戈登的回答)

标签: sql postgresql foreign-keys referential-integrity


【解决方案1】:

您有一个潜在的建模问题:“任务需要一些设备”,如所述。但是“一些”是否真的意味着“一个”,一个任务可以需要2个或更多设备吗?如果是这样并且假设一个设备可能需要超过 1 个任务,您需要一个解析表(也许是 Task_Equipment)来解析这代表的多对多。那么

create table equipment (
       id serial primary key
     , equipment_name varchar(80)
     );

create table task (
      id serial primary key
    , task_name varchar(80)
    ); 

create table task_equipment (
       task_id       int
     , equipment_id  int 
     , constraint    te_pk 
                     primary key (task_id, equipment_id)
     , constraint    te2task_fk 
                     foreign key (task_id)
                     references task(task_id)
     , constraint    te2equipment_fk 
                     foreign key (equipment_id)
                     references equipment(equipment_id)  
     );

如果您的版本将其用作身份而不是序列号,我同意。

【讨论】:

    【解决方案2】:

    serial 是一种实际上是整数的数据类型。所以,你想要:

    create table task (
        id serial primary key,
        task_name varchar(80),
        equipment_id int references equipment(id) 
    );
    

    也就是说,Postgres 现在建议使用int generated always as identity。这样就更清楚了:

    create table task (
        id int generated always as identity primary key,
        task_name varchar(80)
    );
    
    create table task (
        id int generated always as identity primary key,
        task_name varchar(80),
        equipment_id int references equipment(id) 
    );
    

    首选generated always as identity 的原因是技术性的。但是一个效果是代码更加一致——主键和外键都具有相同的显式类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      • 2020-02-14
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2014-04-22
      相关资源
      最近更新 更多