Как установить проверку уникального ключа по другой таблице - PullRequest
0 голосов
/ 11 января 2019

Я создал три таблицы: supplier, item и purchase. supplier идентификатор связан с item таблицей, а item идентификатор связан с purchase таблицей. Я не хочу вставлять itemid в purchase таблицу в тот же элемент supplier. Как я могу установить ограничение?

CREATE TABLE csupplier(
  supid NUMBER(10) PRIMARY KEY ,
  supname VARCHAR2(30)
 );

CREATE TABLE ctitem(
  itemid NUMBER(10) PRIMARY KEY,
  itemname VARCHAR2(50),
  supid NUMBER(10)
 );
ALTER TABLE CTITEM
  ADD CONSTRAINT CTITEM_FK1 FOREIGN KEY(SUPID )REFERENCES CSUPPLIER(SUPID );
CREATE TABLE cPurchase(
  purchaseid NUMBER(10) PRIMARY KEY,
  itemid NUMBER(10),
  purchaseqty NUMBER(10)
 );
ALTER TABLE CPURCHASE
  ADD CONSTRAINT CPURCHASE_FK1 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID )

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Я не хочу вставлять элемент-1 и элемент-3 одновременно при покупке

Проблема в том, что Oracle не понимает концепцию в то же время . Он понимает транзакции, он понимает операторы DML, он понимает уникальные ключи. Поэтому нам нужно сформулировать ваш вопрос в терминах, понятных Oracle: например, данная покупка не может иметь более одного товара от одного поставщика .

Ваша первая проблема в том, что ваша модель данных не может поддерживать такое правило. Ваша таблица cpurchase имеет первичный ключ purchaseid, что означает, что у вас есть одна запись на каждый купленный предмет. Не существует набора приобретенных предметов, в отношении которых мы можем применить правило. Итак, первое, что нужно изменить модель данных:

CREATE TABLE cPurchase(
  purchaseid NUMBER(10) PRIMARY KEY );
CREATE TABLE cPurchaseItem(
  purchaseid NUMBER(10),
  itemid NUMBER(10),
  purchaseqty NUMBER(10)
 );

ALTER TABLE CPURCHASEITEM
  ADD CONSTRAINT CPURCHASEITEM_PK PRIMARY KEY(PURCHASEID,ITEMID); 
ALTER TABLE CPURCHASEITEM
  ADD CONSTRAINT CPURCHASEITEM_FK1 FOREIGN KEY(PURCHASEID )REFERENCES CPURCHASE;
ALTER TABLE CPURCHASE
  ADD CONSTRAINT CPURCHASE_FK2 FOREIGN KEY(ITEMID )REFERENCES CTITEM(ITEMID );

Теперь у нас есть структура детализации заголовка, которая присваивает несколько предметов одной покупке, что означает, что мы можем попытаться применить правило.

Следующая проблема заключается в том, что supplierid не является атрибутом cpurchaseitem. Невозможно создать проверочное ограничение для таблицы или столбца, который выполняет запрос к другой таблице. Что вам нужно, так это SQL-утверждение, которое представляет собой условную конструкцию, которая позволит нам определять такие правила. Увы, Oracle (и любая другая СУБД) в настоящее время поддерживает утверждения.

Так что у нас остается три варианта:

  1. Перейти к процедуре и написать API транзакции, который обеспечивает соблюдение этого правила.
  2. Денормализовать cpurchaeitem, чтобы включить supplierid, затем создать уникальное ограничение для (purchaseid, supplierid). Вам нужно будет заполнить supplierid всякий раз, когда вы заполняете cpurchaseitem.
  3. Написать триггер после оператора:

(Предупреждение: это закодированный wildstyle и может содержать ошибки и / или ошибки компиляции.)

create or replace trigger cpurchaseitem_trg
     after insert or update on cpurchaseitem
declare
     rec_count number;
begin
     select count(*)
     into rec_count
     from cpurchaseitem pi
         join citem I on pi.itemid = i.itemid
     group by pi.purchaseid, i.supplierid having count(*) > 1;

     if rec_count > 0 then
         raise_application_error(-20000
            , 'more than one item for a supplier!');
     end if;
 end;

Честно говоря, ни одно из этих решений не является особенно привлекательным. API - это твердое решение, но открытое для обхода. Триггер будет страдать от проблем с масштабированием, так как количество покупок со временем увеличивается (хотя это можно уменьшить, написав вместо этого составной триггер, оставленный в качестве упражнения для читателя). Денормализация - это самое безопасное (и, вероятно, наиболее эффективное) решение, даже если оно не моделирует лучшую практику.

0 голосов
/ 11 января 2019

Есть 2 решения вашей проблемы: 1. Измените таблицу cPurchase и добавьте столбец supid в таблицу. и сделайте уникальный ключ в этом столбце. Это решит вашу проблему.

CREATE TABLE cPurchase(
  purchaseid NUMBER(10) PRIMARY KEY,
  itemid NUMBER(10),
  purchaseqty NUMBER(10),
  supid NUMBER(10) UNIQUE KEY
 );
  1. Если изменить невозможно в этой таблице, запишите уровень строки, Перед вставкой / триггером обновления. В этом триггере напишите логику, чтобы найти Supid на основе ctitem Item_id, и они найдут, что любой предмет этого поставщика существует в вашей таблице покупок.

    CREATE [ OR REPLACE ] TRIGGER SUP_CHECK
    BEFORE INSERT
       ON cPurchase
       FOR EACH ROW 
    
    DECLARE
       L_COUNT NUMBER;
    
    BEGIN
      SELECT COUNT(*) INTO L_COUNT 
      FROM cPurchase c
      WHERE C.itemid in (Select itemid from ctitem ct where ct.supid = (Select supid 
       from ctitem  where itemid = :new.itemid)  );
    
    EXCEPTION
       WHEN ...
       -- exception handling
    
    END;
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...