简体   繁体   中英

Sybase constraint with foreign key and conditional check against foreign table column value

Is it possible on Sybase to define a constraint(s) which require a column to be a foreign key and also satisfy a condition based on the value of a foreign column, eg in the below example tables could a constraint be created on the "product" table such that "product.code is a foreign key of a brand.code which has valid=1"?

CREATE TABLE brand (
    code        char(8)       NOT NULL,
    valid       int           NOT NULL,
    rowid       numeric(10,0) IDENTITY,
    CONSTRAINT brand_pk PRIMARY KEY (code),
    CONSTRAINT valid_check CHECK (valid IN (0,1))
)

CREATE TABLE product (
    code        char(8)       NOT NULL,
    CONSTRAINT product_pk PRIMARY KEY (code)
)

I think it's best to change the structure just a little bit.

CREATE TABLE brand (
    code        char(8)       NOT NULL,
    valid       int           NOT NULL,
    rowid       numeric(10,0) IDENTITY,
    CONSTRAINT brand_pk PRIMARY KEY (code),

    -- The following UNIQUE constraint lets the pair of values be the target of 
    -- a foreign key reference.
    CONSTRAINT brand_is_valid UNIQUE (code, valid),

    CONSTRAINT valid_check CHECK (valid IN (0,1))
);

CREATE TABLE product (
    code        char(8)       NOT NULL,
    valid       int           NOT NULL,

    -- The column "code" is a PK in the referenced table, so this still works. It's 
    -- a 1:0 or 1:1 relationship.
    CONSTRAINT product_pk PRIMARY KEY (code),

    -- The next constraint requires a unique constraint on the pair of 
    -- columns in the table "brand".  By itself, it references every row
    -- in "brand". That's too many rows.
    CONSTRAINT product_fk FOREIGN KEY (code, valid) 
                          REFERENCES brand (code, valid),

    -- But this constraint restricts the foreign key references to only those 
    -- rows that have valid = 1 in the table "brand".
    CHECK (valid = 1)
);

In order to bypass the creation of a foreign-key based on the "valid" condition, you will need to modify your table design and create a trigger to set the product.code = NULL. Pardon my syntax (I haven't coded Sybase for a while), but this is the general idea:

Add a new column to serve as the primary key since we will need to set product.code = NULL when valid=0:

CREATE TABLE product (
    rowid       int identity primary key,
    code        char(8) NULL,
    CONSTRAINT brand_fk FOREIGN KEY (code) REFERENCES brand(code)
)

Then create a trigger similar to this one:

create trigger FK_WhenValid 
on product 
for insert 
AS
  IF (SELECT COUNT(*) FROM brand b inner join inserted i on b.code = i.code AND b.valid=0 ) > 0 
  BEGIN
    UPDATE product SET code = NULL WHERE code in (SELECT i.code from brand b join inserted i on b.code = i.code and b.valid = 0)
  END

this trigger only supports product insertions. 此触发器仅支持产品插入。 If "valid" can change, another approach is required.

You could also implement the foreign key as a trigger instead of a declarative constraint and only set product.code = inserted.code when valid = 1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM