【问题标题】:In Postgres, how do you restrict possible values for a particular column?在 Postgres 中,如何限制特定列的可能值?
【发布时间】:2011-08-30 23:30:02
【问题描述】:

我想在一个表(称为discussion)中创建一个列element_type,它允许文本值“课程”或“测验”,但如果在该列中插入任何其他值,则会产生错误。

我知道我可以创建一个名为 element_types 的单独表,其中包含 element_id(主键,int)和 element_type(唯一,文本)列,并在表 discussion 中创建一个外键 foreign_element_id引用element_types 的列element_id。或者,我可以完全忘记element_id,而只是将element_type 设置为主键。但我想避免创建新表。

有没有更直接的方法来限制列中的可能值而不创建新表?

【问题讨论】:

  • 为什么要避免创建表?它们并不是特别昂贵。
  • 每当我想限制可能的值时,与其说是表的成本不如说是不必要的混乱,在我的情况下,这种情况非常频繁。

标签: sql postgresql


【解决方案1】:

您可以添加CHECK CONSTRAINT:

ALTER TABLE distributors 
   ADD CONSTRAINT check_types 
   CHECK (element_type = 'lesson' OR element_type = 'quiz');

虽然 IMO 更简洁的选择是创建一个 ENUM:

CREATE TYPE element_type AS ENUM ('lesson', 'quiz');

【讨论】:

  • 优秀。谢谢你。作为对可能像我一样对 Postgres 不熟悉的其他人的说明,CREATE TYPE 创建了一个用户定义的类型,以用作任何其他类型,例如 int 或 text 可以使用。在这种情况下,可以说:CREATE TYPE element_type as ENUM ('lesson', 'quiz'); CREATE TABLE discussion ( type_of_element element_type; );
  • 值得注意的是,虽然您可以在最近的版本中向 ENUM 类型添加值,但没有优雅/简单的方法可以删除它们。如果您预计您的允许值会发生很大变化,我建议您使用检查约束。
  • 我们在将 postgresql 枚举映射到 Java 枚举时遇到了问题,因此决定继续使用“检查”
【解决方案2】:

快捷语法是:

ALTER TABLE distributors  
   ADD CONSTRAINT check_types 
   CHECK (element_type IN ('lesson', 'quiz') );

这会自动翻译成:

CONSTRAINT check_types CHECK (element_type::text = ANY (ARRAY['lesson'::character varying, 'quiz'::character varying) )

享受 ;-)

【讨论】:

    【解决方案3】:

    每当有人尝试插入或更新具有无效 element_type 的行时,此触发器都会引发异常。

    CREATE OR REPLACE FUNCTION check_discussion_element_type() RETURNS TRIGGER AS $$
    DECLARE new_element_type varchar(25);
    BEGIN
        SELECT element_type into new_element_type
            FROM discussion
            WHERE discussion.element_id = NEW.element_id;
    
        IF new_element_type != 'lesson' AND new_element_type != 'quiz'
           THEN RAISE EXCEPTION 'Unexpected discussion type';
        END IF;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;
    create trigger t_check_discussion_element_type after update or insert on discussion for each row execute procedure check_discussion_element_type();
    

    如果要删除硬编码类型,可以对其进行调整以检查新类型是否存在于类型表中。

    【讨论】:

    • 与检查约束或 ENUM 相比,解决方案非常缓慢且复杂。
    猜你喜欢
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    相关资源
    最近更新 更多