检查约束调用函数Oracle SQL开发人员

Oli*_*ara 3 sql oracle oracle-sqldeveloper

在Oracle SQL开发人员中是否可以执行此类操作

CREATE FUNCTION fnCheckValid(accountidd IN NUMBER) 
RETURN NUMBER 
   IS retval NUMBER(4,0);
   BEGIN 
      SELECT COUNT(accountid_fk) 
      INTO retval 
      FROM tbl_AccountAuthentications 
      WHERE accountid_fk = accountidd; 
      RETURN(retval); 
    END;
/


ALTER TABLE tbl_AccountAuthentications
ADD CONSTRAINT chkCheckvalid CHECK(fnCheckValid(accountid_fk) <= 1);
Run Code Online (Sandbox Code Playgroud)

我不断得到的错误是

Error starting at line 999 in command:
ALTER TABLE tbl_AccountAuthentications
ADD CONSTRAINT chkCheckvalid CHECK(fnCheckValid(accountid_fk) <= 1)
Error report:
SQL Error: ORA-00904: "FNCHECKVALID": invalid identifier
00904. 00000 -  "%s: invalid identifier"
*Cause:    
*Action:
Run Code Online (Sandbox Code Playgroud)

该功能正在创建,我可以找到它,但当我试图调用它时,我一直收到该错误

这就是我想要实现的目标

AccountID    RegularID     OpenID
 1            5             null
 1            null          10
 1            null          11
 1            6                             <-- Forbidden
Run Code Online (Sandbox Code Playgroud)

这样用户就无法创建2个常规帐户,但可以拥有他想要的OpenID帐户数

该表设置如下

CREATE TABLE tbl_AccountAuthentications(
        newAuthID NUMBER(4,0)
          CONSTRAINT naid_pk PRIMARY KEY,        
        accountid_fk NUMBER(4,0)
          CONSTRAINT accid_fk 
            REFERENCES tbl_UserAccounts(account_id),
        regularid_fk NUMBER(4,0)
          CONSTRAINT rgid_fk
            REFERENCES tbl_StrongRoom(password_id),
        openid_fk NUMBER(4,0)
          CONSTRAINT opid_fk
            REFERENCES tbl_OpenID(openid)
);
Run Code Online (Sandbox Code Playgroud)

Wer*_*eit 8

不,你不能这样做,请参阅检查约束的限制:

  • 调用用户定义的函数

但您可以使用虚拟列进行解决方法

ALTER TABLE tbl_AccountAuthentications ADD (fnCheck NUMBER GENERATED ALWAYS AS (fnCheckValid(accountid_fk)) VIRTUAL);


ALTER TABLE tbl_AccountAuthentications
ADD CONSTRAINT chkCheckvalid CHECK(fnCheck <= 1);
Run Code Online (Sandbox Code Playgroud)

注意,函数必须是DETERMINISTIC,否则它不起作用.Oracle不会验证您的函数是否确实是确定性的,它只是检查关键字.这是允许的(尽管它根本没有任何意义):

CREATE OR REPLACE FUNCTION DET_FUNCTION RETURN NUMBER DETERMINISTIC IS 
BEGIN 
    RETURN DBMS_RANDOM.RANDOM();
END;
/
Run Code Online (Sandbox Code Playgroud)


Ben*_*Ben 6

您希望确保AccountIDRegularID列一起是唯一的,无论OpenID的值有多少.

正如你所确定的那样,这样做的唯一方法就是限制它.您在评论中注意到您已尝试使用触发器.这并没有在数据库中限制值,它只是确保它试图启用触发器时进行验证.我希望,当你尝试它时,你得到错误"ORA-04091:正在改变,触发器/功能可能看不到它".当您从表中选择时,您正处于更改(插入或更新)的过程中.

如果你必须限制这个,那就是你应该做的; 这样做的问题是你的表没有规范化.所以,规范它.使用两个表而不是您拥有的表.

首先,您需要您的RegularIDAccountID上是唯一的,这意味着它应该存储在此级别.看起来好像tbl_UserAccounts这个标识符是唯一的,所以改变这个表并在那里存储你的RegularID.

接下来,您需要一个具有用户可能需要的OpenID数量的表.这意味着您需要AccountIDOpenID 1上唯一的表.

create table openid_account_auth (
   , account_id number(4,0)
   , open_id number(4,0)
   , constraint pk_openid_account_auth
       primary key (account_id, open_id)
   , constraint fk_openid_account_auth_accid
       foreign key (account_id)
       references tbl_UserAccounts(account_id)
   , constraint fk_openid_account_auth_open
       foreign key (open_id)
       references tbl_OpenID (openid)
     );
Run Code Online (Sandbox Code Playgroud)

此表(以及您自己的)上的一点,表示多个帐户可以具有相同的OpenID.如果您不打算这样做,那么您应该将AccountID作为外键添加tbl_OpenID,这将是确保每个OpenID与一个且仅一个AccountID相关联的唯一方法.

然后,如果您确实需要使用此信息,则可以创建视图以便以相同的方式获取信息.我不确定你为什么会这样.

create or replace view AccountAuthentications as
 select account_id, regular_id, null
   from user_accounts
  union all
 select account_id, null, open_id
   from openid_account_auth;
Run Code Online (Sandbox Code Playgroud)

简而言之,除非受到严格限制,否则应始终将数据存储在自然级别,并使用数据库确保维护完整性.如果您稍后需要稍微使用数据,则可以使用视图或物化视图等来执行此操作.

我很抱歉,但我不能把自己写在每张桌子的名字前面tbl_.