Найти повторяющиеся / повторяющиеся строки в иерархическом SQL - PullRequest
5 голосов
/ 15 июля 2009

Я пытаюсь обнаружить дублированные / повторяющиеся значения в иерархической таблице.

Рассмотрим следующий (слегка надуманный) пример:

SELECT *
FROM   emp
START WITH mgr IN (SELECT empno FROM emp WHERE ename = 'JONES'
                   UNION ALL
                   SELECT empno FROM emp WHERE ename = 'JONES')
CONNECT BY PRIOR empno = mgr;

Returns ...

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20

То, что я на самом деле хочу, это ...

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20

т.е. я хочу, чтобы каждая строка возвращалась столько раз, сколько существует в подзапросе (игнорируя порядок). Поскольку в START WITH используется предложение IN, повторяющиеся значения подавляются. Можно ли реорганизовать SQL, чтобы я мог это сделать?

Обратите внимание, что в моем случае этот подпункт не является UNION, а представляет собой SELECT, который может возвращать несколько (возможно, повторяющихся) значений из таблицы.

Я мог бы сделать это в PL / SQL, записав значения во временную таблицу и затем GROUPing + COUNTing, но я бы предпочел сделать это в SQL, только если это возможно.

Дайте мне знать, если требуется какое-либо разъяснение.

Спасибо: -)

EDIT:

Обратите внимание, что из подзапроса может быть 0 ... N значений.

Ответы [ 4 ]

3 голосов
/ 16 июля 2009

Попробуйте это ..

SELECT  EMPNO,ENAME FROM,count(*)as counts   emp group by EMPNO,ENAME having count(*)>1
0 голосов
/ 16 июля 2009

Похоже, вам нужно сначала выполнить внешнее объединение из emp к результату вашего сложного запроса выбора, а затем основывать на этом запрос на соединение.

Примерно так, может быть:

WITH mgrs AS (
   SELECT empno FROM emp WHERE ename = 'JONES'
   UNION ALL
   SELECT empno FROM emp WHERE ename = 'JONES'
),
all_emps AS (
   SELECT emp.*, 
          CASE WHEN mgrs.empno IS NOT NULL THEN 1 END AS start_with  
   FROM emp
   LEFT OUTER JOIN mgrs ON mgrs.empno = emp.mgr
)
SELECT *
FROM all_emps
START WITH start_with = 1
CONNECT BY PRIOR empno = mgr;
0 голосов
/ 16 июля 2009

Одним из способов дублирования набора результатов является перекрестное соединение (декартово произведение) его с двумя строками, то есть:

SQL> WITH your_query AS (
  2     SELECT object_name
  3       FROM all_objects WHERE ROWNUM <= 3
  4  )
  5  SELECT your_query.*
  6    FROM your_query
  7   CROSS JOIN (SELECT NULL FROM dual UNION ALL SELECT NULL FROM dual);

OBJECT_NAME
------------------------------
IND$
IND$
ICOL$
ICOL$
OBJ$
OBJ$

В вашем случае это должно работать:

WITH your_query AS (
   SELECT *
     FROM emp
    START WITH mgr IN (SELECT empno FROM emp WHERE ename = 'JONES')
          CONNECT BY PRIOR empno = mgr
)
SELECT your_query.*
  FROM your_query
 CROSS JOIN (SELECT NULL FROM dual UNION ALL SELECT NULL FROM dual);
0 голосов
/ 15 июля 2009

это довольно просто:

ВЫБРАТЬ * ИЗ empSTART С мгр в (ВЫБЕРИТЕ empno ИЗ emp ГДЕ ename = СОЮЗ ДЖОНСА ВСЕ
ВЫБЕРИТЕ empno ИЗ emp ГДЕ ename = «JONES») ПОДСОЕДИНЯЙТЕСЬ ПО ПРИОРЕ

...