【问题标题】:SQL (PostgreSQL) unique value between groups组之间的 SQL (PostgreSQL) 唯一值
【发布时间】:2020-11-13 10:59:56
【问题描述】:

我有一个包含 val_A、val_B 列的表。要求我只能插入(没有更新/删除,我想避免触发器和存储过程)。

我如何实现这样的要求,即列 val_A 的值必须是唯一的,但对于整个表不是,而只是基于 val_B 的组。换句话说,对于 val_B = 1,我可以有许多 val_A = 1 的条目,但在这种情况下,我不能有 val_A = 1 和 val_B != 1;

例如:

+-------+-------+---------------------+
| val_A | val_B |       Comment       |
+-------+-------+---------------------+
|     1 |     1 |                     |
|     2 |     1 |                     |
|     1 |     1 | This is Allowed     |
|     1 |     2 | This is not allowed |
+-------+-------+---------------------+

编辑 #1 我正在寻找的解决方案应该适用于当前的插入。 我正在尝试类似于Davide Anghileri 响应的方法,但在并发插入场景中失败了。

【问题讨论】:

    标签: sql postgresql where-clause unique-index


    【解决方案1】:

    您可以将检查条件放在 WHERE 子句中。举个例子:

    INSERT INTO table_name(val_A, val_B)
    SELECT 1, 2
    WHERE NOT EXISTS (SELECT * FROM table_name WHERE val_A=1 AND val_B!=2)
    

    如果需要,您可以从另一个表中取出要插入的数字(例如 1、2)。 Where 子句中的数字也应该设置为另一个表:

     val_A=other_table.val_A AND val_B!=other_table.val_B
    

    在此条件下,您可以插入 1,1 但不能插入 1,2,因为您已经有一条具有相同 val_A 和不同 val_B 的记录。

    【讨论】:

    • 谢谢,请看我的原帖 EDIT #1
    【解决方案2】:

    这很棘手,但您可以在表达式上创建唯一索引 - 并利用 Postgres 允许 NULL 值在唯一索引中重复的事实。

    所以:

    create unique index unq_t_val_a_val_b on
        (case when val_a <> val_b then least(val_a, val_b) end,
         case when val_a <> val_b then greatest(val_a, val_b) end
        );
    

    当值不同时,least()greatest() 创建一个索引,其中包含两个键,值按顺序排列。当值相同时,键为NULL,因此它们实际上并不是唯一索引的一部分。

    您也可以通过过滤来做到这一点:

    create unique index unq_t_val_a_val_b on
        (least(val_a, val_b), greatest(val_a, val_b))
        where val_a <> val_b;
    

    【讨论】:

      【解决方案3】:

      您可以使用唯一的过滤索引:

      create unique index myidx 
          on mytable(val_a)
          where (val_b is distinct from 1)
      

      这仅允许在 val_a 中重复 val_b 的值为 1 的行。

      【讨论】:

      • 谢谢,但我不能只固定值 1。这必须是通用解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-16
      • 1970-01-01
      • 2010-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      相关资源
      最近更新 更多