Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在PostgreSQL中创建具有条件和子查询的唯一索引?_Sql_Database_Postgresql_Constraints - Fatal编程技术网

如何在PostgreSQL中创建具有条件和子查询的唯一索引?

如何在PostgreSQL中创建具有条件和子查询的唯一索引?,sql,database,postgresql,constraints,Sql,Database,Postgresql,Constraints,我使用PGSQL并尝试在下面添加索引 CREATE UNIQUE INDEX fk_client ON user_client (fk_client) WHERE fk_client NOT IN(SELECT fk_client FROM legal_entity); 但是。。。这是不可能的,因为在创建索引时允许运行子查询 我得到以下错误: ERROR: cannot use subquery in index predicate 有没有办法解决这个问题 上述模型代表了该案例的情况

我使用PGSQL并尝试在下面添加索引

CREATE UNIQUE INDEX fk_client ON user_client (fk_client) WHERE fk_client NOT IN(SELECT fk_client FROM legal_entity);
但是。。。这是不可能的,因为在创建索引时允许运行子查询

我得到以下错误:

ERROR:  cannot use subquery in index predicate
有没有办法解决这个问题

上述模型代表了该案例的情况

  • 客户可以是普通人,也可以是公司
  • 如果是普通人,则在“法人实体”表中没有FK
  • 如果是普通人,她应该在“user\u client”表中只显示一条记录
用索引是不行的,但是有没有办法解决这个问题呢

脚本生成表:

-- user is a special word, then renamed to users
CREATE TABLE users (
    id_user INT,
    name VARCHAR(50) NOT NULL,
    CONSTRAINT user_pkey PRIMARY KEY (id_user)
);

CREATE TABLE client (
    id_client INT,
    CONSTRAINT client_pkey PRIMARY KEY (id_client)
);

CREATE TABLE legal_entity (
    fk_client INT,
    federal_id VARCHAR(14) NOT NULL,
    CONSTRAINT legal_entity_pkey PRIMARY KEY (fk_client),
    CONSTRAINT legal_entity_fkey FOREIGN KEY (fk_client) REFERENCES client (id_client)
);

CREATE TABLE user_client (
    fk_client INT,
    fk_user INT,
    CONSTRAINT user_client_pkey PRIMARY KEY (fk_client, fk_user),
    CONSTRAINT user_client_fkey_1 FOREIGN KEY (fk_client) REFERENCES client (id_client),
    CONSTRAINT user_client_fkey_2 FOREIGN KEY (fk_user) REFERENCES users (id_user)
);
更新:这是数据模型修改后的新情况。 重点是:法律实体和客户似乎共享一个关键域(这看起来不正确),让法律实体拥有自己的关键域似乎更合适

DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;

-- user is a special word, then renamed to users
CREATE TABLE users
        ( id INTEGER PRIMARY KEY
        -- name is a special word
        , zname VARCHAR(50) NOT NULL
        );

CREATE TABLE client
        (id INTEGER PRIMARY KEY
        );

CREATE TABLE legal_entity
        ( id INTEGER PRIMARY KEY
        , client_id INTEGER REFERENCES client(id)
        , federal_id VARCHAR(14) NOT NULL
        );

CREATE TABLE user_client
        ( client_id INTEGER REFERENCES client (id)
        , user_id INTEGER REFERENCES users (id)
        , legal_id INTEGER REFERENCES legal_entity(id)
        , CONSTRAINT user_client_pkey PRIMARY KEY (client_id, user_id) 
        );

CREATE INDEX tres_stupide ON user_client (client_id) WHERE legal_id IS NULL;

我通过添加规则表解决了问题:

CREATE OR REPLACE RULE rule_test AS ON INSERT
    TO user_client WHERE (
        (SELECT fk_client FROM legal_entity WHERE fk_client = new.fk_client) IS NULL) AND (
        (SELECT fk_client FROM user_client WHERE fk_client = new.fk_client) IS NOT NULL)
    DO INSTEAD NOTHING;

使用规则的缺点是,规则只是在解析查询后重写查询,因此如果通过触发器添加数据,则不会触发查询。添加一个使用逻辑调用函数的检查约束更安全。如果我正确地遵循您的逻辑,应该是这样的:

CREATE OR REPLACE FUNCTION check_user_client(fkc int) 
  RETURNS boolean AS
$$
DECLARE
  i int;
BEGIN
  SELECT count(*) INTO i FROM legal_entity WHERE fk_client = fkc;
  IF (i > 0) THEN
    RETURN true;
  END IF;

  SELECT count(*) INTO i FROM user_client WHERE fk_client = fkc;
  IF (i = 0) THEN
    RETURN true;
  END IF;

  RETURN false;  
END
$$ LANGUAGE plpgsql;

ALTER TABLE user_client ADD CONSTRAINT unique_user CHECK (check_user_client(fk_client));

foo_id不能为null fk_1和fk_2 PKs是tbl_关系foo_id是外键,可以为null。fk_1是有条件的(foo_id不为NULL)。我不明白你这句话的其余部分。可能是关于OP调用列fk_1的混淆,这对于列来说是一个非常糟糕的名称。我编辑了这个问题,我认为现在最好理解一下。法人实体中的客户端id是PK,没有意义在用户客户端中插入重复值。您的数据模型似乎不正确。user\u client表允许用户和客户端之间存在N::M关系。在本文中,您解释了客户是“自然人”或法律实体。N::M关系将允许客户机成为一个人员集合,而s则属于这些集合中的多个。客户机id作为PK出现在多个表中也是可疑的,IMO。请给出实际的表定义,而不是文本描述。#完成-希望这有帮助。抱歉,我没有阅读grafics。我读SQL。太好了!现在编辑了问题并添加了创建表的脚本。您的答案也可以编辑。此外,模型是相同的,区别在于现在有了上下文。谢谢!有时间我会考的。谢谢!这个功能运行得很好,很抱歉延迟了反馈。您如何处理这里的并发事务?它们可能都满足条件,然后提交,使表处于不一致的状态。
CREATE OR REPLACE FUNCTION check_user_client(fkc int) 
  RETURNS boolean AS
$$
DECLARE
  i int;
BEGIN
  SELECT count(*) INTO i FROM legal_entity WHERE fk_client = fkc;
  IF (i > 0) THEN
    RETURN true;
  END IF;

  SELECT count(*) INTO i FROM user_client WHERE fk_client = fkc;
  IF (i = 0) THEN
    RETURN true;
  END IF;

  RETURN false;  
END
$$ LANGUAGE plpgsql;

ALTER TABLE user_client ADD CONSTRAINT unique_user CHECK (check_user_client(fk_client));