Check Constraint Calling a Function Oracle SQL developer

a 夏天 提交于 2019-12-01 20:59:16

You want to ensure that the columns AccountID and RegularID, together, are unique, no matter how many values of OpenID there are.

The only way of doing this, as you've determined, is to constrain it. You note in the comments that you've experimented with triggers. This does not constrain the values within the database, it only ensures that it attempts to verify when the trigger is enabled. I expect that, when you attempted it, you got the error "ORA-04091: is mutating, trigger/function may not see it." as you're selecting from a table you're in the processes of changing (insert or update).

If you have to constrain this then that's what you should do; the problem with doing so is that your table is not normalised. So, normalise it. Use two tables instead of the one you have.

Firstly, you need your RegularID to be unique over AccountID this means it should be stored at this level. It appears as though tbl_UserAccounts is unique on this identifier so alter this table and store your RegularID there.

Next, you want a table that has as many OpenID s as a user might want. This means that you need a table unique on AccountID and OpenID 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)
     );

One point on this table (and your own), it means that multiple accounts can have the same OpenID. If you did not intend this then you should add AccountID as a foreign key in tbl_OpenID, which would be the only way to ensure that each OpenID is associated with one, and only one, AccountID.

You can then create a view in order to get the information in the same manner, if you really feel the need to use this. I'm not certain why you would.

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;

Simply put, unless under severe constraints, you should always store data at it's natural level and use the database to ensure that integrity is maintained. If you then need to use the data slightly differently you can use views, or materialized views etc., to do so.

1. I'm sorry but I can't bring myself to prefix the name of every table with tbl_.

No you can't do that, see Restrictions on Check Constraints:

  • Calls to user-defined functions

But you can make a workaround using virtual columns

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


ALTER TABLE tbl_AccountAuthentications
ADD CONSTRAINT chkCheckvalid CHECK(fnCheck <= 1);

Note, function has to be DETERMINISTIC, otherwise it does not work. Oracle does not verify whether your function is actually deterministic, it just checks for the keyword. This one is allowed (although it does not make any sense at all):

CREATE OR REPLACE FUNCTION DET_FUNCTION RETURN NUMBER DETERMINISTIC IS 
BEGIN 
    RETURN DBMS_RANDOM.RANDOM();
END;
/
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!