几分钟前我问here如何使用递归CTE获取父记录。 这现在有效,但是当我创建一个返回所有父节点的Table值函数时,我得到了错误的顺序(向后,由PK idData排序)。我无法直接订购,因为我需要CTE提供的逻辑顺序。
这给出了正确的顺序(从下一个父级到该父级,依此类推):
declare @fiData int;
set @fiData=16177344;
WITH PreviousClaims(idData,fiData)
AS(
SELECT parent.idData,parent.fiData
FROM tabData parent
WHERE parent.idData = @fiData
UNION ALL
SELECT child.idData,child.fiData
FROM tabData child
INNER JOIN PreviousClaims parent ON parent.fiData = child.idData
)
select iddata from PreviousClaims
但是以下函数以向后的顺序返回所有记录(按PK排序):
CREATE FUNCTION [dbo].[_previousClaimsByFiData] (
@fiData INT
)
RETURNS @retPreviousClaims TABLE
(
idData int PRIMARY KEY NOT NULL
)
AS
BEGIN
DECLARE @idData int;
WITH PreviousClaims(idData,fiData)
AS(
SELECT parent.idData,parent.fiData
FROM tabData parent
WHERE parent.idData = @fiData
UNION ALL
SELECT child.idData,child.fiData
FROM tabData child
INNER JOIN PreviousClaims parent ON parent.fiData = child.idData
)
INSERT INTO @retPreviousClaims
SELECT idData FROM PreviousClaims;
RETURN;
END;
select * from dbo._previousClaimsByFiData(16177344);
更新 由于每个人都认为CTE没有订购(任何“排序”将是完全随意和巧合),我想知道为什么相反似乎是真的。我向很多家长询问了一个孩子的要求,当我从孩子到父母等等时,CTE中的命令完全符合逻辑顺序。这意味着CTE正在像光标一样从一个记录到另一个记录进行迭代,而后面的select则按照这个顺序返回它。但是当我打电话给TVF时,我得到了主键idData的顺序。
解决方案很简单。我只需要删除TVF返回表的父键。所以改变......
RETURNS @retPreviousClaims TABLE
(
idData int PRIMARY KEY NOT NULL
)
为...
RETURNS @retPreviousClaims TABLE
(
idData int
)
..它保持正确的“顺序”(它们被插入到CTE的临时结果集中的顺序相同)。
UPDATE2:
因为Damien提到“CTE-Order”在某些情况下会发生变化,我会在CTE中添加一个新的列relationLevel
,它描述了父记录的关系水平(顺便提一下,这一点非常有用) fe for ssas cube)。
所以最终的Inline-TVF(返回所有列)现在是:
CREATE FUNCTION [dbo].[_previousClaimsByFiData] (
@fiData INT
)
RETURNS TABLE AS
RETURN(
WITH PreviousClaims
AS(
SELECT 1 AS relationLevel, child.*
FROM tabData child
WHERE child.idData = @fiData
UNION ALL
SELECT relationLevel+1, child.*
FROM tabData child
INNER JOIN PreviousClaims parent ON parent.fiData = child.idData
)
SELECT TOP 100 PERCENT * FROM PreviousClaims order by relationLevel
)
这是一种示范性的关系:
select idData,fiData,relationLevel from dbo._previousClaimsByFiData(46600314);
谢谢。
答案 0 :(得分:3)
执行ORDERing的正确方法是向最外面的select添加ORDER BY子句。其他任何东西都依赖于可能随时改变的实现细节(包括数据库/表的大小是否上升,这可能允许更多并行处理)。
如果您需要方便的东西来进行排序,请查看MSDN page on WITH中的示例中的示例D:
WITH DirectReports(ManagerID, EmployeeID, Title, EmployeeLevel) AS
(
SELECT ManagerID, EmployeeID, Title, 0 AS EmployeeLevel
FROM dbo.MyEmployees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.ManagerID, e.EmployeeID, e.Title, EmployeeLevel + 1
FROM dbo.MyEmployees AS e
INNER JOIN DirectReports AS d
ON e.ManagerID = d.EmployeeID
)
将一些similay添加到您的CTE的EmployeeLevel列中,一切都应该有效。
答案 1 :(得分:2)
我认为CTE正在创建排序的印象是错误的。这些行按顺序出现(可能是由于它们最初插入tabData的原因)是巧合。无论如何,TVF正在返回一个表,所以如果你想保证订购,你必须向你用来调用它的SELECT显式添加一个ORDER BY:
select * from dbo._previousClaimsByFiData(16177344) order by idData
答案 2 :(得分:2)
在任何地方都没有ORDER BY
- 无论是在表值函数中,还是在该TVF的SELECT
中。
任何“订购”都将完全随意而巧合。
如果您需要特定订单,则需要指定ORDER BY。
那你为什么不能只为你的SELECT添加一个ORDER BY:
SELECT * FROM dbo._previousClaimsByFiData(16177344)
ORDER BY (whatever you want to order by)....
或将您的ORDER BY
放入TVF:
INSERT INTO @retPreviousClaims
SELECT idData FROM PreviousClaims
ORDER BY idData DESC (or whatever it is you want to order by...)