【问题标题】:SQL Server recursive CTE and pagingSQL Server 递归 CTE 和分页
【发布时间】:2009-09-06 16:21:03
【问题描述】:

我有这张桌子

 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 paging common-table-expression


    【解决方案1】:

    这是您为分页更新的过程:

    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
    

    【讨论】:

    • 您需要关于 FRIEND_BLOCKED_LIST 表的哪些信息?
    • 同样在联合后的第二次选择中,它应该是 WHERE t.friend= @un 而不是 WHERE t.un = @un 所以它们不是相同的查询
    • 列列表(如果不是很长),以及 FRIEND_BLOCKED_LIST 上的 UNION 的逻辑是什么。按原样查询,看起来它会为同一个人返回 FRIEND_BLOCKED_LIST.friend 和 FRIEND_BLOCKED_LIST.un(?)。目前尚不清楚表中发生了什么。
    • 修正了 UNION 的第二部分,抱歉我的错字。
    • 我正在尝试选择(比如说)usera 作为朋友的用户以及将 usera 作为朋友的用户
    【解决方案2】:

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

    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;
    

    【讨论】:

    • , recursive_friends as (selectfriend , row_number() over (order byfriend asc) as rnfrom FRIENDS) 似乎不对
    猜你喜欢
    • 2012-12-25
    • 2012-04-23
    • 2014-05-19
    • 2021-10-10
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多