我有一个具有以下结构的表。表名:表0
结构如下
Select process from Table0 where Name like '%Aswini%'
Process
-------
112
778
756
所有这些过程必须进入下表表名:表1
结构如下
Select Exec, stepid, condition
from Table1
where Exec = 112
Exec stepid condition
-----------------------
112 2233 0
112 2354 0
445 3455 0
第二个表'表2'结构如下:
Select stepid, processid
from Table2
where stepid = 2233
Stepid processid
-----------------
2233 445
2354 566
3455 556
表1 stepid
输入表2 stepid
,表2 Processid
输入表1 Exec
。我必须以递归方式获取processID
,直到条件为0,否则表不返回任何行,最后的processid是父ID。
我没有参加过CTE。所以我使用了一个简单的连接来获得以下结果。
select b.processid
from Table1 a
inner join Table2 b on a.stepid = b.stepid
where a.condition = 0
and a.exec = 112(parent from table0)
如果满足条件,上面的查询将给出Exec 112的父代。
我必须再次输入查询的父项并执行它。
我可以在C#的帮助下实现这一点,将其置于循环中。但我只想在SQL Server中使用它。这可以实现吗?
编辑
当我执行CTE时,我得到以下结果
Process Parent
112 445
112 566
112 445
112 566
如果初始进程有2个exec,则最终进程父结构重复两次(exec数)。为什么会这样呢?它只需要显示一次结果。
没有光标的解决方案(我个人更喜欢):
WITH [CTE] AS
(
SELECT
T1.[Exec] AS [process],
1 AS [n],
T1.[Exec],
T1.[Exec] AS [parent]
FROM
[Table1] AS T1
UNION ALL
SELECT
C.[process],
C.[n] + 1,
T1.[Exec],
T2.[processid]
FROM
[CTE] AS C
INNER JOIN [Table1] AS T1 ON T1.[Exec] = C.[parent]
INNER JOIN [Table2] AS T2 ON T2.[stepid] = T1.[stepid]
)
SELECT C.[process], C.[parent]
FROM [CTE] AS C
WHERE C.[n] = (SELECT MAX([n]) FROM [CTE] WHERE [process] = C.[process])
说明:
公用表表达式的锚点部分(SELECT
之前的UNION ALL
查询)定义了操作的起始点。在这种情况下,它只是从Table1
中选择所有数据,它有四个字段:
process
将包含应确定父母的过程的价值(Exec
值)。n
将包含一个序列号,从1开始。Exec
将包含一个“移位”值,用于在公用表表达式的下一个“递归”部分中连接记录。parent
将包含来自processid
的相应Table2
字段,该字段代表Exec
值的直接父级。此锚表达式将生成以下数据:
process n Exec parent
112 1 112 112
445 1 445 445
公共表表达式的递归部分(SELECT
之后的UNION ALL
查询)不断从Table1
(其Exec
值等于先前CTE记录的parent
值)和Table2
(与Table1
字段上的stepid
相关)向CTE添加记录。 CTE中新添加的记录将具有以下字段值:
process
将从之前的CTE记录中复制。n
将增加1。Exec
将得到加入的Exec
的Table1
值的Exec
值(等于之前的CTE记录的parent
值)。parent
将 - 再次 - 从processid
获得相应的Table2
值,其中stepid
值等于Table1
的stepid
值。整个CTE将产生以下结果:
process n Exec parent
112 1 112 112
112 2 112 445
112 3 445 556
445 1 445 445
445 2 445 556
主要查询(在CTE下方)将仅为CTE中的每个“最后”记录选择process
和parent
字段(其中n
的值是特定process
值的最大值,其使用子查询确定)。
这会产生以下最终结果:
process parent
445 556
112 556
希望这有所帮助。
关于第3表Table0
问题的更新编辑:
假设您的查询SELECT [process] FROM [Table0] WHERE [Name] LIKE '%Aswini%'
将包含上述查询的有效进程以返回,则只需更改上述主查询的WHERE子句。
以前的WHERE子句:
WHERE C.[n] = (SELECT MAX([n]) FROM [CTE] WHERE [process] = C.[process])
更新了WHERE子句:
WHERE
C.[n] = (SELECT MAX([n]) FROM [CTE] WHERE [process] = C.[process]) AND
C.[process] IN (SELECT [process] FROM [Table0] WHERE [Name] LIKE '%Aswini%')
在进程具有多个父级时编辑可能的重复项
如果进程有多个父(??),则上述查询会生成重复项。为了消除重复项并提供更稳健的方法来确定流程的最顶层父级,进行了以下修改:
parent
连接到Table1
,CTE的锚点部分将进程的实际父级放在Table2
字段中。此连接应该是左连接,因此没有父项的进程(如果可能)也将包含在结果中;他们的parent
值将等于他们自己的进程ID。process
不等于parent
)。这是为了避免递归中的无限循环(如果可能的话)。parent
字段的值也在另一个结果记录中用作相同基本过程的exec
字段的值(process
字段中的值)。因为在这种情况下,parent
字段不是最终的父值,而其他结果记录可能是包含实际父级的更合适的候选者。换句话说:如果进程A有父B,进程B有父C,则CTE中有三个相关结果:(A,A,B),(A,B,C)和(B,B,C) )。结果(A,A,B)无效,因为结果中也有更合适的候选(A,B,C)。最终结果应包括(A,C)和(B,C),但不包括(A,B)。这个逻辑是使用WHERE子句中的EXISTS运算符中的子查询实现的,但当然也可以使用CTE本身的LEFT JOIN来实现。n
不再使用并已被删除。最终查询将如下所示:
WITH [CTE] AS
(
SELECT
T1.[exec] AS [process],
T1.[exec],
COALESCE(T2.[processid], T1.[exec]) AS [parent]
FROM
[Table1] AS T1
LEFT JOIN [Table2] AS T2 ON T2.[stepid] = T1.[stepid]
UNION ALL
SELECT
C.[process],
T1.[exec],
T2.[processid]
FROM
[CTE] AS C
INNER JOIN [Table1] AS T1 ON T1.[exec] = C.[parent]
INNER JOIN [Table2] AS T2 ON T2.[stepid] = T1.[stepid]
WHERE
C.[parent] <> C.[process]
)
SELECT DISTINCT C.[process], C.[parent]
FROM [CTE] AS C
WHERE
NOT EXISTS (SELECT 1 FROM [CTE]
WHERE [process] = C.[process] AND [exec] = C.[parent])
AND C.[process] IN (SELECT [process] FROM [Table0] WHERE [name] LIKE '%Aswini%')
我希望这对你来说效果很好。
您是否尝试使用游标并将第一个表存储在游标中并通过直到游标末尾来获取进程ID。
DECLARE f_cursor CURSOR FOR
Select Exec, stepid
from Table1
OPEN f_cursor
FETCH NEXT FROM f_cursor
INTO @exec,@stepid
WHILE @@FETCH_STATUS = 0
BEGIN
select b.processid
from Table1 a
inner join Table2 b on a.stepid = b.stepid
where a.condition = 0
and a.exec =@exec
//store the processid somewhere for later use.
END
CLOSE f_cursor;
DEALLOCATE f_cursor;