具有层次结构级别的递归cte sql

时间:2013-10-28 17:43:34

标签: sql sql-server-2008 common-table-expression

我对这个递归CTE有一点问题,它工作正常,除非我有一个没有root可读权限的用户意味着没有这个元素的条目。因此,如果我对具有树内叶子权限的用户运行此查询,则此查询的级别部分将无法正常工作。

它将显示示例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的级别对于id 8保持为2,对于id 9保持3,但如果之前没有,则需要id 8级别1

6 个答案:

答案 0 :(得分:2)

您还没有告诉我们您是如何知道用户是否拥有给定ID的权利。这是必要的信息。我将在下面添加一些代码,假设您在查询中添加一个名为 hasRights 的列,并且如果用户没有权限,则此列将具有零值,如果用户没有权限,则该值将为1做。您可能需要对此进行调整,因为我没有要测试的数据,但希望它会让您接近。

基本上,如果用户拥有权限,则查询将更改为仅向级别添加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

答案 1 :(得分:0)

如果不存在更高级别(0或1),则需要更高级别,然后下一级别变为更高级别。

如果是,那么在最终结果

时你必须这样做

将所有结果插入临时表,让我们说#info(具有相同的数据特​​征)

现在,在表格中准备好所有最终数据之后,

请从顶部查看。

从#info中选择*,其中level = 0

如果返回0行,则必须更新每个记录级别。到(等级=等级-1)

现在再次对Level = 0,然后是level 1,然后是level 2,然后是递归中的level 3。这将很容易,但不容易编码。所以尝试不递归然后尝试最终更新。

我希望这会有所帮助:)

如果您正在寻找其他内容,请回复。

答案 2 :(得分:0)

尝试执行以下选择,并告诉我是否是您想要的结果:

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

答案 3 :(得分:0)

将表格转换为分层类型是一种选择:

  • xml 数据类型

答案 4 :(得分:0)

SOME TIMES选项(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

答案 5 :(得分:0)

我很遗憾成为派对的人并且破坏了创建这样一个有趣的SQL的乐趣,但也许您应该将所有相关的访问数据加载到您的应用程序中并确定应用程序中的用户级别?

我敢打赌它会产生更易维护的代码..