Oracle PL/SQL and SQL XML Generation Techniques
Classified in Computers
Written on in
English with a size of 4.85 KB
PL/SQL Components for Race Management
The following PL/SQL objects demonstrate core database programming concepts, including custom functions for calculation, procedures for data manipulation and ranking, and triggers for auditing.
1. Calculating Global Time: The tempo_global Function
This function calculates the total elapsed time for a specific pilot by summing the duration of all stages recorded in the TempoEtapas table. It includes robust error handling using SQLCODE.
CREATE FUNCTION tempo_global (ID_piloto IN NUMBER)
RETURN NUMBER
IS
soma_tempo NUMBER;
coderro NUMBER;
CURSOR c1 IS
SELECT tempo_inicio, tempo_fim
FROM TempoEtapas
WHERE Piloto_idPiloto = ID_piloto;
BEGIN
soma_tempo := 0;
FOR item IN c1 LOOP
soma_tempo := soma_tempo + (item.tempo_fim - item.tempo_inicio);
END LOOP;
RETURN soma_tempo;
EXCEPTION
WHEN OTHERS THEN
coderro := SQLCODE;
RAISE_APPLICATION_ERROR(-20002, 'Código erro: ' || coderro);
END;2. Generating the Dakar Podium: The dakar_podium Procedure
This procedure determines the ranking for the Dakar event based on the calculated global time (using the tempo_global function). It filters pilots who have completed 14 stages, calculates their total time, and inserts the results (position, first name, last name, total time, and formatted time) into a temporary table (temp).
CREATE OR REPLACE PROCEDURE dakar_podium (categoria IN VARCHAR2) IS
posicao NUMBER := 1;
nomecompleto VARCHAR2(45);
pnome VARCHAR2(45);
unome VARCHAR2(45);
tempoglobal NUMBER;
CURSOR C1 IS
SELECT nome, tempo_global(id_Piloto) AS tglobal
FROM pilotos p
JOIN tempoetapas te ON te.Pilotos.idPiloto = p.id_Piloto
WHERE (SELECT COUNT(*) FROM tempoetapas WHERE Pilotos.idPiloto = p.idPiloto) = 14
ORDER BY tempo_global(id_Piloto) ASC;
BEGIN
DELETE FROM temp;
OPEN C1;
LOOP
FETCH C1 INTO nomecompleto, tempoglobal;
EXIT WHEN C1%NOTFOUND;
pnome := SUBSTR(nomecompleto, 1, INSTR(nomecompleto, ' ') - 1);
unome := SUBSTR(nomecompleto, INSTR(nomecompleto, ' ', -1) + 1);
INSERT INTO temp (num1, str1, str2, num2, str3)
VALUES (posicao, pnome, unome, tempoglobal, TO_CHAR(TO_DATE(tempoglobal, 'SSSSS'), 'HH24:MI:SS'));
posicao := posicao + 1;
END LOOP;
END;3. Auditing Data Changes: The loggar Trigger
This AFTER row-level trigger records all INSERT, UPDATE, and DELETE operations performed on the TempoEtapas table into a Log table. It also includes a cleanup mechanism to remove log entries older than 5 days.
CREATE OR REPLACE TRIGGER loggar
AFTER UPDATE OR DELETE OR INSERT ON TempoEtapas
FOR EACH ROW
BEGIN
-- Delete log entries older than 5 days
DELETE FROM LOG WHERE SYSDATE - data_alteracao > 5;
IF INSERTING THEN
INSERT INTO Log VALUES (USER, SYSDATE, 'INSERT', :NEW.etapa_idetapa, :NEW.piloto_idPiloto, :NEW.tempo_inicio, :NEW.tempo_fim);
ELSIF UPDATING THEN
INSERT INTO Log VALUES (USER, SYSDATE, 'UPDATE', :OLD.etapa_idetapa, :OLD.piloto_idPiloto, :OLD.tempo_inicio, :OLD.tempo_fim);
ELSIF DELETING THEN
INSERT INTO Log VALUES (USER, SYSDATE, 'DELETE', :OLD.etapa_idetapa, :OLD.piloto_idPiloto, :OLD.tempo_inicio, :OLD.tempo_fim);
END IF;
END;SQL Techniques: Generating XML Data
These SQL queries demonstrate how to use Oracle's XML functions (specifically XMLELEMENT) to structure relational data into XML format, joining DEPARTMENTS and EMPLOYEES tables.
4. Basic XML Generation using XMLELEMENT
This query generates an XML structure where each row represents a DEPARTMENT containing nested Employee elements, filtered for departments 30 and 40.
SELECT
XMLELEMENT("DEPARTMENT",
XMLELEMENT("Employee", job_id, last_name)
)
FROM DEPARTMENTS
JOIN employees ON departments.department_id = employees.department_id
WHERE department_id = 30 OR department_id = 40
ORDER BY last_name;5. XML Generation with Attributes using XMLATTRIBUTES
This query enhances the XML output by adding the department_id as an attribute named deptno to the DEPARTMENT element.
SELECT
XMLELEMENT("DEPARTMENT",
XMLATTRIBUTES(department_id AS "deptno"),
XMLELEMENT("Employee", job_id, last_name)
)
FROM DEPARTMENTS
JOIN employees ON departments.department_id = employees.department_id
WHERE department_id = 30 OR department_id = 40
ORDER BY last_name;