SQL 在 CTE 上使用 COUNT(*) 的存储过程 SET 输出参数

SQL stored procedure SET output param using COUNT(*) ON a CTE

我正在使用带有 CTE 的存储过程并进行一些分页。我还想 return 一个输出参数,其中包含在我的分页之前 returned 查询的总计数。 我的问题是我收到 "OrderedSet" 不是有效对象名称的错误。

    @ft INT,
    @page INT,
    @pagesize INT,
    @count INT OUTPUT
AS
BEGIN

DECLARE @offset INT
SET @offset = @page * @pagesize
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    WITH OrderedSet AS (
    SELECT *, ROW_NUMBER() OVER (ORDER BY Id DESC) AS 'Index'
    FROM tbl_BulkUploadFiles buf
    WHERE
    buf.FileType = @ft )
    SELECT * FROM OrderedSet WHERE [Index] BETWEEN @offset AND (@offset + @pagesize)
    SET @count = (SELECT COUNT(*) FROM OrderedSet)
END

所以我的问题在最后一行,错误是最后一个 OrderedSet 不是有效的对象名称。

在此先感谢您的帮助!

我看到的唯一选择是将查询重复为内联视图

  select @count = numrows FROM 
  (
    SELECT count(*) as numrows, 
    ROW_NUMBER() OVER (ORDER BY Id DESC) AS 'Index'
    FROM tbl_BulkUploadFiles buf
    WHERE
    buf.FileType = @ft 
    ) XXX WHERE [Index] BETWEEN @offset AND (@offset + @pagesize)

您不能在多个 select 语句中使用 CTE。来自 MSDN docs(谈论 CTE 本身)。

This is derived from a simple query and defined within the execution scope of a single SELECT, INSERT, UPDATE, or DELETE statement.

您要么需要 运行 CTE 两次(可能是个坏主意),要么 select 将 CTE 的结果转换为临时文件 table 然后 select来自其中的分页数据以及总计数。

这里有 2 种方法可以避免多次复制和粘贴所有 CTE。

Return 作为结果集列的总行数

这里的好处是您可以计算总行数而无需多个查询和临时 tables,但是您必须在前端添加逻辑以从结果集的第一行获取总行数在遍历它以显示分页集之前。另一个考虑因素是您必须考虑没有返回行,因此如果没有返回行则将总行数设置为 0。

;WITH OrderedSet AS (
    SELECT
        *,
        ROW_NUMBER() OVER (ORDER BY Id DESC) AS Seq,
        ROW_NUMBER() OVER (ORDER BY Id) AS SeqRev
    FROM tbl_BulkUploadFiles buf
    WHERE buf.FileType = @ft
)
    SELECT *, Seq + SeqRev - 1 AS [TotalCount]
    FROM OrderedSet
    WHERE Seq BETWEEN @offset AND (@offset + @pagesize)

利用温度 table

虽然有临时成本 table,但如果您的数据库实例遵循 tempdb 的最佳实践(多核的多个文件、合理的初始大小等),200k 行可能不是很大处理,因为存储过程完成后上下文丢失,所以 200k 行不会存在太久。但是,如果经常同时调用这些存储过程,它确实会带来挑战——扩展性不太好。但是,您并没有保留整个 table - 只是分页行,所以希望您的页面大小远小于 200k 行。

由于 ASC 和 DESC 的方法,下面的方法试图通过仅获取第一行来最小化能够计算行数的 tempdb 成本 ROW_NUMBERs。

;WITH OrderedSet AS (
    SELECT
        *,
        ROW_NUMBER() OVER (ORDER BY Id DESC) AS Seq,
        ROW_NUMBER() OVER (ORDER BY Id) AS SeqRev
    FROM @buf buf --tbl_BulkUploadFiles buf
    WHERE buf.FileType = @ft
)
    SELECT * INTO #T
    FROM OrderedSet
    WHERE Seq BETWEEN @offset AND (@offset + @pagesize)
SET @count = COALESCE((SELECT TOP 1 SeqRev + Seq - 1 FROM #T), 0)
SELECT * FROM #T

注意:上面用于计算行数的方法改编自 How to reference one CTE twice? and http://www.sqlservercentral.com/articles/T-SQL/66030/