【问题标题】:Selecting Departments in a Department-Tree-Structure from a Root-Department excluding special Sub-Departments-Tree (see Text)从根部门中选择部门树结构中的部门,不包括特殊的子部门树(见正文)
【发布时间】:2016-02-09 04:06:34
【问题描述】:

问题: 我真的很难从一个以树形结构(父子结构)排列的部门表中选择一组特殊的部门。

您可以使用以下设置进行游戏: http://sqlfiddle.com/#!3/18a28/3

详情: 父子关系由名为 FullPath 的字符串属性建模。 FullPath-String 是由反斜杠分隔的数字顺序。例如:“1”是没有父系的部门。 '1\2' 是以部门 '1' 作为父部门的部门。 '1\3\5\6' 是一个以 '1\3\5' 作为父部门的部门,它本身具有 '1\3' 作为父部门,依此类推。每个部门记录都有一个名为 hasFKToOrg 的布尔属性,设置为 1 或 0。

这是设置: 创建表部门 ([FullPath] varchar(128), [hasFKToOrg] int) ;

INSERT INTO Department
    ([FullPath], [hasFKToOrg])
VALUES
    ('1', 1),
    ('1\2', 0),
    ('1\3', 1),
    ('1\3\6',0),
    ('1\3\4', 1),
    ('1\3\4\6', 0),
    ('1\3\5', 1),
    ('1\3\5\6', 0)
;

我需要什么: 一个选择语句,它提供一个专用父部门的所有子部门,包括父部门本身(根据定义,它总是用 hasFKToOrg = 1 标记)。必须从结果集中排除该父部门下也标记有 hasFKToOrg = 1 的所有子树分支。

例如:

  1. '1' 是父部门。 select 语句必须将“1”和“1/2”作为部门传递。
  2. '1\3' 是父部门。 select 语句必须将 '1\3' 和 '1\3\6' 作为部门传递。
  3. '1\3\4' 是父部门。 select 语句必须将 '1\3\4' 和 '1\3\4\6' 作为部门传递。
  4. '1\3\5' 是父部门。 select 语句必须将 '1\3\5' 和 '1\3\5\6' 作为部门传递。

到目前为止我的解决方案: 我尝试了部门之间的内部连接。由于多种原因,内部连接方法不起作用。我能做些什么呢?

DECLARE @root_path varchar(20) = '1\3'; 
GO
select d.FullPath, de.FullPath
from Department d
join Department de on (d.FullPath not like de.FullPath+'%')
where
d.FullPath like @root_path+'%'
and
(
  de.hasFKToOrg = 1
  and
  de.FullPath <> @root_path
  and
  not (d.hasFKToOrg = 1 and de.hasFKToOrg = 1 and d.FullPath <> @root_path and de.FullPath <> @root_path)
)

这提供了 '1\3' 和 '1\3\4\6' 和 '1\3\5\6' 这是错误的,因为 '1\3' 和 '1\3\6' 是正确的部门。有什么建议我可以做些什么来获得正确的结果集?

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    因为您将孩子定义为低一级,所以您不能使用'%'。您需要单个野生字符。 有一个限制,它不会自动支持 /12/ 更改 where 子句

    d.FullPath like @root_path+'%'
    

    d.FullPath like @root_path+'\_'
    

    或者你可以试试这个

    d.FullPath like @root_path+'%' AND  d.FullPath not like @root_path+'%\%'
    

    所以不接受低于一级以上的部门。

    【讨论】:

      【解决方案2】:

      你应该停止重新设计轮子并使用hiearchyId

      CREATE TABLE #Department
          ([FullPath] hierarchyID NOT NULL PRIMARY KEY, [hasFKToOrg] int);
      
      INSERT INTO #Department ([FullPath], [hasFKToOrg])
      VALUES ('/1/', 1), ('/1/2/', 0), ('/1/3/', 1),  ('/1/3/6/',0),
             ('/1/3/4/', 1), ('/1/3/4/6/', 0), ('/1/3/5/', 1), ('/1/3/5/6/', 0);
      
      DECLARE @node hierarchyId = '/1/';
      
      SELECT CAST(FullPath AS nvarchar(100)), hasFKToOrg 
      FROM #Department
      WHERE FullPath.IsDescendantOf(@node) = 1
        AND FullPath.GetLevel() - 1 = @node.GetLevel()
        AND hasFKToOrg = 0
      UNION ALL 
      SELECT CAST(FullPath AS nvarchar(100)), hasFKToOrg 
      FROM #Department
      WHERE FullPath = @node
      

      LiveDemo

      IsDescendantOf

      如果这是 parent 的后代,则返回 true。

      【讨论】:

        【解决方案3】:

        简单的 Where 子句

        我用你所有可能的场景测试了我的脚本,我的结果符合你的预期。最好的部分是我在一个简单的 where 子句中完成了这一切。没有什么花哨。 性能方面,它应该是不错的,具体取决于您的桌子大小。可能比使用带有一堆 '%' 通配符的 where 子句更好。

        DECLARE @root_path VARCHAR(1000) = '1';
        DECLARE @RootSlashCount INT = (LEN(@root_path) - LEN(REPLACE(@root_path,'\',''))); --number of slashes in @root_path
        
        SELECT *
        FROM department
        WHERE       (hasFKToOrg = 1 AND FullPath = @root_path) --Exact match when hasFKToOrg = 1
                    OR
                    (       hasFKToOrg = 0 --Only when it's 0
                        AND LEFT(FullPath,LEN(@root_path)) = @root_path --Match root path to all FullPaths that match 
                        AND (LEN(FullPath) - LEN(REPLACE(FullPath,'\',''))) = @RootSlashCount + 1 --only return direct descendants by using the number of slashes
                    )
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-03-20
          • 2021-07-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-20
          相关资源
          最近更新 更多