Uma solução possível para garantir, em ambiente APEX, a consistência duma estrutura ISA, total e disjuntiva. A possible solution to ensure, in APEX environment, the consistency of a total and disjunctive ISA structure. Nota introdutória: esta solução não é perfeita para todos os ambientes. Deve ser considerada apenas para ambiente Apex. Ler notas no fim deste documento. Introductory Note: This solution is not perfect for all environments. It must be considered for Apex environment only. Read notes at the end of this document. Seja então o conjunto de entidades pessoa, com os atributos bi_pessoa, nome_pessoa e morada_pessoa, tendo como chave bi_pessoa. Supondo que cada pessoa é obigatoriamente e em exclusivo, um cliente (com nr_cliente) ou um empregado (com data_entrada_empregado). Then be the set of pessoa entities, with the attributes bi_pessoa, nome_pessoa and morada_pessoa, having as key bi_pessoa. Assuming that each pessoa is strictly and exclusively, a client (with nr_cliente) or an empregado (with data_entrada_empregado). A solução passa pela criação de, para além das tabelas pessoa, cliente e empregado, duas views: uma v_cliente, contendo os atributos de pessoa e o atributo específico nr_cliente; a outra view, v_empregado, contém para além dos atributos de pessoa, aquele que é específico do conjunto empregado, a saber, data_entrada_empregado. Eis pois: The solution is to create, in addition to the pessoa, cliente and empregado tables, two views: a v_cliente, containing the attributes of the pessoa and the specific attribute in the cliente; The other view, v_empregado, contains, in addition to the attributes of pessoa, the one that is specific to the empregado, namely, data_entrada_empregado. Therefore,
drop table pessoa cascade constraints; create table pessoa(bi_pessoa number(8) not null, nome_pessoa varchar2(30) not null, morada_pessoa varchar2(30) not null, primary key (bi_pessoa)); drop table cliente cascade constraints; create table cliente(bi_pessoa number(8) not null,nr_cliente number(4) not null, unique (nr_cliente), primary key (bi_pessoa), foreign key (bi_pessoa) references pessoa ON DELETE CASCADE); drop table empregado cascade constraints; create table empregado(bi_pessoa number(8) not null,data_entrada_empregado date not null, primary key (bi_pessoa), foreign key (bi_pessoa) references pessoa ON DELETE CASCADE); create or replace view v_cliente as select bi_pessoa,nome_pessoa,morada_pessoa,nr_cliente from pessoa natural inner join cliente; create or replace view v_empregado as select bi_pessoa,nome_pessoa,morada_pessoa,data_entrada_empreg ado from pessoa natural inner join empregado; Criadas as views, é necessário criar triggers do tipo instead of sobre as views, com o propósito de: inserir primeiro em pessoa, depois em cliente (para o caso de v_cliente); update em pessoa e em cliente; e por fim, delete em pessoa, o que provoca automaticamente a remoção do tuplo correspondente em cliente (ver o pormenor ON DELETE CASCADE no commando de criação da tabela cliente). Outros 3 triggers semelhantes são definidos relativamente à view
v_empregado. Eis pois: Once the views are created, it is necessary to create "instead of" triggers on the views, with the purpose of: inserting first in pessoa, then in cliente (in the case of v_client); Update in pessoa and in cliente; And finally, delete in perssoa, which automatically causes the corresponding tuple to be removed from the cliente (see the "ON DELETE CASCADE" detail in the cliente table creation command). Another 3 similar triggers are defined relatively to the view v_empregado. Therefore, CREATE OR REPLACE TRIGGER ins_v_cliente INSTEAD OF INSERT ON v_cliente DECLARE bi number; SELECT count(*) into bi from pessoa where bi_pessoa = :new.bi_pessoa; if bi <1 then insert into pessoa(bi_pessoa,nome_pessoa,morada_pessoa) values (:new.bi_pessoa,:new.nome_pessoa,:new.morada_pessoa); insert into cliente(bi_pessoa,nr_cliente) values(:new.bi_pessoa,:new.nr_cliente); else RAISE_APPLICATION_ERROR(-20001,'Já existe uma pessoa com esse BI'); END IF; CREATE OR REPLACE TRIGGER up_v_cliente INSTEAD OF UPDATE ON v_cliente UPDATE pessoa SET nome_pessoa = :NEW.nome_pessoa, morada_pessoa = :NEW.morada_pessoa WHERE bi_pessoa = :NEW.bi_pessoa; UPDATE cliente SET nr_cliente = :NEW.nr_cliente
WHERE bi_pessoa = :NEW.bi_pessoa; CREATE OR REPLACE TRIGGER del_v_cliente INSTEAD OF DELETE ON v_cliente delete from pessoa where bi_pessoa = :old.bi_pessoa; CREATE OR REPLACE TRIGGER ins_v_empregado INSTEAD OF INSERT ON v_empregado DECLARE bi number; SELECT count(*) into bi from pessoa where bi_pessoa = :new.bi_pessoa; if bi <1 then insert into pessoa(bi_pessoa,nome_pessoa,morada_pessoa) values (:new.bi_pessoa,:new.nome_pessoa,:new.morada_pessoa); insert into empregado(bi_pessoa,data_entrada_empregado) values(:new.bi_pessoa,:new.data_entrada_empregado); else RAISE_APPLICATION_ERROR(-20001,'Já existe uma pessoa com esse BI'); END IF; CREATE OR REPLACE TRIGGER up_v_empregado INSTEAD OF UPDATE ON v_empregado UPDATE pessoa SET nome_pessoa = :NEW.nome_pessoa, morada_pessoa = :NEW.morada_pessoa WHERE bi_pessoa = :NEW.bi_pessoa; UPDATE empregado SET data_entrada_empregado =
:NEW.data_entrada_empregado WHERE bi_pessoa = :NEW.bi_pessoa; CREATE OR REPLACE TRIGGER del_v_empregado INSTEAD OF DELETE ON v_empregado delete from pessoa where bi_pessoa = :old.bi_pessoa; Criadas estas estruturas em SQL command, há que criar em apex uma página do tipo Form, mais concretamente Form on a table with report em que a tabela/view escolhida será v_cliente. Em define Report Page, editar: Implementation: Interactive; em Page Name: Relatório de Clientes; Em breadcrumbs: breadcrumb; em Parent key: inicio (a página inicial); Next; Em Define Report Page: Do not use tabs; Next. Em Define Report Page: selecionar todas as colunas; Next; Em create Report Page, aceitar o icon por defeito. Next. Em Define Form Page, editar: Page name: Criar/Editar clientes; em Region Title: Criar/Editar: clientes; Em Entry Name: Criar/Editar clientes. Next. Em primary Key: bi_pessoa; Next; Em Define the source for the primary key columns, seleccionar Existing Trigger ; Next; selecionar todas as colunas; next; Em identify Process Options, aceitar inserção, update e remoção. Next; Finish. Alterar o item bi_pessoa do form: Em Display as, escolher Number field em vez de hidden. If you create these structures in SQL command, you must create a page of the Form type, namely "Form on a table
with report", in which the chosen table / view will be v_cliente. Under Report Page, edit: Implementation: Interactive; In Page Name: Customer Report; In breadcrumbs: breadcrumb; In Parent key: "home" (the home page); Next; In Define Report Page: Do not use tabs; Next. Under Define Report Page: select all columns; Next; In create Report Page, accept the default icon. Next. In Define Form Page, edit: Page name: Create / Edit Clients; In Region Title: Create / Edit: clients; In Entry Name: Create / Edit Clients. Next. In primary Key: bi_pessoa; Next; In "Define the source for the primary key columns", select "Existing Trigger"; Next; Select all columns; Next; In identify Process Options, accept insertion, update, and removal. Next; Finish. Change the pessoa s bi_pessoa item: In Display as, choose "Number field" instead of hidden. 1ª nota final: esta solução não impede que, em ambiente SQL, fora do Apex, seja possível inserir um tuplo na tabela pessoa sem que seja inserido o correspondente tuplo na tabela cliente ou na tabela empregado. Uma solução que abrangesse este caso seria mais complexa e está fora do âmbito deste curso. No entanto, esta é uma solução que resolve o problema em ambiente Apex. 2ª Nota final: há que ter em conta que, de forma garantir que o tuplo relativo a uma pessoa não é inserido duas vezes, basta que o trigger instead_of insert on v_cliente seja definido simplesmente por First final note: This solution does not prevent a SQL instance outside Apex from inserting a tuple in the pessoa table without inserting the corresponding tuple in the cliente table or in the table empregado. A solution covering this case would be more complex and is out of the scope of this course. However, this is a solution that solves the problem in the Apex environment.
2. Final note: It should be taken into account that, in order to ensure that the tuple relative to a pessoa is not inserted twice, it suffices that the trigger instead_of insert on v_client is defined simply by CREATE OR REPLACE TRIGGER ins_v_cliente INSTEAD OF INSERT ON v_cliente insert into pessoa(bi_pessoa,nome_pessoa,morada_pessoa) values (:new.bi_pessoa,:new.nome_pessoa,:new.morada_pessoa); insert into cliente(bi_pessoa,nr_cliente) values(:new.bi_pessoa,:new.nr_cliente); O mesmo se aplica ao trigger instead_of insert on v_cliente mas com a devida adaptação. The same applies to the trigger instead_of insert on v_client but with the appropriate adaptation. A razão pela qual se definiu da forma indicada, reside na importância de chamar a atenção para a necessidade de, quando se desenham interfaces para o utilizador final (não informático), ser útil que este possa compreender as mensagens de erro, sem necessidade de saber o que são chaves primárias, etc.. Daí a mensagem sem pormenor técnico informático: 'Já existe uma pessoa com esse BI'. Contudo, é de referir que a técnica usada para este efeito e que consiste na consulta prévia à tabela pessoa, para verificar que o tuplo que se quer inserir não foi já inserido anteriormente, é uma técnica com um custo computacional que se deve evitar, havendo técnicas computacionalmente mais leves para o fazer. Porém, tais téncicas saem já fora do âmbito deste curso. The reason why it has been defined in the way indicated is that it is important to draw attention to the need, when designing interfaces for the end user (not a computer programmer), to be able to understand the error messages without needing to know what are primary keys, etc... Hence the message without technical
computer detail: Já existe uma pessoa com esse BI'. However, it should be noted that the technique used for this purpose, which consists of the previous consultation to the pessoa table, to verify that the tuple that is to be inserted has not been inserted previously, is a technique with a computational cost that must be avoided, if other computing techniques to do so in a computationally lighter way. However, such techniques are outside the scope of this course.