2016-12-20 19 views
0

我与雇员数据库的工作基于价值TSQL查找记录,其中的一个字段是显示他们所报告的管理员ID的层次,他们的指导报告等在字符串

的结构本专栏如下:

123|456|789|135|246|790 

员工经理将790,他们的经理246等,一直在链上。

我想找到一种方法来搜索X Manager在雇员层次结构中的记录。

例如:SELECT FROM employees WHERE '135' IN HierachyColumn

我无法使用XML由于这之中链接的服务器不允许在分布式查询XML上。我这样说是因为我会用XML包装每个值,然后使用.exist来检查它的存在。

它自己包含此字符串的数据在VIEW之内,所以我可以根据建议对其进行一点处理,但是我在一个好方法上留下了空白。

是否有任何其他选项用于基于此字符串进行搜索?

回答

0

这应该做的伎俩:

-- sample data 
DECLARE @employees TABLE(HierarchyColumn varchar(100)) 
INSERT @employees 
VALUES ('123|456|789|135|246|790'), ('144|451|689|822'), ('144|451|689|822|990|999'); 

-- your search string 
DECLARE @searchString int = 451; 

-- solution 
SELECT * 
FROM @employees 
WHERE HierarchyColumn LIKE CONCAT('%|',@searchstring,'|%') 
OR HierarchyColumn LIKE CONCAT(@searchstring,'|%') 
OR HierarchyColumn LIKE CONCAT('%|',@searchstring); 

结果:

HierarchyColumn 
--------------------------- 
144|451|689|822 
144|451|689|822|990|999 

或者,您也可以做到这一点,将得到相同的结果:

-- sample data 
DECLARE @employees TABLE(HierarchyColumn varchar(100)) 
INSERT @employees 
VALUES ('123|456|789|135|246|790'), ('144|451|689|822'), ('144|451|689|822|990|999'); 

-- your search string 
DECLARE @searchString int = 451; 

-- solution 
SELECT HierarchyColumn 
FROM @employees 
CROSS JOIN 
(
    VALUES (CONCAT('%|',@searchstring,'|%')), 
     (CONCAT(@searchstring,'|%')), 
     (CONCAT('%|',@searchstring)) 
) p(pattern) 
WHERE HierarchyColumn LIKE pattern; 
+0

任何奇特的方式将它变成一个单一的LIKE语句,将捕获所有3种情况?我知道它很多要问,只是好奇 – SBB

+0

''|' + HierarchyColumn +'|'如'%|' + @searchstring +'|%''。它不是[SARGABLE](https://en.wikipedia.org/wiki/Sargable),所以它不能从索引中受益。 – HABO

+0

@HABO - 这是正确的。您不会在优化器选择的列上进行索引查找。如果你有一个SARGable的基于集合的解决方案,我很乐意看到它。;) –

0

另一种方法,提供所有层次结点的长度都是相同的,就像我这样修改我的解决方案到this post

-- sample data 
DECLARE @employees TABLE(HierarchyColumn varchar(100)) 
INSERT @employees 
VALUES ('123|456|789|135|246|790'), ('144|451|689|822'), ('144|451|689|822|990|999'); 

-- your search string 
DECLARE @searchString int = 451; 

SELECT * 
FROM 
(
    SELECT 
    HierarchyColumn, 
    itemLevel = ROW_NUMBER() OVER (PARTITION BY e.HierarchyColumn ORDER BY N), 
    item  = SUBSTRING(e.HierarchyColumn, ((N*4)-3), 3) 
    FROM @employees e 
    CROSS APPLY 
    (
    SELECT TOP ((LEN(e.HierarchyColumn)/4)+1) ROW_NUMBER() OVER (ORDER BY (SELECT 1)) 
    FROM 
    (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) a(x), 
    (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) b(x), 
    (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) c(x), 
    (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) d(x) 
) iTally(N) 
) x 
WHERE item = @searchString; 

这不仅会返回节点,还会返回节点在层次结构中的位置级别。

HierarchyColumn   itemLevel item 
------------------------- --------- ---- 
144|451|689|822   2   451 
144|451|689|822|990|999 2   451 
2

假设(在一天结束时)您的查询,将是非sargable。

在这样的情况下,我倾向于选择CharIndex()实际上可能会给你的性能提升http://cc.davelozinski.com/sql/like-vs-substring-vs-leftright-vs-charindex

Declare @Find varchar(25)='|451|' -- Note I pre-piped the Find 

Select * 
From employees 
Where CharIndex(@Find,'|'+HierarchyColumn+'|')>0 

披露:前一段时间,我跑了一系列的测试。我的结果并不像文章中列出的那么戏剧化,但却是值得注意的。