问题: 我真的很难从部门表中选择一组特殊的部门,这些部门以树形结构排列(父子结构)。
您可以使用以下设置进行播放: http://sqlfiddle.com/#!3/18a28/3
详细说明: 父子关系由名为FullPath的字符串属性建模。 FullPath-String是由反斜杠分隔的数字顺序。例如:' 1'是一个没有父母的部门。 ' 1 \ 2'是一个部门,有部门' 1'作为父母。 ' 1 \ 3 \ 5 \ 6'是一个有' 1 \ 3 \ 5'作为父母部门,它本身有' 1 \ 3'作为父母等。每个department-record都有一个名为hasFKToOrg的布尔属性,该属性设置为1或0。
这是设置: CREATE TABLE部门 ([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)
;
我需要什么: 一个select语句,它传递一个专用父系的所有子系,包括父系本身(根据定义,它总是标记为hasFKToOrg = 1)。必须从结果集中排除该父级部门下也标记为hasFKToOrg = 1的所有子树分支。
例如:
到目前为止我的解决方案: 我尝试了部门之间的内部联接。内连接方法由于多种原因不起作用。我该怎么做呢?
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)
)
这提供了&#39; 1 \ 3&#39;和&#39; 1 \ 3 \ 4 \ 6&#39;和&#39; 1 \ 3 \ 5 \ 6&#39;这是假的,因为&#39; 1 \ 3&#39;和&#39; 1 \ 3 \ 6&#39;是正确的部门。有什么建议我可以做什么而不是得到正确的结果集?
答案 0 :(得分:0)
因为您将孩子定义为下一级,所以您不能使用'%'。你需要单一的野性角色。 有一个限制,这将不会自动支持/ 12 / 更改where子句
d.FullPath like @root_path+'%'
到
d.FullPath like @root_path+'\_'
或者你可以试试这个
d.FullPath like @root_path+'%' AND d.FullPath not like @root_path+'%\%'
所以不要接受超过一级的部门。
答案 1 :(得分:0)
您应该停止重新启动滚轮并使用 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
强>
如果这是父级的后代,则返回true。
答案 2 :(得分:0)
我使用所有可能的方案测试了我的脚本,我的结果符合您的预期。最好的部分是我在一个简单的where子句中完成所有操作。没有什么花哨。 性能方面,它应该是体面的,取决于您的表大小。可能比使用带有一堆&#39;%&#39;的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
)