首页 > 解决方案 > SQL Server:使用父子关系偏移行获取下一个

问题描述

我们目前使用分页网格来显示我们的一些数据。为了完成分页,我们将 start 和 count 参数传递到我们的数据函数中,用于查询的 OFFSET 和 FETCH NEXT 部分。

一般来说,这有效,除非我们的数据中有一个->多的关系。在这些情况下,我们(如预期的那样)为每个子属性获得重复的父行。使用 Dapper,我们可以适当地将这些数据合并到对象中。

然而,问题是 OFFSET 和 FETCH NEXT 也将这些子行考虑在内。如果我们想要 25 条记录,如果这些父记录的某个部分有多个子记录,我们可能只取回 15 条父记录。

典型例子:

SELECT C.Name, U.Make 
FROM Contacts C 
LEFT JOIN Units U on U.ContactId = C.ContactId 
OFFSET 10 FETCH NEXT 5 ROWS ONLY

潜在回报值:

 Name  | Make
 Tommy | Toyota
 Tommy | Nissan
 Bob   | Chevy
 Bob   | Ford
 Christie | Chevy

可以看到,即使总记录集是请求的 5 项,我们也只返回 3 条父记录。

是否有一种构造查询的方法,使得 OFFSET 和 FETCH NEXT 仅适用于父表/记录,而无需通过仅获取父记录和正在运行的查询来填充我们的子属性来强制执行此操作?

蛮力示例:

var contacts = queryToGetParentRecords(); foreach(var contact in contacts){ contact.CarMakes = queryToGetChildData(contact.Id); }

标签: .netsql-server

解决方案


You need an ORDER BY in your SQL to make use of the FETCH, since there is no order to a SQL table.

I would use a window function for your purpose. If you are ordering by ContactId something like the following. You need to use a CTE or subquery to make use of the dense_rank results:

;with cte as (

    SELECT 
         C.Name, U.Make 
        ,dense_rank() over (order by C.ContactId) FetchRank
        FROM Contacts C 
        LEFT JOIN Units U
        ON U.ContactId = C.ContactId 

)
select Name, Make
    from cte
    where FetchRank between 10 and 15

推荐阅读