Postgres:带有两个外键的非空约束

时间:2018-06-04 14:17:36

标签: postgresql

我是数据库设计的新手,想尝试一个简单的聊天网络应用来练习这项技能。

我正在尝试制作一个像聊天应用程序一样的Messenger.com,用户可以将消息发送给联系人和群组。

我找到了这个很好的教程但是我的“消息”表有问题:http://www.vertabelo.com/blog/technical-articles/database-model-for-a-messaging-system

这个想法是,当向用户发送消息时,“reciever_group_id”为NULL,并且当消息发送到组时,“reciever_user_id”为NULL。但是,postgres不会允许向Messages表添加消息,因为外键不能为NULL,即它违反了reciever_user_id或reciever_group_id的NOT-NULL约束。

任何提示?

CREATE TABLE users (
  id serial primary key,
  username character varying(32) NOT NULL UNIQUE,
  password character varying(255) NOT NULL,
  name character varying(64) NOT NULL,
  image character varying(255),
  active int NOT NULL DEFAULT 0
);

CREATE TABLE groups (
  id serial primary key,
  name character varying(255) NOT NULL
);

CREATE TABLE group_users (
  id serial primary key,
  user_id serial references users(id),
  group_id serial references groups(id)
);

CREATE TABLE messages (
  id serial primary key,
  user_id serial references users(id),
  reciever_user_id serial references users(id),
  reciever_group_id serial references groups(id),
  body text
);

2 个答案:

答案 0 :(得分:3)

您需要一个检查约束,以确保这两列中只有一列包含非空值。

CREATE TABLE messages (
  id serial primary key,
  user_id integer,
  receiver_user_id integer,
  receiver_group_id integer,
  body text,
  constraint check_group_user check (
      (receiver_user_id is null and receiver_group_id is not null) 
   or (receiver_user_id is not null and receiver_group_id is null) )
);

另外:将FK列定义为serial,这将自动生成不同的ID,因为每列使用另一个序列。

应使用引用列的基本数据类型定义外键列。所以integer代替serialserial is not a real data type

答案 1 :(得分:1)

您还可以使用使用NUM_NONNULLS(...)的约束。

类似的东西:

CREATE TABLE messages (
  id serial primary key,
  user_id integer,
  receiver_user_id integer,
  receiver_group_id integer,
  body text,
  constraint check_group_user check (
    NUM_NONNULLS(receiver_user_id, receiver_group_id) = 1
  )
);