我想要分页&存储过程中的动态orderby
子句(多于一列)。我确实尝试了以下但是给了我一个错误
似乎我不能在Rank()
上使用Row_number()窗口函数不能在另一个窗口函数或聚合的上下文中使用。
除了linq to sql
之外,还有其他方法可以实现这个目标吗?SELECT [t8].[AssetId],
[t8].[WorkOrderId],
[t8].[IssueDescription] AS [WorkOrderDescription],
[t8].[value] AS [Type],
[t8].[WorkOrderStatusTypeName] AS [Status],
[t8].[value2] AS [StartDate],
[t8].[CompletedDate] AS [CompleteDate],
[t8].[value22] AS [CompletedBy],
ISNULL([t8].[value3],0) AS [Hours]
FROM (
SELECT ROW_NUMBER()
OVER (ORDER BY CASE WHEN @sortColumnName = 'default' THEN (RANK() over( order by [t7].[WorkOrderStatusTypeId] ASC, [t7].[WorkOrderId])) END ,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'asc' THEN [t7].[WorkOrderId] END ASC,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'desc' THEN [t7].[WorkOrderId] END DESC
) AS [ROW_NUMBER],
[t7].[AssetId],
[t7].[WorkOrderId],
[t7].[IssueDescription],
[t7].[value],
[t7].[WorkOrderStatusTypeName],
[t7].[value2],
[t7].[CompletedDate],
[t7].[value22],
[t7].[value3]
from --Different tables
) as t8
WHERE [t8].[ROW_NUMBER] BETWEEN ((@pageIndex-1) * @pageSize)+ 1 AND @pageIndex * @pageSize
ORDER BY [t8].[ROW_NUMBER]
答案 0 :(得分:2)
用于
SELECT CASE
WHEN @sortColumnName ='default' AND @sortOrder = 'asc' then row_number() over (order by [t7].[WorkOrderStatusTypeId], [t7].[CompletedDate] ASC)
WHEN @sortColumnName ='WorkOrderId' AND @sortOrder = 'asc' then row_number() over (order by [t7].[WorkOrderId] ASC)
WHEN @sortColumnName ='WorkOrderId' AND @sortOrder = 'desc' then row_number() over (order by [t7].[WorkOrderId] DESC)
END AS [ROW_NUMBER],
而不是
SELECT ROW_NUMBER()
OVER (ORDER BY CASE WHEN @sortColumnName = 'default' THEN (RANK() over( order by [t7].[WorkOrderStatusTypeId] ASC, [t7].[WorkOrderId])) END ,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'asc' THEN [t7].[WorkOrderId] END ASC,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'desc' THEN [t7].[WorkOrderId] END DESC
) AS [ROW_NUMBER],
不能将RowNumber()和Rank()等嵌套窗口函数放在一起,而是可以在case语句中使用它们。
答案 1 :(得分:1)
似乎您希望默认订单分为两列,并且您尝试使用RANK()
尝试将两个默认排序条件放在一个CASE中。
显然,这是不可能的。一个明显的选择似乎是将两列分成两个CASE,重复@sortColumnName = 'default'
条件:
ROW_NUMBER()
OVER (ORDER BY CASE WHEN @sortColumnName = 'default' THEN [t7].[WorkOrderStatusTypeId] END ASC,
CASE WHEN @sortColumnName = 'default' THEN [t7].[WorkOrderId] END ASC,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'asc' THEN [t7].[WorkOrderId] END ASC,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'desc' THEN [t7].[WorkOrderId] END DESC
另一方面,可以很容易地看出第二个和第三个CASE可以合并为一个,因为当相应的条件为真时,两者都返回相同的表达式。所以,这就是你可以做的事情:
ROW_NUMBER()
OVER (ORDER BY CASE WHEN @sortColumnName = 'default' THEN [t7].[WorkOrderStatusTypeId] END ASC,
CASE WHEN @sortColumnName = 'default' OR @sortColumnName = 'WorkOrderId' AND @sortOrder = 'asc' THEN [t7].[WorkOrderId] END ASC,
CASE WHEN @sortColumnName = 'WorkOrderId' AND @sortOrder = 'desc' THEN [t7].[WorkOrderId] END DESC
如您所见,第二个CASE用于在参数中明确指定该列并指定WorkOrderId ASC
时按'default'
设置排序。
答案 2 :(得分:0)
创建Web API时,进行动态排序的唯一方法是构建Sql字符串并使用内置的sprop“SP_EXECUTESQL”运行它。请参阅下面的解决方案示例,该示例返回一个分页列表,按多列字符串排序,并通过输出参数返回总行数。
请注意,当使用直接连接的字符串时,必须首先检查sql注入恶意代码的参数。在这里,我必须检查SearchTerm和SortTerm
alter PROCEDURE [dbo].[usp_Ranking_SearchForPlayerByName]
@SearchTerm varchar(100),
@WeekNumber int,
@Gender nchar(1),
@SortTerm nvarchar(100),
@PageSize int,
@PageNumber int,
@TotalCount int OUT
AS
BEGIN
SET ANSI_NULLS, QUOTED_IDENTIFIER ON
DECLARE @PreviousWeek int = dbo.PreviousWeekNo(@WeekNumber)
DECLARE @Offset int = (@PageNumber - 1) * @PageSize
DECLARE @sql nvarchar(max) = N'Select
h.PlayerID
,p.Forename as FirstName
,p.Surname as Lastname
,p.Gender as Gender
,''return country of residence'' as Country
,r.Name as Region
,h.Position as RankThisWeek
,previousWk.Position as RankLastWeek
,(previousWk.Position - h.Position) as Change
From PlayerHistories h
left outer join
(Select * from PlayerHistories
where WeekNumber = @PreviousWeek) previousWk on h.PlayerId = previousWk.PlayerId
inner join Players p on h.PlayerId = p.Id
left join Countries c on p.CountryId = c.Id
left join Regions r on c.RegionId = r.Id
Where h.WeekNumber = @WeekNumber And
p.Gender = CASE When @Gender = ''M'' Then ''M'' When @Gender = ''F'' Then ''F'' Else p.gender End And
p.FullName like ''%' + @SearchTerm + '%''
Order by ' + @SortTerm + '
OFFSET @offset ROWS FETCH NEXT @PageSize ROWS ONLY
'
EXEC SP_EXECUTESQL @Sql,
N'@PreviousWeek int, @WeekNumber int, @Gender nchar(1), @offset int, @PageSize int',
@PreviousWeek, @WeekNumber, @Gender, @offset, @PageSize;
SELECT @TotalCount =
(SELECT Count(h.Id)
From PlayerHistories h
left outer join
(Select * from PlayerHistories
where WeekNumber = @PreviousWeek) previousWk on h.PlayerId = previousWk.PlayerId
inner join Players p on h.PlayerId = p.Id
Where h.WeekNumber = @WeekNumber And
p.Gender = CASE When @Gender = 'M' Then 'M' When @Gender = 'F' Then 'F' Else p.gender End And
p.FullName like '%' + @SearchTerm + '%');
END
使用以下语句测试这个:
DECLARE @op int
exec dbo.usp_Ranking_SearchForPlayerByName 'smith',201715,'','LastName DESC, Gender, FirstName',10,1, @op OUTPUT
select @op