Oracle
 sql >> Database >  >> RDS >> Oracle

Subquery ricorsivo con ordinamento

Inizialmente, non potevo vedere una soluzione più elegante che creare una tabella temporanea.

Stavo pensando, che dialetto imbarazzante di SQL Oracle è:

  1. Perché no SE LA TABELLA ESISTE ELIMINA TABELLA?
  2. Perché devo eseguire ESEGUI IMMEDIATO con una stringa? Perché non posso fare da solo DROP TABLE TEMP?
  3. Perché non posso avere ORDER BY senza annidare tra parentesi su ANCHOR?
  4. Perché non posso avere ORDER BY su SELECT ricorsivo dopo UNION ALL?
  5. SQL WITH necessita di standardizzazione. Altri dialetti del database non richiedono che i nomi delle colonne siano tra parentesi nell'istruzione WITH. Se non lo fai, ottieni un errore ALIAS senza significato, al punto del join ricorsivo dopo UNION ALL.
  6. Impaginazione:vedi qui Nessun LIMITE / 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;

Quindi (mathguy sull'Oracle Community Forum) mi ha fatto notare che il mio SEARCH DEPTH FIRST avrebbe dovuto essere appena JOBMST_NAME.

Poi tutto va a posto:

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