[英]I have a stored procedure and I have made it using UNION ; how can I count total number of rows?
[英]How to set total number of rows before an OFFSET occurs in stored procedure
我创建了一个存储过程,用于对 DataTable 进行筛选和分页。
问题:我需要为在OFFSET
发生之前找到的@TotalRecords
设置一个OUTPUT
变量,否则它@TotalRecord
@RecordPerPage
设置为@RecordPerPage
。
我弄乱了 CTE,也只是尝试了这个:
SELECT *, @TotalRecord = COUNT(1)
FROM dbo
但这也行不通。
这是我的存储过程,其中大部分内容已提取:
ALTER PROCEDURE [dbo].[SearchErrorReports]
@FundNumber varchar(50) = null,
@ProfitSelected bit = 0,
@SortColumnName varchar(30) = null,
@SortDirection varchar(10) = null,
@StartIndex int = 0,
@RecordPerPage int = null,
@TotalRecord INT = 0 OUTPUT --NEED TO SET THIS BEFORE OFFSET!
AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM
(SELECT *
FROM dbo.View
WHERE (@ProfitSelected = 1 AND Profit = 1)) AS ERP
WHERE
((@FundNumber IS NULL OR @FundNumber = '')
OR (ERP.FundNumber LIKE '%' + @FundNumber + '%'))
ORDER BY
CASE
WHEN @SortColumnName = 'FundNumber' AND @SortDirection = 'asc'
THEN ERP.FundNumber
END ASC,
CASE
WHEN @SortColumnName = 'FundNumber' AND @SortDirection = 'desc'
THEN ERP.FundNumber
END DESC
OFFSET @StartIndex ROWS
FETCH NEXT @RecordPerPage ROWS ONLY
先感谢您!
你可以尝试这样的事情:
COUNT(*) OVER()
以获得总行数OFFSET .. FETCH NEXT
)所以你的代码看起来像这样:
-- CTE definition - call it whatever you like
WITH BaseData AS
(
SELECT
-- select all the relevant columns you need
p.ProductID,
p.ProductName,
-- using COUNT(*) OVER() returns the total count over all rows
TotalCount = COUNT(*) OVER()
FROM
dbo.Products p
)
-- now select from the CTE - using OFFSET/FETCH NEXT, get only those rows you
-- want - but the "TotalCount" column still contains the total count - before
-- the OFFSET/FETCH
SELECT *
FROM BaseData
ORDER BY ProductID
OFFSET 20 ROWS FETCH NEXT 15 ROWS ONLY
作为一种习惯,在可能的 null 之前,我更喜欢非 null 条目。 我没有在下面的回复中引用这些内容,并将工作示例仅限于您最关心的两个输入。
我相信可能有一些更干净的方法来应用您的局部变量来过滤查询结果,而无需执行偏移。 您可以返回临时表或永久使用表来清理自身并使用未返回的 ID 作为设置页面的方式。 更流畅,更少大惊小怪。
但是,我知道这并不总是可行的,而且我对那些试图为您解决用例而不试图回答问题的人感到沮丧。 通常有多种方法可以解决任何问题。 你的工作是决定哪一个最适合你的场景。 我们的工作是帮助您找出脚本。
话虽如此,这里有一个使用动态 SQL 的潜在解决方案。 我非常相信动态 SQL,并将其广泛用于基于用户的表控制和 ETL 映射控制的简易性。
use TestCatalog;
set nocount on;
--Builds a temp table, just for test purposes
drop table if exists ##TestOffset;
create table ##TestOffset
(
Id int identity(1,1)
, RandomNumber decimal (10,7)
);
--Inserts 1000 random numbers between 0 and 100
while (select count(*) from ##TestOffset) < 1000
begin
insert into ##TestOffset
(RandomNumber)
values
(RAND()*100)
end;
set nocount off;
go
create procedure dbo.TestOffsetProc
@StartIndex int = null --I'll reference this like a page number below
, @RecordsPerPage int = null
as
begin
declare @MaxRows int = 30; --your front end will probably manage this, but don't trust it. I personally would store this on a table against each display so it can also be returned dynamically with less manual intrusion to this procedure.
declare @FirstRow int;
--Quick entry to ensure your record count returned doesn't excede max allowed.
if @RecordsPerPage is null or @RecordsPerPage > @MaxRows
begin
set @RecordsPerPage = @MaxRows
end;
--Same here, making sure not to return NULL to your dynamic statement. If null is returned from any variable, the entire statement will become null.
if @StartIndex is null
begin
set @StartIndex = 0
end;
set @FirstRow = @StartIndex * @RecordsPerPage
declare @Sql nvarchar(2000) = 'select
tos.*
from ##TestOffset as tos
order by tos.RandomNumber desc
offset ' + convert(nvarchar,@FirstRow) + ' rows
fetch next ' + convert(nvarchar,@RecordsPerPage) + ' rows only'
exec (@Sql);
end
go
exec dbo.TestOffsetProc;
drop table ##TestOffset;
drop procedure dbo.TestOffsetProc;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.