Cours
PL/SQL, qui est l'extension du langage SQL procédural d'Oracle, est un élément essentiel à connaître si vous envisagez de travailler avec des bases de données Oracle. Cela s'applique aux postes clés tels que ceux d'administrateur de base de données, de développeur et d'analyste de données, qui doivent tous gérer une logique métier complexe au sein de la base de données.
Je pense que les recruteurs évaluent les candidats sur trois aspects principaux :
- Compréhension conceptuelle : Principes fondamentaux, types de données, structures de contrôle et gestion des exceptions.
- Compétences pratiques en codage : Écrire des procédures stockées, des fonctions, des déclencheurs et des paquets efficaces.
- Considérations relatives aux performances : Optimisation du code PL/SQL afin d'améliorer le temps d'exécution, de minimiser la consommation de ressources et d'éviter les erreurs telles que les changements de contexte excessifs entre SQL et PL/SQL.
Pour vous aider, je vous propose un guide sur les questions d'entretien relatives au langage PL/SQL. Je commencerai par les concepts fondamentaux, puis j'aborderai des sujets plus avancés tels que le traitement en masse, le SQL dynamique et l'optimisation des performances.
Si vous souhaitez acquérir les concepts fondamentaux de la base de données Oracle, je vous recommande de suivre notre cours Introduction à Oracle SQL, qui constitue une ressource essentielle pour apprendre à interagir avec la base de données Oracle et comprendre comment celle-ci utilise PL/SQL pour traiter les requêtes.
Questions d'entretien pour débutants en PL/SQL
Au cours de la phase initiale de l'entretien, le recruteur peut vous poser des questions fondamentales afin d'évaluer vos connaissances des concepts de base relatifs aux bases de données et au langage PL/SQL. Veuillez étudier ces questions et y répondre afin de vous préparer pour la phase initiale de l'entretien.
1. Qu'est-ce que PL/SQL ?
PL/SQL est l'extension procédurale d'Oracle pour SQL. Contrairement au langage SQL, qui est déclaratif et axé sur la récupération et la manipulation des données, PL/SQL permet aux développeurs de mettre en œuvre une logique procédurale, ce qui en fait un outil puissant pour écrire des règles métier complexes au sein de la base de données. Il prend en charge les variables, les boucles, les conditions, la gestion des exceptions et la programmation modulaire via des procédures, des fonctions et des paquets.
2. Quelle est la structure de base d'un bloc PL/SQL ?
Un bloc PL/SQL est l'unité fondamentale d'exécution en PL/SQL. Il se compose de quatre sections principales :
-
DECLARE(Facultatif) : Utilisé pour définir des variables, des constantes, des curseurs et des types définis par l'utilisateur. -
BEGIN: Section exécutable où sont écrites les requêtes SQL et les instructions procédurales. -
EXCEPTION(Facultatif) : Gère les erreurs d'exécution et les exceptions afin d'assurer une récupération en douceur après une erreur. -
END;: Indique la fin du bloc.
3. Quels sont les types de données PL/SQL essentiels ?
PL/SQL prend en charge divers types de données, classés comme suit :
-
Types scalaires: Types à valeur unique tels que
NUMBER,VARCHAR2,DATE,BOOLEAN. -
Types composites : Collections telles que
RECORD(structures personnalisées) etTABLE/VARRAY(tableaux). -
Types de référence : Pointeurs vers des objets de base de données, tels que
REF CURSORpour le traitement dynamique des requêtes.
4. Quelles sont les structures de contrôle de base en PL/SQL ?
PL/SQL comprend plusieurs structures de contrôle qui facilitent la gestion du flux d'un programme :
-
Boucles : Il s'agit notamment de
LOOP,FOR LOOPetWHILE LOOP, qui permettent l'exécution répétitive d'instructions. -
Instructions conditionnelles : Il s'agit notamment des instructions «
IF» et «CASE», qui exécutent différents blocs de code en fonction de conditions. La fonction DECODE() constitue un autre exemple pertinent de conditionnel qui mérite d'être étudié.
Questions d'entretien de niveau intermédiaire sur PL/SQL
Après avoir abordé les questions fondamentales, passons maintenant à des questions d'entretien de niveau intermédiaire sur les structures de données. Après avoir évalué vos connaissances de base, les examinateurs vont maintenant évaluer votre maîtrise technique dans la mise en œuvre et l'utilisation des concepts PL/SQL.
5. Quelle est la différence entre les procédures stockées et les fonctions ?
Les procédures stockées et les fonctions sont toutes deux des blocs de code PL/SQL réutilisables, mais elles ont des objectifs assez différents.
Les procédures stockées sont utilisées pour effectuer des opérations qui ne renvoient pas de valeur, telles que l'insertion, la mise à jour ou la suppression de données. Ils sont utilisés pour des tâches qui modifient des données ou effectuent des opérations complexes sans renvoyer de résultat.
Par exemple, la procédure ci-dessous met à jour l'salary e de l'employé avec l'employee_id e donnée en ajoutant l'p_increment e spécifiée de manière à ce que le salaire soit mis à jour dynamiquement en fonction des paramètres d'entrée.
CREATE PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER) AS
BEGIN
-- Update the salary of the employee with the given ID
UPDATE employees
SET salary = salary + p_increment
WHERE employee_id = p_emp_id;
END;
Les fonctions, quant à elles, renvoient une valeur après avoir effectué des opérations. Ils sont adaptés aux calculs ou à la récupération de données qui nécessitent un résultat.
La fonction ci-dessous simplifie la récupération du salaire d'un employé, ce qui la rend réutilisable dans les requêtes SQL ou d'autres procédures.
CREATE FUNCTION get_employee_salary(p_emp_id NUMBER) RETURN NUMBER AS
v_salary NUMBER;
BEGIN
-- Retrieve the salary for the given employee ID
SELECT salary INTO v_salary
FROM employees
WHERE employee_id = p_emp_id;
-- Return the retrieved salary
RETURN v_salary;
END;
6. Que sont les paquets PL/SQL ?
Les packages PL/SQL sont des collections de procédures, de fonctions et de variables associées qui encapsulent du code afin d'améliorer l'organisation et la réutilisabilité. Ils se composent de deux parties :
- Spécifications de l'emballage : Déclare les éléments publics (procédures, fonctions, variables).
- Corps du paquet : Contient les détails de mise en œuvre des procédures et des fonctions déclarées dans la spécification.
Par exemple, la requête ci-dessous crée un package employee_pkg qui définit une procédure permettant d'augmenter le salaire d'un employé et une fonction permettant de récupérer le nombre total d'employés, dont les implémentations doivent être fournies dans le corps du package.
-- Create a package named 'employee_pkg'
CREATE PACKAGE employee_pkg AS
-- Procedure to increase an employee's salary by a percentage
PROCEDURE raise_salary(p_emp_id NUMBER, p_percent NUMBER);
-- Function to return the total number of employees
FUNCTION get_total_employees RETURN NUMBER;
END employee_pkg;
7. Que sont les déclencheurs PL/SQL ?
Les déclencheurs sont des blocs PL/SQL qui s'exécutent automatiquement en réponse à des événements spécifiques de la base de données, tels que des insertions, des mises à jour ou des suppressions. Les déclencheurs sont utilisés pour appliquer les règles métier. Ils sont également couramment utilisés pour effectuer des audits. Ils sont classés en plusieurs catégories :
- Déclencheurs au niveau des lignes : Exécutez une fois pour chaque ligne concernée.
- Déclencheurs au niveau des instructions : Exécutez une fois par instruction SQL, quel que soit le nombre de lignes concernées.
La requête ci-dessous crée un déclencheur d'AFTER UPDATE trg_salary_audit sur le tableau employees qui enregistre les modifications de salaire dans le tableau salary_audit table, en capturant l'ID de l'employé, l'ancien et le nouveau salaire, ainsi que l'horodatage de la mise à jour.
-- Create or replace a trigger 'trg_salary_audit'
CREATE OR REPLACE TRIGGER trg_salary_audit
AFTER UPDATE OF salary ON employees -- Fires after salary updates in 'employees' table
FOR EACH ROW -- Executes for each updated row
BEGIN
-- Inserts old and new salary details into 'salary_audit' table
INSERT INTO salary_audit (employee_id, old_salary, new_salary, change_date)
VALUES (:OLD.employee_id, :OLD.salary, :NEW.salary, SYSDATE);
END;
Veuillez étudier notre tutoriel sur les déclencheurs SQL afin d'être bien préparé au cas où les déclencheurs seraient abordés lors de l'entretien.
8. Quelles sont les méthodes de gestion des exceptions en PL/SQL ?
PL/SQL fournit des mécanismes de gestion des erreurs pour assurer la stabilité et prévenir les plantages. Les types d'exceptions comprennent les suivants :
-
Exceptions prédéfinies : Exceptions intégrées telles que
NO_DATA_FOUND,TOO_MANY_ROWSetZERO_DIVIDE. -
Exceptions définies par l'utilisateur : Les exceptions personnalisées sont déclarées à l'aide de
EXCEPTIONet levées à l'aide deRAISE.
Par exemple, le bloc PL/SQL suivant récupère le salaire d'un employé dont l'ID est 100, génère une exception personnalisée si le salaire est inférieur à 1 000 et gère les erreurs éventuelles, notamment les enregistrements d'employés manquants et les exceptions inattendues.
DECLARE
v_salary NUMBER; -- Variable to store the employee's salary
e_low_salary EXCEPTION; -- Custom exception for low salary
BEGIN
-- Retrieve salary of employee with ID 100
SELECT salary INTO v_salary FROM employees WHERE employee_id = 100;
-- Raise exception if salary is below 1000
IF v_salary < 1000 THEN
RAISE e_low_salary;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- Handle case where employee ID is not found
DBMS_OUTPUT.PUT_LINE('Employee not found.');
WHEN e_low_salary THEN -- Handle custom low salary exception
DBMS_OUTPUT.PUT_LINE('Salary is below the allowed threshold.');
WHEN OTHERS THEN -- Handle any other unexpected errors
DBMS_OUTPUT.PUT_LINE('An unexpected error occurred: ' || SQLERRM);
END;
Les meilleures pratiques en matière de gestion des exceptions comprennent les éléments suivants :
- Veuillez toujours anticiper les exceptions potentielles.
- Veuillez utiliser des messages d'erreur pertinents.
- Enregistrer les exceptions à des fins d'audit.
- Veuillez veiller à ce que le code de gestion des exceptions soit concis et axé sur la récupération.
9. Comment peut-on vérifier si une instruction UPDATE a été exécutée ou non ?
L'attribut SQL %NOTFOUND peut être utilisé pour déterminer si l'instruction UPDATE a réussi à modifier des enregistrements. Si la dernière instruction SQL exécutée n'a affecté aucune ligne, cette variable renvoie l'TRUE.
Par exemple, la requête ci-dessous met à jour le salaire des employés du département 10 en l'augmentant de 10 %, puis vérifie si des lignes ont été affectées par l'instruction d'UPDATE ion à l'aide de l'attribut %NOTFOUND. Si aucune ligne n'a été mise à jour, le message « Aucune ligne n'a été mise à jour » s'affiche. Si des lignes ont été mises à jour, le nombre de lignes concernées est affiché à l'aide de l'attribut SQL%ROWCOUNT.
DECLARE
-- Declare a variable to store the number of rows updated
rows_updated INTEGER;
BEGIN
-- Perform an UPDATE statement on the 'employees' table
UPDATE employees
SET salary = salary * 1.1
WHERE department_id = 10;
-- Check if any rows were updated by using %NOTFOUND
IF SQL%NOTFOUND THEN
-- If no rows were updated, print a message
DBMS_OUTPUT.PUT_LINE('No rows were updated.');
ELSE
-- If rows were updated, print how many rows were affected
rows_updated := SQL%ROWCOUNT; -- Store the number of rows updated
DBMS_OUTPUT.PUT_LINE(rows_updated || ' rows were updated.');
END IF;
END;
/
Questions d'entretien avancées sur PL/SQL
Explorons maintenant quelques questions d'entretien avancées, au cas où vous postuliez à un poste plus élevé qui exige davantage d'expérience.
10. Quelles sont les méthodes permettant d'optimiser les performances en PL/SQL ?
Il est essentiel de minimiser les changements de contexte entre SQL et PL/SQL afin d'optimiser les performances. Chaque commutation entraîne une surcharge qui peut ralentir les temps d'exécution, en particulier dans les situations impliquant des transitions fréquentes entre les deux.
11. Comment utilisez-vous les opérations groupées pour minimiser les changements de contexte ?
PL/SQL fournit des techniques de traitement en masse pour optimiser l'interaction entre SQL et PL/SQL en récupérant ou en modifiant plusieurs lignes à la fois.
Par exemple, le bloc PL/SQL ci-dessous récupère tous les employés du département 10 à l'aide d' BULK COLLECT, les place dans une collection et les parcourt pour imprimer le nom de chaque employé, améliorant ainsi les performances en minimisant les changements de contexte entre SQL et PL/SQL.
DECLARE
-- Define a table-type collection based on the 'employees' table structure
TYPE emp_table IS TABLE OF employees%ROWTYPE;
v_emps emp_table; -- Declare a variable of this type
BEGIN
-- Bulk fetch employees from department 10 into the collection
SELECT * BULK COLLECT INTO v_emps FROM employees WHERE department_id = 10;
-- Loop through the collection and print employee names
FOR i IN 1..v_emps.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_emps(i).employee_name);
END LOOP;
END;
De plus, ce bloc PL/SQL utilise la fonction FORALL pour effectuer une mise à jour groupée, augmentant le salaire de 10 % pour les employés dont les identifiants sont 101, 102 et 103.
DECLARE
-- Define a table-type collection for employee IDs
TYPE t_emp_ids IS TABLE OF employees.employee_id%TYPE;
-- Initialize collection with specific employee IDs
v_emp_ids t_emp_ids := t_emp_ids(101, 102, 103);
BEGIN
-- Bulk update salaries by 10% for specified employee IDs
FORALL i IN 1..v_emp_ids.COUNT
UPDATE employees SET salary = salary * 1.10 WHERE employee_id = v_emp_ids(i);
END;
12. Qu'est-ce que le SQL dynamique et les curseurs de référence ?
Le SQL dynamique permet d'exécuter des instructions SQL de manière dynamique lors de l'exécution, ce qui est particulièrement utile lorsque l'on traite des noms de tableaux, des colonnes ou des structures de requêtes variables.
Le bloc PL/SQL suivant utilise le SQL dynamique pour compter le nombre de lignes dans le tableau employees et affiche le résultat. J'apprécie cette approche car elle offre une certaine flexibilité.
DECLARE
v_table_name VARCHAR2(50) := 'employees'; -- Store table name
v_count NUMBER; -- Variable to hold row count
BEGIN
-- Dynamically count rows in the specified table
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || v_table_name INTO v_count;
-- Print the total count
DBMS_OUTPUT.PUT_LINE('Total Employees: ' || v_count);
END;
Les curseurs de référence sont des curseurs dynamiques qui peuvent être ouverts, récupérés et fermés lors de l'exécution, ce qui permet le transfert des résultats de requêtes entre les unités de programme.
Le bloc PL/SQL ci-dessous utilise une requête SQL ( REF CURSOR ) pour récupérer et afficher les noms des employés du département 20. Le curseur est ouvert de manière dynamique, parcouru à l'aide d'une boucle, puis fermé après traitement.
DECLARE
-- Define a REF CURSOR type
TYPE emp_ref_cursor IS REF CURSOR;
v_cursor emp_ref_cursor; -- Declare a cursor variable
v_name employees.employee_name%TYPE; -- Variable to store employee name
BEGIN
-- Open the cursor for employees in department 20
OPEN v_cursor FOR SELECT employee_name FROM employees WHERE department_id = 20;
-- Fetch and print employee names in a loop
LOOP
FETCH v_cursor INTO v_name;
EXIT WHEN v_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Employee: ' || v_name);
END LOOP;
-- Close the cursor
CLOSE v_cursor;
END;
13. Comment gérez-vous les erreurs de mutation de tableau ?
Des erreurs de mutation de table surviennent lorsqu'un déclencheur tente de modifier la table sur laquelle il est déclenché. Un déclencheur composé permet de diviser l'exécution du déclencheur en plusieurs phases, telles que BEFORE, AFTER et FOR EACH ROW, afin d'éviter les problèmes de modification directe.
Le déclencheur composé ci-dessous enregistre efficacement les modifications de salaire dans le tableau salary_audit en collectant les données avant chaque mise à jour de ligne et en effectuant une insertion en masse après l'instruction, ce qui réduit les changements de contexte et améliore les performances.
CREATE OR REPLACE TRIGGER trg_salary_audit
FOR UPDATE OF salary ON employees -- Trigger fires on salary updates
COMPOUND TRIGGER
-- Declare an associative array to store audit records
TYPE t_salary_audit IS TABLE OF salary_audit%ROWTYPE INDEX BY PLS_INTEGER;
v_audit_data t_salary_audit;
v_idx PLS_INTEGER := 0;
-- Before updating each row, store old and new salary details
BEFORE EACH ROW IS
BEGIN
v_idx := v_idx + 1;
v_audit_data(v_idx).employee_id := :OLD.employee_id;
v_audit_data(v_idx).old_salary := :OLD.salary;
v_audit_data(v_idx).new_salary := :NEW.salary;
v_audit_data(v_idx).change_date := SYSDATE;
END BEFORE EACH ROW;
-- After the statement, insert all audit records in bulk
AFTER STATEMENT IS
BEGIN
FORALL i IN 1..v_idx
INSERT INTO salary_audit VALUES v_audit_data(i);
END AFTER STATEMENT;
END trg_salary_audit;
14. Qu'est-ce que la surcharge en PL/SQL ?
La surcharge permet de définir plusieurs procédures ou fonctions portant le même nom mais avec des paramètres différents au sein d'un même paquet. Cela améliore la lisibilité et la maintenabilité du code en offrant plusieurs façons d'effectuer des opérations similaires.
Dans la requête ci-dessous, le corps du package implémente deux procédures surchargées nommées ` update_salary` : L'une augmente le salaire d'un employé d'un montant spécifié, tandis que l'autre définit un nouveau salaire avec une date d'entrée en vigueur, mettant à jour la table d' employees s en conséquence.
-- Create the package specification
CREATE OR REPLACE PACKAGE emp_pkg AS
-- Procedure to increment salary by a specified amount
PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER);
-- Overloaded procedure to set a new salary with an effective date
PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER, p_effective_date DATE);
END emp_pkg;
/
-- Create the package body
CREATE OR REPLACE PACKAGE BODY emp_pkg AS
-- Procedure to increment salary by a specified amount
PROCEDURE update_salary(p_emp_id NUMBER, p_increment NUMBER) AS
BEGIN
UPDATE employees
SET salary = salary + p_increment
WHERE employee_id = p_emp_id;
END update_salary;
-- Overloaded procedure to set a new salary with an effective date
PROCEDURE update_salary(p_emp_id NUMBER, p_new_salary NUMBER, p_effective_date DATE) AS
BEGIN
UPDATE employees
SET salary = p_new_salary, last_update = p_effective_date
WHERE employee_id = p_emp_id;
END update_salary;
END emp_pkg;
/
15. Quelles sont les directives du compilateur et les pragmas en PL/SQL ?
PL/SQL fournit des directives de compilation (PRAGMA) pour optimiser le code et gérer les exceptions. Les pragmas courants comprennent :
-
PRAGMA EXCEPTION_INIT: Associe une exception définie par l'utilisateur à un code d'erreur Oracle. -
PRAGMA SERIALLY_REUSABLE: Optimise l'utilisation de la mémoire du package pour une meilleure évolutivité.
Le bloc PL/SQL ci-dessous gère l'insertion d'un employé avec un salaire non valide à l'aide d'une exception personnalisée e_invalid_salary mappée au code d'erreur -20001. Si l'exception est levée, un message d'erreur s'affiche.
DECLARE
e_invalid_salary EXCEPTION; -- Declare custom exception for invalid salary
PRAGMA EXCEPTION_INIT(e_invalid_salary, -20001); -- Associate exception with error code -20001
BEGIN
-- Attempt to insert an employee with invalid salary
INSERT INTO employees (employee_id, salary) VALUES (999, -1000);
EXCEPTION
-- Handle the custom exception and print a message
WHEN e_invalid_salary THEN
DBMS_OUTPUT.PUT_LINE('Invalid salary detected!');
END;
16. Quelles sont les différentes méthodes permettant de tracer et de déboguer du code PL/SQL ?
PL/SQL fournit plusieurs packages intégrés pour le traçage et le débogage des performances du code. Les méthodes courantes comprennent l'utilisation de DBMS_TRACE pour suivre le flux d'exécution, DBMS_APPLICATION_INFO pour surveiller l'activité de la session et DBMS_SESSION pour recueillir des informations de diagnostic au niveau de la session.
La requête ci-dessous active d'abord le traçage SQL à l'aide de la commande « DBMS_SESSION.set_sql_trace(TRUE) », puis définit les informations de session spécifiques au client avec la commande « DBMS_APPLICATION_INFO.set_client_info() » à des fins de surveillance. Le bloc PL/SQL est exécuté, ce qui simule une opération d'UPDATE. Enfin, il désactive le traçage après l'exécution à l'aide de l'instruction « DBMS_SESSION.set_sql_trace(FALSE) ».
-- Enable tracing for the current session using DBMS_SESSION
BEGIN
-- Start session-level tracing
DBMS_SESSION.set_sql_trace(TRUE);
END;
/
-- Set application information using DBMS_APPLICATION_INFO
BEGIN
-- Set the application name and action for session monitoring
DBMS_APPLICATION_INFO.set_client_info('Trace Debug Session');
DBMS_APPLICATION_INFO.set_action('Debugging PL/SQL Code');
END;
/
-- Example PL/SQL block that simulates a process for debugging
DECLARE
v_employee_id NUMBER := 100;
BEGIN
-- Example query to fetch employee details
FOR rec IN (SELECT first_name, last_name FROM employees WHERE employee_id = v_employee_id) LOOP
DBMS_OUTPUT.put_line('Employee: ' || rec.first_name || ' ' || rec.last_name);
END LOOP;
-- Simulate some logic that could be traced
IF v_employee_id = 100 THEN
DBMS_OUTPUT.put_line('Employee ID is 100');
END IF;
END;
/
-- Disable tracing after the session is complete
BEGIN
-- Stop session-level tracing
DBMS_SESSION.set_sql_trace(FALSE);
END;
/
Questions d'entretien PL/SQL basées sur des scénarios
Dans les applications d'entreprise réelles, PL/SQL est utilisé pour gérer des logiques métier complexes. Les recruteurs évaluent fréquemment la capacité d'un candidat à appliquer PL/SQL dans des scénarios pratiques. Vous trouverez ci-dessous quelques défis majeurs, ainsi que des stratégies pour les relever.
Pour cette dernière section, si vous passez un entretien, je vous encourage à réfléchir à la manière de répondre aux questions en suivant ce modèle, mais essayez bien sûr d'adapter votre réponse à votre secteur d'activité spécifique ou de refléter votre propre expérience. Il en va de même si vous interviewez un candidat et que vous souhaitez obtenir des suggestions sur la manière de poser une question et d'évaluer la pertinence de la réponse. Dans ce cas, j'espère que cette section vous inspirera tant pour vos questions que pour vos critères d'évaluation.
Améliorez les compétences SQL de votre équipe
Formez votre équipe à SQL avec DataCamp for Business. Une formation complète, des projets pratiques et des indicateurs de performance détaillés pour votre organisation.

