Thread: constraint question (I think)

constraint question (I think)

From
Gary Stainburn
Date:
Hi folks.

I'm trying to model  a vehicle compound structure and have the following:

Four seperate compounds, North, East, South and West,
Each compound has a number of rows with Labels fastened to the fences
As the compounds are not perfect rectangles, the rows are of differing 
lengths.

I have tables for the compounds and rows, but can't work out how to set the 
constraints on the bays table - a seperate table while development takes 
place, merged with our existing stock table eventually;

I've managed to add the constraint to prevent compound_bay records being 
created for compound rows that do not exist,

My question is, how do I prevent a record being created for a bay higher than 
than the length of the row, i.e. > 20 in North row A or > 40 in East row A?

-- list of available compounds
create table compounds ( co_id        int4 primary key, co_name    varchar(80)
);

-- description of rows per compound
create table compound_rows ( co_id        int4 references compounds(co_id), cr_id        int4 not null, cr_label
varchar(5)not null, cr_sequence    int4 not null, cr_length    int4, primary key    (co_id, cr_id)
 
);
create unique index "compound_rows_sequence_index"  on compound_rows using btree (co_id, cr_sequence);
create unique index "compound_rows_label_index"  on compound_rows using btree (co_id, cr_label);

COPY compounds (co_id,co_name) from stdin;
1    North
2    East
3    South
4    West
\.

COPY compound_rows (co_id,cr_id,cr_label,cr_sequence,cr_length) from stdin;
1    1    A    10    20
1    2    B    20    20
1    3    C    30    25
1    4    D    40    25
2    1    A    10    40
2    2    B    20    40
2    3    C    30    45
2    4    D    40    45
\.

-- link from stock table one bay per vehicle
create table compound_bays ( st_VIN    varchar(17) primary key references stock (st_VIN), co_id        int4 not null,
cr_id       int4 not null, cb_id        int4 not null
 
);

alter table compound_bays add constraint compound_bays_row_check foreign key (co_id, cr_id) references
compound_rows(co_id,cr_id);


-- 
Gary Stainburn
This email does not contain private or confidential material as it
may be snooped on by interested government parties for unknown
and undisclosed purposes - Regulation of Investigatory Powers Act, 2000     


Re: Trigger/Function - one solution - was constraint question (I think)

From
Gary Stainburn
Date:
I have managed to develop one solution using functions and triggers. Has 
anyone got a better solution?

Gary

create unique index "compound_bays_unique_index" on compound_bays using btree 
(co_id,cr_id,cb_id);

create or replace function compound_rows_range_check() returns trigger as 
$proc$
DECLARE  BAYNO int4;
BEGIN -- if changing compound or row fail IF NEW.co_id <> OLD.co_id THEN   RAISE EXCEPTION 'cannot change compound id';
ENDIF; IF NEW.cr_id <> OLD.cr_id THEN   RAISE EXCEPTION 'cannot change row id'; END IF; SELECT cb_id into BAYNO from
compound_bayswhere     co_id = NEW.co_id and     cr_id = NEW.cr_id and     cb_id > NEW.cr_length     order by cb_id
desc    limit 1; IF found THEN   RAISE EXCEPTION 'Cannot remove occupied bays: % > %',       BAYNO, NEW.cr_length; END
IF;RETURN NEW;
 
END;
$proc$ LANGUAGE plpgsql;

CREATE TRIGGER compound_rows_range_check BEFORE UPDATE on compound_rows FOR EACH ROW EXECUTE PROCEDURE
compound_rows_range_check();

create or replace function compound_bays_range_check() returns trigger as 
$proc$
DECLARE  ROWLENGTH int4;
BEGIN SELECT cr_length into ROWLENGTH from compound_rows where     co_id = NEW.co_id and     cr_id = NEW.cr_id; IF not
foundTHEN   RAISE EXCEPTION 'Compound / Row not found';  END IF; IF NEW.cb_id > ROWLENGTH THEN   RAISE EXCEPTION 'row
lengthexceeded: % > %',     NEW.cb_id,ROWLENGTH; END IF; RETURN NEW;
 
