交叉应用中的 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 表的扫描同时运行,但我仍然不完全确定为什么它没有增加行号值,因为有重复的项目。

有人能解释一下吗?我需要使用第一种方法,因为交叉应用查询实际上是一个以 ModelItemIdSolutionId 为参数的 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 子句

使用ROW_NUMBER()窗口功能选择行

在某个时间段查找某连续出现问题

ROW_NUMBER SQL Server 2005的LIMIT功能实现(ROW_NUMBER()排序函数)

DB2 中的 ROW_NUMBER()

oracle查询优化