在递归 CTE 中删除所有包含 ID 的较短子序列
Remove all shorter subsequences containing an ID in a recursive CTE
标题好乱!让我详细说明一下。
我有两张桌子;一个表示模块(可以包含其他模块的某种类型的网页)称为 module_info
,另一个表示每个页面在模块层次结构中的位置称为 www_menu
.
module_info
:
+----------+------------+---------+
| moduleID | modulename | menu_id |
+----------+------------+---------+
| 1 | tests | 1 |
| 2 | docs | 2 |
| 3 | mail | 3 |
| 4 | networks | 4 |
| 5 | payroll | 5 |
| 6 | admin | 6 |
| 7 | travel | 7 |
| 8 | bios | 8 |
+----------+------------+---------+
www_menu
:
+--------+--------+-------------------+------------------+
| menuID | parent | title | location |
+--------+--------+-------------------+------------------+
| 1 | 0 | Tests | modules/tests |
| 2 | 0 | Testing Documents | modules/docs |
| 3 | 0 | Mailing Lists | modules/mail |
| 4 | 1 | Network Services | modules/networks |
| 5 | 1 | Payroll | modules/payroll |
| 6 | 2 | Administration | modules/admin |
| 7 | 3 | Travel | modules/travel |
| 8 | 4 | Biographies | modules/bios |
+--------+--------+-------------------+------------------+
这是我显示层次结构的查询:
WITH [root] AS
(
SELECT www.menuID
,CAST(www.title + ' (' + mi.modulename + ')' AS VARCHAR(200)) AS [path]
,CAST(mi.id AS VARCHAR(20)) AS ids
FROM [dbo].[module_info] AS mi
INNER JOIN [dbo].[WWW_Menu] www ON www.menuid = mi.menu_id
WHERE www.location LIKE 'modules/%'
UNION ALL
SELECT leaf.menuID
,CAST([root].[path] + ' > ' + leaf.title AS VARCHAR(200))
,CAST([root].ids + ',' + CONVERT(VARCHAR(4), mi.id) AS VARCHAR(20))
FROM [dbo].[WWW_Menu] AS leaf
INNER JOIN [root] ON leaf.parent = [root].menuID
INNER JOIN [dbo].[module_info] AS mi ON leaf.menuID = mi.menu_id
)
SELECT [path], ids FROM [root]
以及上面两个表中 运行 的结果:
+----------------------------------------+-------+
| path | ids |
+----------------------------------------+-------+
| Tests | 1 |
| Testing Documents | 2 |
| Mailing Lists | 3 |
| Network Services | 4 |
| Payroll | 5 |
| Administration | 6 |
| Travel | 7 |
| Biographies | 8 |
| Tests > Network Services | 1,4 |
| Tests > Payroll | 1,5 |
| Testing Documents > Administration | 2,6 |
| Mailing Lists > Travel | 3,7 |
| Network Services > Biographies | 4,8 |
| Tests > Network Services > Biographies | 1,4,8 |
+----------------------------------------+-------+
我将在 select 框中显示这些结果,以便在 selected 模块中搜索文档。事情是这样的; Biographies
、Network Services > Biographies
和 Tests > Network Services > Biographies
是同一个模块。
对于每个模块,我只想显示以该模块结尾的最长层次字符串
+----------------------------------------+-------+
| path | ids |
+----------------------------------------+-------+
| Tests | 1 |
| Testing Documents | 2 |
| Mailing Lists | 3 |
| Tests > Network Services | 1,4 |
| Tests > Payroll | 1,5 |
| Testing Documents > Administration | 2,6 |
| Mailing Lists > Travel | 3,7 |
| Tests > Network Services > Biographies | 1,4,8 |
+----------------------------------------+-------+
也许这不是一个 SQL 问题,最好通过某种迭代 server-side 来完成。但是,针对此问题的 self-contained SQL 解决方案将是我的首选。谢谢。
一种方法会涉及大量的字符串操作。相反,当您浏览列表时,请跟踪添加到列表中的最后一个模块。然后使用 row_number()
获得每个 "last" 模块的最长:
WITH [root] AS (
SELECT www.menuID,
CAST(www.title + ' (' + mi.modulename + ')' AS VARCHAR(200)) AS [path],
CAST(mi.id AS VARCHAR(20)) AS ids,
mi.id as lastId
FROM [dbo].[module_info] mi INNER JOIN
[dbo].[WWW_Menu] www
ON www.menuid = mi.menu_id
WHERE www.location LIKE 'modules/%'
UNION ALL
SELECT leaf.menuID,
CAST([root].[path] + ' > ' + leaf.title AS VARCHAR(200)),
CAST([root].ids + ',' + CONVERT(VARCHAR(4), mi.id) AS VARCHAR(20)),
mi.id
FROM [dbo].[WWW_Menu] leaf INNER JOIN
[root]
ON leaf.parent = [root].menuID INNER JOIN
[dbo].[module_info] mi
ON leaf.menuID = mi.menu_id
)
SELECT [path], ids
FROM (SELECT r.*,
ROW_NUMBER() OVER (PARTITION BY lastId ORDER BY length(path) DESC) as seqnum
FROM [root] r
) r
WHERE seqnum = 1;
标题好乱!让我详细说明一下。
我有两张桌子;一个表示模块(可以包含其他模块的某种类型的网页)称为 module_info
,另一个表示每个页面在模块层次结构中的位置称为 www_menu
.
module_info
:
+----------+------------+---------+
| moduleID | modulename | menu_id |
+----------+------------+---------+
| 1 | tests | 1 |
| 2 | docs | 2 |
| 3 | mail | 3 |
| 4 | networks | 4 |
| 5 | payroll | 5 |
| 6 | admin | 6 |
| 7 | travel | 7 |
| 8 | bios | 8 |
+----------+------------+---------+
www_menu
:
+--------+--------+-------------------+------------------+
| menuID | parent | title | location |
+--------+--------+-------------------+------------------+
| 1 | 0 | Tests | modules/tests |
| 2 | 0 | Testing Documents | modules/docs |
| 3 | 0 | Mailing Lists | modules/mail |
| 4 | 1 | Network Services | modules/networks |
| 5 | 1 | Payroll | modules/payroll |
| 6 | 2 | Administration | modules/admin |
| 7 | 3 | Travel | modules/travel |
| 8 | 4 | Biographies | modules/bios |
+--------+--------+-------------------+------------------+
这是我显示层次结构的查询:
WITH [root] AS
(
SELECT www.menuID
,CAST(www.title + ' (' + mi.modulename + ')' AS VARCHAR(200)) AS [path]
,CAST(mi.id AS VARCHAR(20)) AS ids
FROM [dbo].[module_info] AS mi
INNER JOIN [dbo].[WWW_Menu] www ON www.menuid = mi.menu_id
WHERE www.location LIKE 'modules/%'
UNION ALL
SELECT leaf.menuID
,CAST([root].[path] + ' > ' + leaf.title AS VARCHAR(200))
,CAST([root].ids + ',' + CONVERT(VARCHAR(4), mi.id) AS VARCHAR(20))
FROM [dbo].[WWW_Menu] AS leaf
INNER JOIN [root] ON leaf.parent = [root].menuID
INNER JOIN [dbo].[module_info] AS mi ON leaf.menuID = mi.menu_id
)
SELECT [path], ids FROM [root]
以及上面两个表中 运行 的结果:
+----------------------------------------+-------+
| path | ids |
+----------------------------------------+-------+
| Tests | 1 |
| Testing Documents | 2 |
| Mailing Lists | 3 |
| Network Services | 4 |
| Payroll | 5 |
| Administration | 6 |
| Travel | 7 |
| Biographies | 8 |
| Tests > Network Services | 1,4 |
| Tests > Payroll | 1,5 |
| Testing Documents > Administration | 2,6 |
| Mailing Lists > Travel | 3,7 |
| Network Services > Biographies | 4,8 |
| Tests > Network Services > Biographies | 1,4,8 |
+----------------------------------------+-------+
我将在 select 框中显示这些结果,以便在 selected 模块中搜索文档。事情是这样的; Biographies
、Network Services > Biographies
和 Tests > Network Services > Biographies
是同一个模块。
对于每个模块,我只想显示以该模块结尾的最长层次字符串
+----------------------------------------+-------+
| path | ids |
+----------------------------------------+-------+
| Tests | 1 |
| Testing Documents | 2 |
| Mailing Lists | 3 |
| Tests > Network Services | 1,4 |
| Tests > Payroll | 1,5 |
| Testing Documents > Administration | 2,6 |
| Mailing Lists > Travel | 3,7 |
| Tests > Network Services > Biographies | 1,4,8 |
+----------------------------------------+-------+
也许这不是一个 SQL 问题,最好通过某种迭代 server-side 来完成。但是,针对此问题的 self-contained SQL 解决方案将是我的首选。谢谢。
一种方法会涉及大量的字符串操作。相反,当您浏览列表时,请跟踪添加到列表中的最后一个模块。然后使用 row_number()
获得每个 "last" 模块的最长:
WITH [root] AS (
SELECT www.menuID,
CAST(www.title + ' (' + mi.modulename + ')' AS VARCHAR(200)) AS [path],
CAST(mi.id AS VARCHAR(20)) AS ids,
mi.id as lastId
FROM [dbo].[module_info] mi INNER JOIN
[dbo].[WWW_Menu] www
ON www.menuid = mi.menu_id
WHERE www.location LIKE 'modules/%'
UNION ALL
SELECT leaf.menuID,
CAST([root].[path] + ' > ' + leaf.title AS VARCHAR(200)),
CAST([root].ids + ',' + CONVERT(VARCHAR(4), mi.id) AS VARCHAR(20)),
mi.id
FROM [dbo].[WWW_Menu] leaf INNER JOIN
[root]
ON leaf.parent = [root].menuID INNER JOIN
[dbo].[module_info] mi
ON leaf.menuID = mi.menu_id
)
SELECT [path], ids
FROM (SELECT r.*,
ROW_NUMBER() OVER (PARTITION BY lastId ORDER BY length(path) DESC) as seqnum
FROM [root] r
) r
WHERE seqnum = 1;