Oracle
 sql >> Base de données >  >> RDS >> Oracle

Sous-requête récursive avec tri

Au départ, je ne voyais pas de solution plus élégante que de créer une table temporaire.

Je pensais, quel dialecte maladroit de SQL Oracle est :

  1. Pourquoi pas IF TABLE EXISTS DELETE TABLE ?
  2. Pourquoi dois-je exécuter EXECUTE IMMEDIATE avec une chaîne ? Pourquoi ne puis-je pas faire DROP TABLE TEMP tout seul ?
  3. Pourquoi ne puis-je pas avoir ORDER BY sans imbriquer entre parenthèses sur ANCHOR ?
  4. Pourquoi ne puis-je pas avoir ORDER BY sur SELECT récursif après UNION ALL ?
  5. SQL WITH doit être standardisé. Les autres dialectes de base de données ne nécessitent pas que les noms de colonne soient entre parenthèses dans l'instruction WITH. Si vous ne le faites pas, vous obtenez une erreur ALIAS sans signification, au point de la jointure récursive après UNION ALL.
  6. Pagination :Voir ici No LIMIT / OFFSET
DECLARE
 v_c NUMBER;
BEGIN
SELECT COUNT(*) INTO v_c FROM user_tables WHERE TABLE_NAME = 'TEMP';
IF v_c = 1 THEN
  EXECUTE IMMEDIATE 'DROP TABLE TEMP';
END IF;
END;
CREATE TABLE TEMP AS  (
    SELECT * FROM (
      SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE
      FROM TIDAL.JOBMST
      WHERE JOBMST_PRNTID IS NOT NULL
      ORDER BY JOBMST_PRNTID, JOBMST_NAME
    )
);
WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
  SELECT * FROM (
    SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
    FROM TIDAL.JOBMST
    WHERE JOBMST_PRNTID IS NULL
    ORDER BY JOBMST_NAME
  )
UNION ALL
SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL + 1
FROM TEMP J2
INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
WHERE J2.JOBMST_PRNTID IS NOT NULL
)
SEARCH DEPTH FIRST BY JOBMST_ID SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ;

Ensuite (mathguy sur le forum de la communauté Oracle) m'a fait remarquer que ma PROFONDEUR DE RECHERCHE EN PREMIER aurait dû être par JOBMST_NAME.

Ensuite, tout se met en place :

WITH J1(JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, LVL) AS  (
    SELECT JOBMST_ID, JOBMST_NAME, JOBMST_PRNTID, JOBMST_TYPE, 1
    FROM TIDAL.JOBMST
    WHERE JOBMST_PRNTID IS NULL
UNION ALL
SELECT J2.JOBMST_ID, J2.JOBMST_NAME, J2.JOBMST_PRNTID, J2.JOBMST_TYPE, J1.LVL + 1
FROM TIDAL.JOBMST J2
INNER JOIN J1 ON J2.JOBMST_PRNTID = J1.JOBMST_ID
WHERE J2.JOBMST_PRNTID IS NOT NULL
)
SEARCH DEPTH FIRST BY JOBMST_NAME SET DISP_SEQ
SELECT *
FROM J1
ORDER BY DISP_SEQ