Рекурсивный cte sql с уровнем иерархии for

у меня есть небольшая проблема с этим рекурсивным CTE, он отлично работает, за исключением случаев, когда у меня есть пользователь без прав root readable означает отсутствие записи для этого элемента. Поэтому, если я запускаю этот запрос для пользователя с правами только на листьях внутри дерева, часть уровня этого запроса не будет работать правильно.

он покажет реальное уровень иерархия, например, 6, но его верхний первый читаемый элемент для него, поэтому он должен быть 1.

WITH Tree
AS (
SELECT
    id,
    parent,
    0 AS Level,
    id AS Root,
    CAST(id AS VARCHAR(MAX)) AS Sort,
    user_id
FROM SourceTable
WHERE parent IS NULL

UNION ALL

SELECT 
    st.id,
    st.parent,
    Level + 1 AS Level,
    st.parent AS Root,
    uh.sort + '/' + CAST(st.id AS VARCHAR(20)) AS Sort,
    st.user_id
FROM SourceTable AS st
    JOIN Tree uh ON uh.id = st.parent    
)

SELECT * FROM Tree AS t
    JOIN UserTable AS ut ON  ut.id = t.user_id AND ut.user_id = '141F-4BC6-8934'
ORDER BY Sort

уровень в следует

id  level
 5    0
 2    1
 7    2
 4    2
 1    2
 6    1
 3    2
 8    2
 9    3

когда пользователь теперь просто имеет права на чтение id 8 и 9 Уровень от CTE остается на 2 для id 8 и 3 для id 9, но мне нужно для id 8 Уровень 1, если нет никого раньше

6 ответов


вы не сказали нам, как вы знаете, имеет ли пользователь права на данный код. Это необходимая информация. Я собираюсь поместить некоторый код ниже, который предполагает, что вы добавляете столбец в свой запрос под названием hasRights и что этот столбец будет иметь нулевое значение, если у пользователя нет прав, и значение одного, если они есть. Возможно, вам придется настроить это, так как у меня нет данных для тестирования, но, надеюсь, это приблизит вас.

в основном запрос изменяется только добавьте 1 уровня, если у пользователя есть права. Он также добавляет только в путь, если пользователь имеет права, в противном случае-пустая строка добавляется. Таким образом, если ids 8 и 9 являются единственными элементами, к которым пользователь имеет доступ, вы должны увидеть уровни 1 и 2 и сортировать пути, похожие на "5/8/9", а не "5/6/8/9". Если вы все еще не можете заставить его работать, это очень поможет нам, если вы разместите образец схемы на SqlFiddle.

WITH Tree
AS (
SELECT
    id,
    parent,
    0 AS Level,
    id AS Root,
    hasRights AS HasRights,
    CAST(id AS VARCHAR(MAX)) AS Sort,
    user_id
FROM SourceTable
WHERE parent IS NULL

UNION ALL

SELECT 
    st.id,
    st.parent,
    Level + st.hasRights AS Level,
    st.parent AS Root,
    st.hasRights AS HasRights,
    uh.sort + CASE st.hasRights WHEN 0 THEN '' ELSE '/' + CAST(st.id AS VARCHAR(20)) END AS Sort,
    st.user_id
FROM SourceTable AS st
    JOIN Tree uh ON uh.id = st.parent    
)

SELECT * FROM Tree AS t
    JOIN UserTable AS ut ON  ut.id = t.user_id AND ut.user_id = '141F-4BC6-8934'
ORDER BY Sort

вы получаете что-то вроде, если более высокий уровень(0 или 1 ) не существует, то следующий уровень становится более высоким уровнем..

Если да, то вы должны сделать это, когда конечный результат

вставьте все результаты в таблицу temp, скажем, #info (с теми же характеристиками данных)

теперь после всех окончательных данных готов в таблице,

пожалуйста, проверьте сверху.

выберите * из #info, где level= 0

Если этот возвращает 0 строк, затем необходимо обновить каждый уровень записей. to (level = уровень -1)

теперь снова то же самое для уровня=0, затем уровень 1, затем Уровень 2 , затем Уровень 3 в рекурсии. это будет легко, но не легко кодировать. Поэтому попробуйте без рекурсии, а затем попробуйте final update.

надеюсь, это поможет:)

пожалуйста, ответьте, если вы ищете что-то другое.


попробуйте выполнить следующие выберите и дайте мне знать, если это ваш желаемый результат:

SELECT *,
 DENSE_RANK() OVER (PARTITION BY t.user_id ORDER BY t.LEVEL ASC) -1 as RelativeUserLevel
FROM Tree AS t
    JOIN UserTable AS ut ON  ut.id = t.user_id AND ut.user_id = '141F-4BC6-8934'
ORDER BY Sort

преобразование таблицы в иерархические типы вариант:

или

  • xml тип данных

несколько раз опция (maxrecursion 10000); очень полезно
У меня нет времени читать вашу проблему, но здесь обрезано

declare cursorSplit Cursor for
   select String from dbo.SplitN(@OpenText,'~') 
   where String not in (SELECT [tagCloudStopWordText]     
   FROM [tagCloudStopList] where [langID]=@_langID)
   option (maxrecursion 10000);
open cursorSplit

Мне жаль быть участником pooper и испортить удовольствие от создания такой интересной части SQL, но, возможно, вы должны загрузить все соответствующие данные доступа в приложение и определить уровни пользователей в приложении?

Я уверен, что это приведет к более ремонтируемому коду..