[英]Oracle SYS_CONNECT_BY_PATH equivalent query into SQL Server
我正在尝试将涉及 Oracle SYS_CONNECT_BY_PATH 语法的复杂查询转换为 SQL Server:
SELECT
DISTINCT TO_CHAR(CONCAT(@ROOT, SYS_CONNECT_BY_PATH(CONCAT('C_',X), '.'))) AS X_ALIAS
, TO_CHAR(CONCAT(@ROOT, PRIOR SYS_CONNECT_BY_PATH(CONCAT('C_',X), '.'))) AS X_ALIAS_FATHER
, TO_CHAR(X) AS X_ALIAS_LEAF
, LEVEL AS LVL
FROM MY_TABLE
LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
LEFT JOIN OTHER_TABLE
ON OTHER_TABLE.MY_ID = COL_X
CONNECT BY (PRIOR ID_SON = ID_FATHER)
AND LEVEL <= MAXDEPTH
START WITH ID_FATHER
IN (SELECT AN_ID AS ID_FATHER FROM BIG_TABLE)
这是我使用这个网站获得的
WITH n(LEVEL, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF) AS
( SELECT 1, CONCAT('C_',X), CONCAT('C_',X), CAST(X AS VARCHAR(30))
FROM MY_TABLE
LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS
ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
LEFT JOIN OTHER_TABLE
ON OTHER_TABLE.MY_ID = COL_X
WHERE ID_FATHER IN (SELECT AN_ID AS ID_FATHER
FROM listAllCfaCfq)
UNION ALL
SELECT n.level + 1, n.X_ALIAS + '.' + nplus1.X_ALIAS, n.X_ALIAS_FATHER + '.' + nplus1.X_ALIAS_FATHER, CAST(X AS VARCHAR(30)
FROM MY_TABLE
LEFT JOIN MY_TABLE_BIS MY_TABLE_BIS_ALIAS
ON MY_TABLE_BIS_ALIAS.MY_ID = COL_X
LEFT JOIN OTHER_TABLE
ON OTHER_TABLE.MY_ID = COL_X AS nplus1, n
WHERE n.ID_SON = nplus1.ID_FATHER)
SELECT DISTINCT LEVEL, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF
WHERE LEVEL <= @MAXDEPTH;
我更改了表的名称,这样做时可能会犯错误,请不要犹豫,在评论中告诉我
所有都可以使用几个FUNCTION来解决,并且通过一些递归很简单(注意T-SQL中的最大递归级别为32)
假设我们有下表:(对一个非常小的公司)
TableName: Employees
id.....name..............manager_id
1 Big Boss NULL
2 Sales Manager 1
3 Support Manager 1
4 R&D Manager 1
5 Sales man 2
6 Support man 3
7 R&D Team leader 4
8 QA Team leader 4
9 C Developer 7
10 QA man 8
11 Java Developer 7
我们只需要一个函数来检查2个ID之间是否存在链接,还有另一个函数来提供从一个到另一个的路径。
第一个函数使用递归非常简单:
Create Function dbo.Do_WE_Have_path(@id int, @boss_id int, @max_level int) returns int
Begin
declare @res int, @man int
set @res = 0
if @id = @boss_id
set @res = 1
else if @max_level > 0
Begin
Select @man=manager_id from Employees where id=@id
set @res = Do_WE_Have_path(@man, @boss_id, @max_level-1) --recursion
End
return res
End
使用上面的函数,我们可以选择连接短于或等于指定级别的所有实体,所以现在我们可以编写一个构建路径的方法(如果存在), 请注意,应该使用上述方法过滤不存在的路径 。
Create Function dbo.Make_The_path(@id int, @boss_id int, @max_level int) returns varchar(max)
Begin
declare @res varchar(max), @man int
select @res = name from Employees where id=@id
if max_level > 0 AND @id <> @boss_id
Begin
select @man = manager_id from Employees where id = @id
set @res = dbo.Make_The_path(@man, @boss_id, max_level-1) + '/' + @res
End
return @res
End
现在我们可以使用这两个函数来获取从老板到工人的路径:
Select dbo.Make_The_path(id, 1, 3) Where Do_WE_Have_path(id, 1, 3)=1
两个函数都可以合并为一个,也许你需要为每个结构再次编写它,但重要的是它是可能的。
您可能需要对层次结构部分使用递归 CTE,然后使用 FOR XML 进行路径构建。 FOR XML 旨在将您的结果转换为 XML,但您可以使用它来将您的结果转换为各种有趣的文本格式。
CREATE TABLE #MY_TABLE
(
ID INT
,ID_FATHER INT
,COL_X INT
)
CREATE TABLE #MY_TABLE_BIS
(
MY_ID INT
,X VARCHAR(50)
)
CREATE TABLE #OTHER_TABLE
(
MY_ID INT
,[ROOT] VARCHAR(50)
)
CREATE TABLE #BIG_TABLE
(
AN_ID INT
)
go
DECLARE @MAXDEPTH INT = 10
;WITH
cte_prepare
AS
(
SELECT
ID
,ID_FATHER
,TB.X
,OT.[ROOT]
FROM #MY_TABLE T
LEFT JOIN #MY_TABLE_BIS TB
ON TB.MY_ID = COL_X
LEFT JOIN #OTHER_TABLE OT
ON OT.MY_ID = COL_X
),
cte_connect (LVL, ID, X_ALIAS, X_ALIAS_FATHER, X_ALIAS_LEAF)
AS
(
SELECT 1
,T.ID
,CAST(CONCAT(T.[ROOT], '.C_', T.X) AS VARCHAR(MAX))
,CAST(CONCAT(T.[ROOT], '.') AS VARCHAR(MAX))
,CAST(T.X AS VARCHAR(30))
FROM cte_prepare T
WHERE T.ID_FATHER IN
(
SELECT AN_ID AS ID_FATHER
FROM #BIG_TABLE
)
UNION ALL
SELECT F.LVL + 1
,S.ID
,CAST(CONCAT(F.X_ALIAS, '.C_' + S.X) AS VARCHAR(MAX))
,CAST(F.X_ALIAS AS VARCHAR(MAX))
,CAST(S.X AS VARCHAR(30))
FROM cte_prepare S
INNER JOIN cte_connect F
ON S.ID_FATHER = F.ID
WHERE F.LVL < @MAXDEPTH
)
SELECT DISTINCT
CT.X_ALIAS
,CT.X_ALIAS_FATHER
,CT.X_ALIAS_LEAF
,CT.LVL
FROM cte_connect CT
-- Uncomment this and set depth when it's greater than 100.
--OPTION (MAXRECURSION 0) -- value between 0 and 32,767 (default is 100), 0 = unlimited
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.