Проблема с запросом дерева Oracle + SQL Server - PullRequest
0 голосов
/ 07 декабря 2011

У меня небольшая проблема с тем, что SQL Server возвращает те же результаты, что и Oracle для нашего запроса дерева SQL.

У нас есть таблица ссылок с атрибутами

CHILD_ID, LINK_ID, PARENT_ID

и таблица элементов с ELEMENT_ID

В Oracle мы используем это

SELECT * FROM LINKS
JOIN ELEMENTS ON ELEMENT_ID = CHILD_ID
WHERE LINK_ID IN 
(SELECT LINK_ID FROM LINKS CONNECT BY PRIOR CHILD_ID = PARENT_ID START WITH PARENT_ID = 'startid')

В SQL Server мы используем это

WITH TREE_LINKS AS
(SELECT CHILD_ID, LINK_ID FROM LINKS WHERE PARENT_ID = 'startid'
UNION ALL
SELECT CURRENT_LINKS.CHILD_ID, CURRENT_LINKS.LINK_ID
FROM LINKS CURRENT_LINKS
INNER JOIN TREE_LINKS t1 ON CURRENT_LINKS.PARENT_ID = t1.CHILD_ID)

SELECT * FROM TREE_LINKS
INNER JOIN LINKS ON TREE_LINKS.LINK_ID = LINKS.LINK_ID 
INNER JOIN ELEMENTS ON ELEMENTS.ELEMENT_ID = TREE_LINKS.CHILD_ID

Это прекрасно работает, кроме 1 выпуска.

В Oracle мы получаем только каждую уникальную ссылку, основанную на LINK_ID. В SQL Server мы получаем все ссылки, описывающие полное дерево, которое может включать дубликаты, когда 1 элемент существует ниже множества других элементов в разных ветвях структуры.

Это означает, что мы получаем большое количество дублирующихся строк из SQL Server. Я тестировал добавление

SELECT DISTINCT TREE_LINKS.LINK_ID AS TREE_LINK_ID, * from TREE_LINKS 

в последнем операторе выбора, но это займет столько времени, сколько у сервера есть больше работы по удалению дубликатов, если они найдены в разных ветвях.

В 1 тестовом примере на данный момент Oracle возвращает 20 000 строк, а SQL Server возвращает 1,6 миллиона строк. До сих пор я не нашел способа заставить SQL Server возвращать те же результаты, что и быстро.

К вашему сведению: добавление DISTINCT в причины рекурсии

Оператор DISTINCT недопустим в рекурсивной части рекурсивного общее табличное выражение 'TREE_LINKS'.

Редактировать: - Пример

Если у нас есть такие ссылки

PARENT_ID, LINK_ID, CHILD_ID
1          1        2
2          2        3 
3          3        4
1          4        3

Есть 4 уникальных элемента, но в полном дереве 6 элементов. Это потому, что есть 2 пути к элементу 3

1 Ответ

1 голос
/ 07 декабря 2011
SELECT LINK_ID
  FROM LINKS
  START WITH PARENT_ID = 'startid'
  CONNECT BY PRIOR CHILD_ID = PARENT_ID

должно быть эквивалентно

РЕДАКТИРОВАТЬ НИЖЕ (И при первом редактировании): изменил PARENT_ID на LINK_ID при втором выборе

WITH TREE_LINKS(CHILD_ID, LINK_ID) AS 
   (SELECT CHILD_ID, LINK_ID
    FROM LINKS
    WHERE PARENT_ID = 'startid'
        UNION ALL
    SELECT NLINKS.CHILD_ID, NLINKS.LINK_ID
    FROM LINKS as NLINKS, TREE_LINKS
    WHERE TREE_LINKS.CHILD_ID = NLINKS.PARENT_ID)

SELECT LINK_ID FROM TREE_LINKS

согласно МоделированиеПОДКЛЮЧИТЕ ПРИОРОМ ORACLE в СЕРВЕРЕ SQL

Остальное должно быть похоже на то, что я могу сказать.

РЕДАКТИРОВАТЬ: возможно что-то вроде:

WITH TREE_LINKS(CHILD_ID, LINK_ID) AS 
   (SELECT CHILD_ID, LINK_ID
    FROM LINKS
    WHERE PARENT_ID = 'startid'
        UNION ALL
    SELECT NLINKS.CHILD_ID, NLINKS.LINK_ID
    FROM LINKS as NLINKS, TREE_LINKS
    WHERE TREE_LINKS.CHILD_ID = NLINKS.PARENT_ID)

SELECT * FROM LINKS as TLINKS
JOIN ELEMENTS ON ELEMENT_ID = TLINKS.CHILD_ID
WHERE TLINKS.LINK_ID IN
(SELECT TREE_LINKS.LINK_ID FROM TREE_LINKS)

, ноУ меня нет mssql или oracle для тестирования на данный момент

EDIT: удалено "AND TREE_LINKS.LINK_ID <> NLINKS.LINK_ID" из запроса, поскольку оно не было необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...