交叉应用中的 ROW_NUMBER 基于存在子句生成“不正确”值
Posted
技术标签:
【中文标题】交叉应用中的 ROW_NUMBER 基于存在子句生成“不正确”值【英文标题】:ROW_NUMBER in cross apply generating "incorrect" values based on exists clause 【发布时间】:2016-08-18 15:31:15 【问题描述】:这里是sql:
-- Schema
DECLARE @ModelItem TABLE (
ModelItemId UNIQUEIDENTIFIER,
MetamodelItemId UNIQUEIDENTIFIER
)
DECLARE @MetamodelItemAncestor TABLE (
MetamodelItemId UNIQUEIDENTIFIER,
ParentMetamodelItemId UNIQUEIDENTIFIER,
AncestorLevel INT
)
DECLARE @SolutionMetamodelItem TABLE (
MetamodelItemId UNIQUEIDENTIFIER,
SolutionId UNIQUEIDENTIFIER
)
INSERT INTO @ModelItem VALUES ('EC6AC6A9-684E-E611-8117-00155D026308', '2AB1F075-684E-E611-8117-00155D026308')
INSERT INTO @MetamodelItemAncestor
VALUES ('2AB1F075-684E-E611-8117-00155D026308', '2AB1F075-684E-E611-8117-00155D026308', 0),
('2AB1F075-684E-E611-8117-00155D026308', 'AA12E380-CA4D-E611-8117-00155D026308', 1)
INSERT INTO @SolutionMetamodelItem
VALUES ('2AB1F075-684E-E611-8117-00155D026308', 'f612a333-ca4d-e611-8117-00155d026308'),
('AA12E380-CA4D-E611-8117-00155D026308', 'fc160f3e-ca4d-e611-8117-00155d026308')
-- query
DECLARE @ModelItemId TABLE (EntityId UNIQUEIDENTIFIER)
DECLARE @SolutionId TABLE (EntityId UNIQUEIDENTIFIER)
INSERT INTO @ModelItemId
VALUES ('EC6AC6A9-684E-E611-8117-00155D026308')
INSERT INTO @SolutionId
VALUES ('f612a333-ca4d-e611-8117-00155d026308'), ('fc160f3e-ca4d-e611-8117-00155d026308')
SELECT mia.*
FROM (
SELECT M.EntityId AS ModelItemId, S.EntityId AS SolutionId
FROM @ModelItemId AS M
CROSS JOIN @SolutionId AS S
) AS m
CROSS APPLY (
SELECT
MI.ModelItemId,
OTA.ParentMetamodelItemId AS [MetamodelItemId],
ROW_NUMBER() OVER (PARTITION BY [MI].[ModelItemId] ORDER BY [OTA].[AncestorLevel] ASC) AS [AspectRank]
FROM @ModelItem AS MI
INNER JOIN @MetamodelItemAncestor AS OTA
ON MI.MetamodelItemId = OTA.MetamodelItemId
WHERE
MI.ModelItemId = m.ModelItemId
AND EXISTS (
SELECT 1
FROM @SolutionMetamodelItem AS MSMI
WHERE MSMI.MetamodelItemId = OTA.ParentMetamodelItemId
AND MSMI.SolutionId = m.SolutionId
)
) mia
SELECT mia.*
FROM @ModelItemId AS m
CROSS APPLY (
SELECT
MI.ModelItemId,
OTA.ParentMetamodelItemId AS [MetamodelItemId],
ROW_NUMBER() OVER (PARTITION BY [MI].[ModelItemId] ORDER BY [OTA].[AncestorLevel] ASC) AS [AspectRank]
FROM @ModelItem as MI
INNER JOIN @MetamodelItemAncestor AS OTA
ON MI.MetamodelItemId = OTA.MetamodelItemId
WHERE
MI.ModelItemId = m.EntityId
AND EXISTS (
SELECT 1
FROM @SolutionMetamodelItem MSMI
WHERE MSMI.MetamodelItemId = OTA.ParentMetamodelItemId
AND MSMI.SolutionId IN (SELECT s.EntityId FROM @SolutionId AS s)
)
) mia
注意 AspectRank。在第二个查询中,它正确地根据分区顺序增加了值。
查看执行计划,对于第一个查询,row_number(序列项目)似乎与@solution
表的扫描同时运行,但我仍然不完全确定为什么它没有增加行号值,因为有重复的项目。
有人能解释一下吗?我需要使用第一种方法,因为交叉应用查询实际上是一个以 ModelItemId
和 SolutionId
为参数的 UDF。
【问题讨论】:
【参考方案1】:我假设交叉应用是针对外部查询中的每一行单独执行的 -> 返回的每一行都是第一(也是唯一)行。
如果这实际上是您的数据所在的位置,为什么您需要在交叉中应用行号,而不是在外部查询中?
【讨论】:
因为最后我需要在WHERE
子句中添加一个AspectRank = 1
以及我的数据。
另外,行号(APPLY
中的所有内容)都在 UDF 中。
所以只需在外部查询中添加 row_number() 并将其包装在派生表中以添加 AspectRank = 1 子句?仍然不明白为什么您甚至希望在 UDF 中包含 row_number,因为它不知道其他行的数据是什么。
本质上这个函数是从实体框架中调用的。所以我正在通过 linq 执行交叉应用。现在,我只能通过实体框架传入 ModelItemId 和 SolutionId(即唯一标识符)。我只能使用第一种方法来构建它(据我所知)。问题是数据在两种方法中都可用,不是吗?唯一的区别是exsits子句,一个是使用IN
,另一个是在apply外部使用=
(所以这是问题所在?)
我可以弄清楚,问题是您的 row_number 是部分完成的,然后当然会重置它。我对 linq 一无所知,但如果您能够写一个新问题并简单解释问题,也许有人可以提供帮助以上是关于交叉应用中的 ROW_NUMBER 基于存在子句生成“不正确”值的主要内容,如果未能解决你的问题,请参考以下文章
使用内连接,左外连接,交叉应用获取语法错误与 Where 子句