0

我正在使用存储过程尝试从排序的 SQL 查询中获取前几行,其中输入参数指定要检索的行数和排序条件。

我已经能够正确检索前几行,但是当我尝试对结果进行排序时,它们只是使用默认条件(主键)排序。

所以我想知道是否有人可以看看它?

USE [database]
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[x0] 
@username nvarchar(50),
@sortBy varchar(50),
@sortDirection varchar(4),
@startRow int,
@endRow int

AS
With Ordering AS(

    SELECT ROW_NUMBER() OVER (Order by
        CASE    WHEN @sortBy='datecreate' THEN 'datecreate'
                WHEN @sortBy='id' THEN 'id'
                WHEN @sortBy='DisplayName' THEN 'DisplayName'
        END,
        CASE    WHEN @sortDirection='asc' THEN 'asc'
                WHEN @sortDirection='desc' THEN 'desc'
        END) AS RowNumber,

    dbo.x1.*, dbo.x2.* 
    FROM  dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
    where username = @username
)
SELECT     RowNumber, *, DisplayName AS DisplayName
FROM         Ordering
Where RowNumber BETWEEN @startRow AND @endRow 

我还尝试将排序条件移动到外部 SQL 查询(Where RowNumber BETWEEN @startRow AND @endRow),但运气不佳。

4

2 回答 2

2

你可以这样做:

;WITH Ordering AS
(
   SELECT rnd  = ROW_NUMBER() OVER (ORDER BY datecreate),
          rni  = ROW_NUMBER() OVER (ORDER BY id),
          rnn  = ROW_NUMBER() OVER (ORDER BY DisplayName),
          rndd = ROW_NUMBER() OVER (ORDER BY datecreate DESC),
          rnid = ROW_NUMBER() OVER (ORDER BY id DESC),
          rnnd = ROW_NUMBER() OVER (ORDER BY DisplayName DESC),
    dbo.x1.*, dbo.x2.* 
    FROM dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
    where username = @username
),
x AS 
(
  SELECT RowNumber = CASE @SortDirection 
    WHEN 'asc' THEN CASE @SortBy
      WHEN 'datecreate'   THEN rnd
      WHEN 'id'           THEN rni
      WHEN 'DisplayName'  THEN rnn 
    END
    WHEN 'desc' THEN CASE @sortBy
      WHEN 'datecreate'   THEN rndd
      WHEN 'id'           THEN rnid
      WHEN 'DisplayName'  THEN rnnd
    END, *, DisplayName AS DisplayName
  FROM Ordering
)
SELECT * FROM x
WHERE RowNumber BETWEEN @startRow AND @endRow 
ORDER BY RowNumber;

但老实说,我认为您将从动态 SQL 中获得更好的性能(并且如果optimize for ad hoc workloads启用该设置,它将不会受到上述解决方案中固有的参数嗅探问题或计划缓存膨胀的影响):

DECLARE @sql NVARCHAR(MAX);

SET @sql = N';WITH Ordering AS
  (
    SELECT ROW_NUMBER() OVER (ORDER BY ' + @SortBy + ' '
      + @SortDirection + ') AS RowNumber,
     dbo.x1.*, dbo.x2.* 
   FROM  dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
   where username = @username
  )
  SELECT RowNumber, *, DisplayName AS DisplayName
   FROM Ordering
   Where RowNumber BETWEEN @startRow AND @endRow 
   ORDER BY RowNumber;';

EXEC sp_executesql @sql, 
  N'@username NVARCHAR(50), @startRow INT, @endRow INT',
  @username, @startRow, @endRow;
于 2012-07-10T00:46:04.603 回答
2

您的问题是在查询中使用常量。您正在按常量字符串而不是列进行排序。我认为您正在混淆动态 SQL 和常规 SQL。

要获取名称,您需要使用:

SELECT ROW_NUMBER() OVER (Order by
        CASE    WHEN @sortBy='datecreate' THEN datecreate
            WHEN @sortBy='id' THEN id
            WHEN @sortBy='DisplayName' THEN DisplayName
        END,

但是,由于类型冲突,这不起作用。你有两个选择。首先,将所有类型转换为具有正确排序顺序的字符串(YYYY-MM-DD 用于日期,零填充用于数字)。或者,因为这是一个存储过程,所以为每个创建一个单独的查询。

问题是您可能将所有内容都作为字符串获取,但我仍然不确定如何获取 ASC 和 DESC。我认为您将需要两个查询,这是可行的,因为这是在存储过程中。

我喜欢亚伦的回答,但我认为它可以改进。

WITH Ordering AS (
   SELECT ROW_NUMBER() OVER
                 (ORDER BY (case when @sortBy = 'datecreate' and @sortdirection = 'ASC'
                                 then datecreate
                            end),
                           (case when @sortBy = 'datecreate' and @sortdirection = 'DESC'
                                 then datecreate
                            end) desc,
                           (case when @sortBy = 'id' and @sortdirection = 'ASC'
                                 then id
                            end),
                           (case when @sortBy = 'id' and @sortdirection = 'DESC'
                                 then id
                            end) desc,
                           (case when @sortBy = 'DisplayName' and @sortdirection = 'ASC'
                                 then DisplayName
                            end),
                           (case when @sortBy = 'DisplayName' and @sortdirection = 'DESC'
                                 then DisplayName
                            end) desc
                 ) as rn,
          dbo.x1.*, dbo.x2.*
   FROM dbo.x1 INNER JOIN dbo.x2 ON dbo.x1.type = dbo.x2.type
   where username = @username
)

等等。不同之处在于只有一个 row_number() 调用,具有更复杂的排序表达式。除了实际用于排序的值之外,所有值都将为 NULL。

于 2012-07-10T00:46:40.443 回答