【问题标题】:Recursive cte sql with for hierarchy level具有层次结构级别的递归cte sql
【发布时间】:2013-11-07 14:57:57
【问题描述】:

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

它将显示真正的 level 层次结构,例如 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 和 3 对于 id 9 保持在 2,但如果之前没有人,我需要 id 8 级别 1

【问题讨论】:

  • 你能展示一些数据和预期的结果吗?
  • 当前用户刚刚阅读时的级别如下 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 和 3 对于 id 9 保持在 2,但如果之前没有人,我需要 id 8 级别 1
  • 感谢后面的相应更新
  • 能否请您添加SourceTable 的数据?否则很难理解你有什么作为递归 CTE 的来源。
  • 如果没有 parentID 的值,就很难创建任何有效的脚本...如果您要添加这些值,则可以找到解决方案

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


【解决方案1】:

如果更高级别(0 或 1 )不存在,则您需要类似的东西,那么下一个级别将成为更高级别..

如果是,那么你必须在最终结果时这样做

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

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

请从顶部检查。

从 #info where level= 0 中选择 *

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

现在 Level=0 再次相同,然后是 1 级,然后是 2 级,然后是 3 级递归。这将很容易但不容易编码。所以尝试不使用递归,然后尝试最终更新。

我希望这会有所帮助:)

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

【讨论】:

    【解决方案2】:

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

    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】:

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

      基本上,如果用户有权限,查询会更改为仅将级别加 1。如果用户有权限,它也只会添加到排序路径,否则会附加一个空字符串。因此,如果 id 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
      

      【讨论】:

        【解决方案4】:

        将您的表转换为分层类型是否是一种选择:

        • xml 数据类型

        【讨论】:

          【解决方案5】:

          SOME TIMES 选项(最大递归 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
          

          【讨论】:

            【解决方案6】:

            很抱歉,我很抱歉成为一个派对大佬,破坏了创建如此有趣的 SQL 片段的乐趣,但也许您应该将所有相关的访问数据加载到您的应用程序中并确定应用程序中的用户级别?

            我敢打赌,这会产生更易于维护的代码..

            【讨论】:

              猜你喜欢
              • 2019-07-02
              • 1970-01-01
              • 1970-01-01
              • 2023-03-24
              • 1970-01-01
              • 2017-02-04
              • 2018-03-30
              • 1970-01-01
              • 2021-10-03
              相关资源
              最近更新 更多