17. Comment concevez-vous des déclencheurs dans des environnements hautement concurrents ?
Considérons un scénario dans lequel vous devez appliquer une règle métier stipulant que le salaire d'un employé ne peut être mis à jour plus d'une fois par jour. Cependant, la base de données connaît une forte concurrence des transactions, et un simple déclencheur pourrait entraîner des conflits ou des problèmes de performances.
Au lieu d'utiliser un déclencheur au niveau des lignes qui s'active à chaque mise à jour et peut ralentir les performances, il est recommandé d'utiliser un déclencheur au niveau des instructions avec une table de journalisation afin d'éviter plusieurs mises à jour de salaire au cours d'une même journée.
Par exemple, le déclencheur ci-dessous empêche les mises à jour multiples du salaire d'un employé le même jour en vérifiant la table salary_update_log avant d'autoriser une mise à jour. Si le salaire a déjà été mis à jour aujourd'hui, une erreur est générée ; sinon, la date de mise à jour est enregistrée.
-- Create a table to log the last salary update for each employee
CREATE TABLE salary_update_log (
employee_id NUMBER PRIMARY KEY, -- Employee ID as primary key
last_update DATE -- Date of the last salary update
);
-- Create or replace a compound trigger to prevent multiple salary updates on the same day
CREATE OR REPLACE TRIGGER trg_prevent_multiple_salary_update
FOR UPDATE OF salary ON employees
COMPOUND TRIGGER
-- Declare a variable to store last salary update date per row
TYPE emp_log_type IS TABLE OF DATE INDEX BY PLS_INTEGER;
emp_log emp_log_type;
BEFORE STATEMENT IS
BEGIN
-- Load existing salary update logs into memory for reference
FOR rec IN (SELECT employee_id, last_update FROM salary_update_log) LOOP
emp_log(rec.employee_id) := rec.last_update;
END LOOP;
END BEFORE STATEMENT;
BEFORE EACH ROW IS
BEGIN
-- Check if an entry exists for this employee
IF emp_log.EXISTS(:NEW.employee_id) THEN
-- Validate if salary was updated today
IF emp_log(:NEW.employee_id) = TRUNC(SYSDATE) THEN
RAISE_APPLICATION_ERROR(-20010, 'Salary can only be updated once per day');
ELSE
-- Update log in memory
emp_log(:NEW.employee_id) := TRUNC(SYSDATE);
END IF;
ELSE
-- Insert a new log entry into memory
emp_log(:NEW.employee_id) := TRUNC(SYSDATE);
END IF;
END BEFORE EACH ROW;
AFTER STATEMENT IS
BEGIN
-- Apply changes to the log table after all row updates
FOR i IN emp_log.FIRST .. emp_log.LAST LOOP
MERGE INTO salary_update_log l
USING (SELECT i AS employee_id, emp_log(i) AS last_update FROM DUAL) s
ON (l.employee_id = s.employee_id)
WHEN MATCHED THEN
UPDATE SET l.last_update = s.last_update
WHEN NOT MATCHED THEN
INSERT (employee_id, last_update) VALUES (s.employee_id, s.last_update);
END LOOP;
END AFTER STATEMENT;
END trg_prevent_multiple_salary_update;
L'exemple ci-dessus permettrait de réduire le verrouillage au niveau des lignes et de minimiser les conflits de transactions lors des mises à jour en masse.
18. Comment divisez-vous les transactions importantes en plusieurs parties plus petites pour garantir leur fiabilité ?
Envisagez un scénario dans lequel un système bancaire doit procéder à une mise à jour massive afin d'ajuster les taux d'intérêt de millions de comptes clients. L'exécution d'une seule transaction volumineuse peut entraîner le verrouillage des tables pendant une durée excessive ou provoquer des échecs de restauration.
Dans ce cas, veuillez utiliser le traitement en masse avec COMMIT par lots afin de traiter les données de manière incrémentielle et d'éviter les conflits.
Le bloc PL/SQL ci-dessous met en œuvre la solution en utilisant BULK COLLECT pour récupérer les identifiants de compte, puis les parcourt pour mettre à jour le taux d'intérêt de 5 %. Il valide les modifications toutes les 1 000 mises à jour afin d'améliorer les performances et de réduire l'utilisation des ressources. Une validation finale garantit que toutes les mises à jour restantes sont enregistrées.
DECLARE
-- Define a collection type for account IDs
TYPE t_accounts IS TABLE OF NUMBER; -- Use NUMBER instead of referencing accounts.account_id
v_account_ids t_accounts; -- Variable to store account IDs
v_batch_size CONSTANT NUMBER := 1000; -- Batch size for commits
BEGIN
-- Bulk collect all account IDs into the collection
SELECT account_id BULK COLLECT INTO v_account_ids FROM accounts;
-- Loop through each account ID to update the interest rate
FOR i IN 1 .. v_account_ids.COUNT LOOP
UPDATE accounts
SET interest_rate = interest_rate * 1.05 -- Increase interest rate by 5%
WHERE account_id = v_account_ids(i);
-- Commit after every 1000 updates
IF MOD(i, v_batch_size) = 0 THEN
COMMIT;
END IF;
END LOOP;
COMMIT; -- Final commit for any remaining updates
END;
/
Cette solution garantirait la fiabilité des systèmes financiers tels que la paie en empêchant les échecs de transaction.
19. Comment organisez-vous une logique complexe en paquets pour faciliter la maintenance ?
Une entreprise de vente au détail doit mettre en place un système de traitement des commandes qui comprend plusieurs étapes : Vérifier la disponibilité des stocks, réserver des articles, calculer les remises et enregistrer l'historique des transactions.
Au lieu de rédiger des procédures autonomes distinctes, il est nécessaire d'organiser cette logique de manière structurée et facile à maintenir. Par conséquent, veuillez utiliser les packages PL/SQL pour encapsuler les procédures et fonctions associées, améliorant ainsi la réutilisabilité et la maintenabilité du code.
La spécification du package ci-dessous définit les fonctions et procédures pour le traitement des commandes, y compris la vérification des stocks, la réservation des stocks, le calcul des remises et l'enregistrement des statuts des transactions. Il offre une approche modulaire pour la gestion des tâches liées aux commandes.
-- Create a package specification for order processing functions and procedures
CREATE PACKAGE order_processing_pkg AS
-- Function to check if enough inventory is available for the product
FUNCTION check_inventory(p_product_id NUMBER, p_quantity NUMBER) RETURN BOOLEAN;
-- Procedure to reserve stock for a specific order
PROCEDURE reserve_stock(p_order_id NUMBER, p_product_id NUMBER, p_quantity NUMBER);
-- Function to calculate discount based on customer and total amount
FUNCTION calculate_discount(p_customer_id NUMBER, p_total_amount NUMBER) RETURN NUMBER;
-- Procedure to log the status of a transaction
PROCEDURE log_transaction(p_order_id NUMBER, p_status VARCHAR2);
END order_processing_pkg;
Nous utilisons ensuite le corps du paquet suivant pour implémenter les fonctions et procédures définies dans la spécification du paquet. Il gère des tâches essentielles telles que la vérification de la disponibilité des stocks, la réservation des stocks, le calcul des remises et l'enregistrement du statut des transactions, garantissant ainsi le bon déroulement des opérations de traitement des commandes.
-- Create the package body implementing the functions and procedures for order processing
CREATE PACKAGE BODY order_processing_pkg AS
-- Function to check if sufficient inventory is available for the product
FUNCTION check_inventory(p_product_id NUMBER, p_quantity NUMBER) RETURN BOOLEAN AS
v_available_qty NUMBER; -- Variable to store available quantity
BEGIN
-- Retrieve the available quantity from inventory
SELECT stock_quantity INTO v_available_qty FROM inventory WHERE product_id = p_product_id;
-- Return true if enough stock is available, otherwise false
RETURN v_available_qty >= p_quantity;
END check_inventory;
-- Procedure to reserve stock for a specific order
PROCEDURE reserve_stock(p_order_id NUMBER, p_product_id NUMBER, p_quantity NUMBER) AS
BEGIN
-- Deduct the ordered quantity from the inventory
UPDATE inventory SET stock_quantity = stock_quantity - p_quantity WHERE product_id = p_product_id;
END reserve_stock;
-- Function to calculate a discount based on the total order amount
FUNCTION calculate_discount(p_customer_id NUMBER, p_total_amount NUMBER) RETURN NUMBER AS
v_discount NUMBER := 0; -- Initialize discount to 0
BEGIN
-- Apply 10% discount if the total amount is greater than 500
IF p_total_amount > 500 THEN
v_discount := p_total_amount * 0.10;
END IF;
-- Return the calculated discount
RETURN v_discount;
END calculate_discount;
-- Procedure to log the transaction status
PROCEDURE log_transaction(p_order_id NUMBER, p_status VARCHAR2) AS
BEGIN
-- Insert a log entry for the order status
INSERT INTO order_log (order_id, status, log_date) VALUES (p_order_id, p_status, SYSDATE);
END log_transaction;
END order_processing_pkg;
20. Comment gérez-vous les blocages dans les systèmes à haut débit de transactions ?
Considérons un scénario dans lequel un système financier met fréquemment à jour plusieurs tableaux connexes simultanément. Les blocages surviennent lorsque deux transactions attendent mutuellement des ressources verrouillées, ce qui entraîne des goulots d'étranglement au niveau des performances.
Pour résoudre ce problème, veuillez toujours verrouiller les lignes dans un ordre cohérent d'une transaction à l'autre. Veuillez également utiliser la clause « NOWAIT » ou « SKIP LOCKED » pour éviter une attente indéfinie.
Par exemple, le bloc PL/SQL ci-dessous tente de verrouiller une ligne spécifique dans le tableau des comptes pour la mise à jour à l'aide de la clause ` FOR UPDATE NOWAIT `, ce qui entraîne l'échec immédiat de la transaction si une autre session verrouille déjà la ligne. Après le verrouillage, il met à jour le statut de la transaction et valide les modifications. Si une erreur survient, il intercepte l'exception et affiche un message d'erreur.
DECLARE
v_balance NUMBER(15,2); -- Declare variable to store the account balance
BEGIN
-- Lock the account row for update to prevent other sessions from modifying it
SELECT balance INTO v_balance FROM accounts
WHERE account_id = 101 FOR UPDATE NOWAIT;
-- Update the transaction status to 'Processed' for all transactions related to this account
UPDATE transactions
SET status = 'Processed'
WHERE account_id = 101 AND status = 'Pending'; -- Update only pending transactions
COMMIT; -- Commit the changes
EXCEPTION
-- Handle errors, such as locking issues or unexpected exceptions
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Transaction failed: ' || SQLERRM);
ROLLBACK; -- Ensure rollback in case of failure
END;
/
De même, ce bloc PL/SQL traite les transactions en attente en les verrouillant pour mise à jour avec l'instruction ` FOR UPDATE SKIP LOCKED`, ce qui lui permet d'ignorer les lignes déjà verrouillées par d'autres sessions. Il met à jour le statut de chaque transaction en « En cours de traitement » et valide les modifications à la fin.
DECLARE
-- Declare a cursor to select pending transactions and lock rows for update
CURSOR c_pending_txns IS
SELECT transaction_id FROM transactions WHERE status = 'Pending' FOR UPDATE SKIP LOCKED; -- Skip locked rows
BEGIN
-- Loop through the pending transactions
FOR txn IN c_pending_txns LOOP
-- Update the status of each transaction to 'Processing'
UPDATE transactions SET status = 'Processing' WHERE transaction_id = txn.transaction_id;
END LOOP;
COMMIT; -- Commit the changes to finalize the transaction updates
END;
Conclusion et ressources supplémentaires
Pour les postes axés sur Oracle, les employeurs recherchent des candidats capables de rédiger du code PL/SQL correct, de relever des défis concrets et d'optimiser les performances des bases de données. Je vous recommande de consulter la documentation officielle Oracle sur la référence du langage PL/SQL pour obtenir un guide détaillé et les meilleures pratiques concernant PL/SQL. Oracle Live SQL (Interactive PL/SQL Playground) permet d'accéder à la plateforme cloud d'Oracle pour exécuter des requêtes PL/SQL en ligne. Je vous encourage également à rejoindre la communauté Oracle afin d'échanger avec des experts et des développeurs Oracle, ainsi que le forum Stack Overflow pour trouver des solutions à vos questions relatives au langage PL/SQL.
Cependant, rien ne remplace un parcours d'apprentissage structuré. C'est pourquoi je recommande vivement de suivre notre cours « Introduction à Oracle SQL », qui est, à mon avis, le meilleur moyen de devenir véritablement un expert. De plus, si vous souhaitez approfondir vos connaissances en matière de bases de données, je vous recommande également de suivre notre cours sur la conception de bases de données, où vous apprendrez à créer et à gérer des bases de données et à sélectionner le SGBD le mieux adapté à vos besoins. Enfin, nous vous invitons à explorer notre cursus professionnel d'ingénieur de données associé en SQL afin d'acquérir les bases de l'ingénierie des données et du stockage de données.
Enfin, si vous interviewez des candidats et que vous souhaitez également améliorer les compétences d'autres personnes, veuillez contacter notre équipe DataCamp for Business. DataCamp peut améliorer les compétences de toute une équipe grâce à des projets pratiques et des parcours d'apprentissage personnalisés. Il s'agit d'un excellent moyen pour les employeurs de combler les lacunes en matière de compétences et de renforcer la confiance et la crédibilité d'une équipe. Nous vous invitons donc à contacter notre équipe dès aujourd'hui.
FAQ PL SQL
Qu'est-ce que le PL/SQL et en quoi diffère-t-il du SQL ?
PL/SQL est un langage procédural développé par Oracle, qui permet des structures de contrôle et la gestion des erreurs, tandis que SQL est un langage déclaratif qui gère la récupération et la manipulation des données.
Qu'est-ce qu'un package PL/SQL ?
Ensemble de procédures, fonctions, variables et curseurs associés pour la programmation modulaire et la réutilisabilité.
En quoi une procédure diffère-t-elle d'une fonction ?
Les procédures exécutent une action qui ne renvoie pas de valeur, tandis que les fonctions renvoient une valeur qui peut être utilisée dans des requêtes.
Que sont les déclencheurs en PL/SQL ?
Actions automatisées exécutées avant ou après les opérations INSERT, UPDATE, DELETE.
Qu'est-ce que le traitement en masse dans PL/SQL ?
Le traitement en masse (BULK COLLECT, FORALL) améliore les performances en réduisant les changements de contexte entre les moteurs PL/SQL et SQL lors du traitement de grands ensembles de données.
