如何在sql中使用父级和子级层次结构选择标题?

时间:2016-10-19 07:13:09

标签: sql sql-server hierarchical-data recursive-query

我需要搜索标题'%p%'。如果我检查标题,父牌和状态作为父级和子级。 如果搜索到的标题父级可见为真,则显示子标题。

SELECT title
FROM table1 t1
JOIN table1 t2 ON t1.title = t2.parenttitle AND t1.visible = TRUE
JOIN table1 t3 ON t3.title = t2.parenttitle AND t3.visible = TRUE
WHERE t1.title LIKE '%p%'

表1

Title   | ParentTitle|visible   
P1        Home         TRUE 
p1.1       p1          TRUE 
p1.2       p1          FALSE    
p1.3       p1.2        TRUE 
p1.3.1     p1.3        TRUE 
p2         Home        TRUE 
p2.1       p2          TRUE 
p2.2       p2.1        FALSE    
P3         Home        TRUE 
p3.1       p3          TRUE 
P3.1.1     p3.1        FALSE    

我需要输出

title
p1
p1.1
p2
p2.1
P3
p3.1

1 个答案:

答案 0 :(得分:1)

CREATE TABLE CTE(
    Title VARCHAR(20),
    ParentTitle VARCHAR(20),
    visible VARCHAR(20),    
)   

INSERT INTO CTE
VALUES
('p1', 'Home', 'TRUE'),
('p1.1', 'p1', 'TRUE'),
('p1.2', 'p1', 'FALSE'),    
('p1.3', 'p1.2', 'TRUE'), 
('p1.3.1', 'p1.3', 'TRUE'), 
('p2', 'Home', 'TRUE'), 
('p2.1', 'p2', 'TRUE'), 
('p2.2', 'p2.1', 'FALSE'),    
('P3', 'Home', 'TRUE'), 
('p3.1', 'p3', 'TRUE'), 
('P3.1.1', 'p3.1', 'FALSE')


; WITH YTE AS
(
    SELECT *,
    ROW_NUMBER() OVER(PARTITION BY LEFT(A.Title, 2) ORDER BY A.Title) AS RN,
    DENSE_RANK() OVER(ORDER BY LEFT(A.Title, 2)) AS DR
    FROM CTE A
)
, ZTE AS
(
    SELECT *, ROW_NUMBER() OVER(PARTITION BY LEFT(A.Title, 2) ORDER BY A.Title) AS RNFalse
    FROM YTE A 
    WHERE A.visible = 'FALSE'
)
, ATE AS 
(
    SELECT A.Title
    FROM YTE A
    INNER JOIN ZTE B ON A.DR = B.DR AND A.RN < B.RN
    WHERE RNFalse = 1
) SELECT * FROM ATE

/*
Output:
p1
p1.1
p2
p2.1
P3
p3.1
*/

如果您不想使用公用表表达式,请使用子查询

SELECT A.Title FROM 
(
    SELECT *,
    ROW_NUMBER() OVER(PARTITION BY LEFT(A.Title, 2) ORDER BY A.Title) AS RN
    FROM CTE A
) AS A
INNER JOIN
(
    SELECT *,
    ROW_NUMBER() OVER(PARTITION BY LEFT(A.Title, 2) ORDER BY A.Title) AS RNFalse
    FROM 
    (
        SELECT *,
        ROW_NUMBER() OVER(PARTITION BY LEFT(A.Title, 2) ORDER BY A.Title) AS RN
        FROM CTE A
    ) A 
    WHERE A.visible = 'FALSE'
) AS B ON LEFT(A.Title, 2) = LEFT(B.Title, 2) AND A.RN < B.RN
WHERE B.RNFalse = 1

因此,如果你想删除ROW_NUMBER,那么你必须比较varchar这不好。但没有其他方式让我离开。试试这个,

SELECT A.Title FROM CTE A
INNER JOIN 
(
     SELECT LEFT(Title, 2) AS TitleGroup, Min(Title) AS Title
     FROM CTE
     WHERE visible = 'False'
     GROUP BY LEFT(Title, 2)
) B ON LEFT(A.Title, 2) = B.TitleGroup 
AND A.Title < B.Title --Comparing String like this is not good