cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Cross Reference Table Design

JimDiaz
Participant
0 Likes
2,303

We are adding a Cross Reference table to identify parts that are equivalents. This is the first time I have modeled this any comments or suggestions are appreciated.

Thanks

Jim

The core Parts Table has a single surrogate integer primary key "PartId". The cross reference table has a PK of PartId and ReferenceId where ReferenceId is the PartId of the cross referenced part.

The insert procedure checks for existing cross reference as well as related cross references so

| 1 | 2 |
| 1 | 3 |
| 2 | 1 | -- Not Allowed
| 3 | 1 | -- Not Allowed
| 2 | 3 | -- Not Allowed

We then use the following procedure to return all cross referenced parts

CREATE OR REPLACE PROCEDURE NSP.CrossReferencedParts(
  IN @PartId INTEGER
  )
RESULT(
  CrossReferenceId  INTEGER
  )
BEGIN
  -- {JJD} Retirn all parts directly or indirectly cross referenced to @PartId
  DECLARE @Count    INTEGER;
  DECLARE @TargetId INTEGER;

  SELECT COUNT(*)
    INTO @Count
    FROM NSP.PartsCrossReference
   WHERE PartId = @PartId;

  IF @Count > 0 THEN

    -- This is the master PartId
    SELECT ReferenceId AS CrossReferenceId
      FROM NSP.PartsCrossReference
     WHERE PartId = @PartId
     UNION
    SELECT @PartId AS CrossReferenceId;

  ELSE

    SELECT PartId
      INTO @TargetId
      FROM NSP.PartsCrossReference
     WHERE ReferenceId = @PartId;

    IF @TargetId IS NOT NULL THEN
      -- This is a referenced PartId
      SELECT ReferenceId AS CrossReferenceId
        FROM NSP.PartsCrossReference
       WHERE PartId = @TargetId
      UNION
      SELECT @TargetId AS CrossReferenceId;

    ELSE

      SELECT COUNT(*)
        INTO @Count
        FROM NSP.Parts
       WHERE PartId = @PartId;

      IF @Count > 0 THEN
        -- The part exists but there are no cross references to this part
        SELECT @PartId AS CrossReferenceId;
      END IF;

    END IF;
  END IF;
END;

Accepted Solutions (0)

Answers (1)

Answers (1)

awitter43
Participant
0 Likes

Maybe this is what you're asking for:

// Parts table
create table parts(
  partID integer,
  partDescr nchar(40),
  primary key (partID)
);

// Relationstable between parent and child
create table pc(
  pPartID integer, // Parent/main part
  cPartID integer  // Child/underlaying part
);
alter table pc add foreign key FK_p (pPartID) references parts (partID) on update restrict on delete restrict;
alter table pc add foreign key FK_c (cPartID) references parts (partID) on update restrict on delete restrict;

// Add trigger to prevent wrong inserts to pc:
create or replace trigger tb_pc before insert, update order 1 on pc referencing new as New_Record old as Old_Record for each row
begin
  if new_record.pPartID > new_record.cPartID then
  begin
    // Make sure the relation always is from lower to higher
    declare buf integer = new_record.pPartID;
    set new_record.pPartID = new_record.cPartID;
    set new_record.cPartID = buf;
  end;
  end if;

  // Test if relation already exists
  begin
    declare ExistOnLevel integer = 0;
    with recursive Relation (pPartID, cPartID, level) as
    (
      (
        select pPartID, cPartID, 1 level
        from pc AS tab
    //    where cPartID = pPartID
      )
      UNION ALL
      (
        select tab.pPartID, rel.cPartID, rel.level+1
        from pc AS tab
             inner join relation AS rel on (tab.cPartID = rel.pPartID /*and tab.pPartID <> tab.cPartID*/ and rel.level < 20)
      )
    )
    select first level
    into ExistOnLevel
    from relation
    where pPartID = new_record.pPartID and cPartID = new_record.cPartID;
    if ExistOnLevel > 0 then
      raiserror 17000 'Relation already exists as ' || if ExistOnLevel = 1 then 'direct' else 'indirect' endif || ' relation';
    end if;
  end;
end;

// Add parts
insert into parts(partID, partDescr)
values
  (1, 'Part 1'),
  (2, 'Part 2'),
  (3, 'Part 3'),
  (4, 'Part 4');


// Add some relations to test
insert into pc(pPartID, cPartID) values(1,2);
insert into pc(pPartID, cPartID) values(2,3);
insert into pc(pPartID, cPartID) values(2,4);
// Some wrong ones
insert into pc(pPartID, cPartID) values(4,2);
insert into pc(pPartID, cPartID) values(1,3);