SQL Server 递归 CTE 和分页

问题描述 投票:0回答:2

我有这张桌子

 CREATE TABLE [dbo].[friend_blocked_list](
 [subdomain] [varchar](50) NOT NULL,
 [un] [nvarchar](50) NOT NULL,
 [friend] [nvarchar](50) NOT NULL,
 [is_blocked] [bit] NOT NULL,
 [approved] [bit] NOT NULL)

我使用以下查询从中选择数据。选择查询结合了已添加为好友的用户和已被用户添加为好友的用户

declare @un varchar(50), @subdomain varchar(50)

set @un='user2';
set @subdomain ='test.domain.com';

WITH FRIENDS as
(
  SELECT friend
  FROM friend_blocked_list
  WHERE un=@un and subdomain=@subdomain and approved=1 and is_blocked=0

  UNION ALL

  SELECT un as friend
  FROM friend_blocked_list
  WHERE friend=@un and subdomain=@subdomain and approved=1 and is_blocked=0
)
select friend from FRIENDS group by FRIENDS.friend order by FRIENDS.friend asc

它适用于少量数据,但我希望能够在服务器端进行分页以减少负载。我正在尝试将它与下面的分页 sp 结合起来

create PROCEDURE [dbo].[Paging]
    @subdomain varchar(50),
    @un varchar(50),
    @PageNumber int,
    @PageSize int
AS
BEGIN
   --paging
   DECLARE @FirstRow INT,@LastRow INT,@RowCount INT,@PageCount INT

   --find recordcount and pages
   SELECT @RowCount = COUNT(*), @PageCount = COUNT(*) / @PageSize 
   FROM friend_blocked_list 
   WHERE subdomain=@subdomain AND un=@un AND approved=1 AND is_blocked=0;

   --- calculate pages    
   IF @RowCount % @PageSize != 0 SET @PageCount = @PageCount + 1 
   IF @PageNumber < 1 SET @PageNumber = 1 
   IF @PageNumber > @PageCount SET @PageNumber = @PageCount 

   SELECT 
        CurrentPage = @PageNumber, 
        TotalPages = @PageCount, 
        TotalRows = @RowCount 

   -- mora calculation
   SELECT @FirstRow = ( @PageNumber - 1) * @PageSize + 1,
          @LastRow = (@PageNumber - 1) * @PageSize + @PageSize ;

   WITH MyTopics  AS
   (
      SELECT *, ROW_NUMBER() OVER (order by un asc) AS RowNumber
      FROM friend_blocked_list 
      WHERE subdomain=@subdomain AND un=@un AND approved=1 AND is_blocked=0
   )
   SELECT *
   FROM MyTopics
   WHERE RowNumber BETWEEN @FirstRow AND @LastRow
   ORDER BY RowNumber ASC;
end

但一如既往,我遇到了麻烦:)。主要问题是我查询中的

UNION ALL
。它阻止我使用
ROW_NUMBER() OVER

有什么想法吗?

sql-server select pagination common-table-expression
2个回答
2
投票

以下是更新的寻呼程序:

CREATE PROCEDURE [dbo].[Paging]
  @subdomain varchar(50),
  @un varchar(50),
  @PageNumber int,
  @PageSize int
AS

  DECLARE @start_row int
  DECLARE @end_row int

  SET @end_row = @PageNumber * @PageSize
  SET @start_row = @end_row - (@PageSize - 1)

BEGIN

  WITH FRIENDS AS (
    SELECT t.friend
      FROM FRIEND_BLOCKED_LIST t
     WHERE t.un = @un 
       AND t.subdomain = @subdomain 
       AND t.approved = 1 
       AND t.is_blocked = 0
   UNION ALL
    SELECT t.un as friend
      FROM FRIEND_BLOCKED_LIST t
     WHERE t.friend = @un 
       AND t.subdomain = @subdomain 
       AND t.approved = 1 
       AND t.is_blocked = 0)
SELECT t.friend
  FROM (SELECT f.friend,
               ROW_NUMBER() OVER (ORDER BY f.friend) AS rownum
          FROM FRIENDS f
      GROUP BY f.friend) t
 WHERE t.rownum BETWEEN @start_row AND @end_row

END

如果您可以提供有关

FRIEND_BLOCKED_LIST
表的更多信息,则可以将查询更改为使用一个 CTE。 两个查询的
UNION
具有相同的
WHERE
子句,同时区分两列,这让我想知道是否不能写得更好。 FRIENDS CTE 可以重写为:

SELECT COALESCE(t.un, t.friend) as friend
  FROM FRIEND_BLOCKED_LIST t
 WHERE @un = COALESCE(t.un, t.friend)
   AND t.subdomain = @subdomain 
   AND t.approved = 1 
   AND t.is_blocked = 0

0
投票

将行号应用于要返回的列表:

WITH FRIENDS as
(
SELECT friend
  FROM friend_blocked_list
  WHERE un=@un and subdomain=@subdomain and approved=1 and is_blocked=0
UNION ALL
SELECT un as friend
  FROM friend_blocked_list
  WHERE friend=@un and subdomain=@subdomain and approved=1 and is_blocked=0 )
, recursive_friends as  (
select friend 
 , row_number() over (order by friend asc) as rn
from FRIENDS )
select friend 
  from recursive_friends
  where rn between @firstRow and @lastRow
  order by FRIENDS.friend asc;
© www.soinside.com 2019 - 2024. All rights reserved.