我有一张资产表:
id|name|parentId
我要为资产建立的视图是:
{
'Id': ......,
'Name': ....,
'ChildrenIds': []
}
我需要一个查询,以选择前50个资产及其直接子资产(因此结果可能超过50个结果)。
我有一个可以使用的CTE,但是它很慢(5秒,对parentId和id进行了索引):
WITH MyCte as
(
SELECT TOP 50 a.Id, a.Name, a.ParentAssetId
FROM assets a
UNION ALL
SELECT a2.AssetId, a2.ParentAssetId
FROM assets a2
INNER JOIN MyCte cte ON cte.Id = a2.ParentAssetId
)
SELECT * From MyCte;
此联接查询完成了我想要的一半。
SELECT TOP 50 a.Id, a.Name, a.ParentAssetId
FROM assets a
LEFT JOIN assets a2 ON a2.ParentAssetId = a.Id
JOIN问题,它给了我50个结果,仅此而已。我需要后代信息来构建视图。我可以进行2次查询,但我不想这样做。
有什么建议吗?
也许我有更好的方法来建立这种观点?没有50 + N的要求? 您可以将GROUP BY与STRING_AGG一起使用,但我担心大小限制。
SAMPLE DATA:
1,Site1,NULL
2,Site2,1
3,Site3,1
4,Site4,2
5,Site5,NULL
TOP 3 ORDER BY ID DESC结果将返回
1,Site1,NULL
2,Site2,1
3,Site3,1
4,Site4,2
但是我想最好是这样的:
1,Site1,NULL|2,Site2,1|3,Site3,1
2,Site2,1|4,Site4,2
3,Site3,1
答案 0 :(得分:0)
您可以使用临时表来实现所需的内容。
table(dplyr::lag(a),a)
a
1 2 3 4 5 6 7
1 0 0 1 1 0 0 0
2 0 0 1 0 0 1 0
3 1 0 0 1 0 0 1
4 0 1 0 0 0 0 0
5 0 0 1 0 1 0 0
6 0 0 0 0 1 0 0
7 0 0 0 0 0 0 1
请注意,这不是确定性的,因为使用TOP时没有ORDER BY。
答案 1 :(得分:0)
您可以使用此CTE并从中进行查看:
WITH MyCte as
(
SELECT TOP 50 a.Id, a.Name, a.ParentAssetId
FROM assets a
)
SELECT cte.*, a1.Id as ChildId, a1.Name as ChildName
FROM MyCte cte
INNER JOIN assets a1
ON a1.ParentAssetId=cte.Id
诚然,这将为您提供与问题中的UNION CTE不同的结果集,但是我假设您可以对用户应用程序进行简单的调整以处理它。这样,对于应用程序来说甚至可能更容易/更有效,因为这些关系存在于行中,而不必进行推断。
也就是说,如果您使用的是最新版本的SQL Server,则可能会查看内置的JSON函数,因为看起来这是您最终尝试生成的输出。
答案 2 :(得分:0)
根据您提供的内容,如果我了解,我认为您正在寻找
WITH CTE AS
(
SELECT TOP 3 *
FROM T
ORDER BY ID DESC
)
SELECT *
FROM CTE
UNION
SELECT *
FROM T
WHERE ID IN (SELECT ParentId FROM CTE);
返回:
+----+-------+----------+
| ID | Name | ParentId |
+----+-------+----------+
| 1 | Site1 | |
| 2 | Site2 | 1 |
| 3 | Site3 | 1 |
| 4 | Site4 | 2 |
| 5 | Site5 | |
+----+-------+----------+
这里是 db<>fiddle
更新:
由于您正在寻找一种传递INT
值的方法,该值表示TOP
中使用的行号,因此您可以将内联表值函数创建为
CREATE FUNCTION dbo.MyFunction (@Rows INT = 1)
RETURNS TABLE
AS
RETURN
(
WITH CTE AS
(
SELECT TOP (@Rows) *
FROM T
ORDER BY ID DESC
)
SELECT *
FROM CTE
UNION
SELECT *
FROM T
WHERE ID IN (SELECT ParentId FROM CTE)
);
并称其为
SELECT *
FROM dbo.MyFunction(2)