具有多个条件的SQL检查约束

具有多个条件的SQL检查约束,sql,postgresql,check-constraints,Sql,Postgresql,Check Constraints,我有一张叫时间表的桌子。在该表中有4列,我想为其创建一个约束,以便只有以下组合是可能的: 如果设置了user\u,则task\u schedule\u id必须为空 如果设置了location\u id或customer\u id,则要求user\u id不为空,并确保未同时设置location\u id和customer\u id 如果设置了task\u schedule\u id,则要求user\u id、customer\u id和location\u id为空 这是表格: CREAT

我有一张叫时间表的桌子。在该表中有4列,我想为其创建一个约束,以便只有以下组合是可能的:

  • 如果设置了
    user\u
    ,则
    task\u schedule\u id
    必须为空
  • 如果设置了
    location\u id
    customer\u id
    ,则要求
    user\u id
    不为空,并确保未同时设置
    location\u id
    customer\u id
  • 如果设置了
    task\u schedule\u id
    ,则要求
    user\u id
    customer\u id
    location\u id
    为空
这是表格:

CREATE TABLE IF NOT EXISTS timesheets
(
    id               uuid        NOT NULL DEFAULT gen_random_uuid(),
    created_at       timestamptz NOT NULL DEFAULT current_timestamp,
    updated_at       timestamptz NOT NULL DEFAULT current_timestamp,
    deleted_at       timestamptz NULL,

    -- Where and who (check if location_id or customer_id is set then require user)
    location_id      uuid        NULL,
    customer_id      uuid        NULL,
    user_id          uuid        NULL,

    -- Or what... BUT not both
    task_schedule_id uuid        NULL,

    -- Billing
    billable         bool        NOT NULL DEFAULT TRUE,
    billed_at        timestamptz NULL,
    
    -- fks and pk
    FOREIGN KEY (user_id) REFERENCES users (id),
    FOREIGN KEY (task_schedule_id) REFERENCES task_schedules (id),
    FOREIGN KEY (location_id) REFERENCES locations (id),
    FOREIGN KEY (customer_id) REFERENCES customers (id),
    PRIMARY KEY (id)
);
这就是我到目前为止所做的:

ALTER TABLE timesheets
    ADD constraint only_one_group
        check (
                ((user_id is null and customer_id is null and location_id is null) and
                 task_schedule_id is not null)
                or
                (user_id is not null and not (customer_id is null and location_id is null) and
                 (customer_id is null or location_id is null) and
                 task_schedule_id is null)
            );

上下文是一个任务计划链接到一个任务,该任务可以包含一个位置id和/或一个客户id。其思想是时间表可以全局创建,也可以与任务一起创建。

您可以将约束写为:

ALTER TABLE timesheets
  ADD constraint just_user__or__location_or_customer_with_user__or__just_task check (
      (
        user_id is not null
        and task_schedule_id is null
        and (
          (location_id is null and customer_id is null)
          and (location_id is not null or customer_id is not null)
        )
      ) or (
        (location_id is not null or customer_id is not null)
        and not (location_id is not null and customer_id is not null)
        and user_id is not null
      ) or (
        task_schedule_id is not null
        and user_id is null
        and location_id is null
        and customer_id is null
      )
    );

@汤姆,请看修改后的解决方案,