END;
$proc$ LANGUAGE plpgsql;

CREATE TRIGGER compound_bays_range_check BEFORE INSERT OR UPDATE on 
compound_bays FOR EACH ROW EXECUTE PROCEDURE compound_bays_range_check();



-- 
Gary Stainburn
This email does not contain private or confidential material as it
may be snooped on by interested government parties for unknown
and undisclosed purposes - Regulation of Investigatory Powers Act, 2000     


Re: Trigger/Function - one solution - was constraint question (I think)

From
"Rafael Domiciano"
Date:
I would develop like this (No so many changes, it is basically a small trigger)

create or replace function compound_rows_range_check() returns trigger as
$body$
DECLARE
  BAYNO int4;
BEGIN
  -- First Verification = if changing compound or row fail
  IF (old.co_id <> new.co_id or
      old.cr_id <> new.cr_id) THEN
RAISE EXCEPTION 'Cannot change co_id () | cr_id ()', old.co_id, old.cr_id;
  END IF; 
  
  -- Last Verification
  SELECT cb_id into BAYNO from compound_bays 
  where
    co_id = NEW.co_id and
    cr_id = NEW.cr_id and
    cb_id > NEW.cr_length
    order by cb_id desc
    limit 1;

  IF (FOUND) THEN
RAISE EXCEPTION 'Cannot remove occupied bays: % > %', BAYNO, NEW.cr_length;
  END IF;

  RETURN NEW;
END;
$body$
LANGUAGE 'plpgsql';

2008/12/4 Gary Stainburn <gary.stainburn@ringways.co.uk>
I have managed to develop one solution using functions and triggers. Has
anyone got a better solution?

Gary

create unique index "compound_bays_unique_index" on compound_bays using btree
(co_id,cr_id,cb_id);

create or replace function compound_rows_range_check() returns trigger as
$proc$
DECLARE
  BAYNO int4;
BEGIN
 -- if changing compound or row fail
 IF NEW.co_id <> OLD.co_id THEN
   RAISE EXCEPTION 'cannot change compound id';
 END IF;
 IF NEW.cr_id <> OLD.cr_id THEN
   RAISE EXCEPTION 'cannot change row id';
 END IF;
 SELECT cb_id into BAYNO from compound_bays where
     co_id = NEW.co_id and
     cr_id = NEW.cr_id and
     cb_id > NEW.cr_length
     order by cb_id desc
     limit 1;
 IF found THEN
   RAISE EXCEPTION 'Cannot remove occupied bays: % > %',
      BAYNO, NEW.cr_length;
 END IF;
 RETURN NEW;
END;
$proc$ LANGUAGE plpgsql;

CREATE TRIGGER compound_rows_range_check BEFORE UPDATE on compound_rows
 FOR EACH ROW EXECUTE PROCEDURE compound_rows_range_check();

create or replace function compound_bays_range_check() returns trigger as
$proc$
DECLARE
  ROWLENGTH int4;
BEGIN
 SELECT cr_length into ROWLENGTH from compound_rows where
     co_id = NEW.co_id and
     cr_id = NEW.cr_id;
 IF not found THEN
   RAISE EXCEPTION 'Compound / Row not found';
 END IF;
 IF NEW.cb_id > ROWLENGTH THEN
   RAISE EXCEPTION 'row length exceeded: % > %',
     NEW.cb_id,ROWLENGTH;
 END IF;
 RETURN NEW;
END;
$proc$ LANGUAGE plpgsql;

CREATE TRIGGER compound_bays_range_check BEFORE INSERT OR UPDATE on
compound_bays
 FOR EACH ROW EXECUTE PROCEDURE compound_bays_range_check();



--
Gary Stainburn

This email does not contain private or confidential material as it
may be snooped on by interested government parties for unknown
and undisclosed purposes - Regulation of Investigatory Powers Act, 2000

--
Sent via pgsql-sql mailing list (pgsql-sql@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-sql