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 クエリ (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,

ただし、型の競合のため、これは機能しません。2つのオプションがあります。まず、すべてのタイプを正しい並べ替え順序で文字列に変換します(日付の場合はYYYY-MM-DD、数値の場合はゼロパッド)。または、これはストアドプロシージャであるため、それぞれに個別のクエリを作成します。

問題は、すべてを文字列として取得する可能性があることですが、ASCとDESCを取得する方法がまだわかりません。これには2つのクエリが必要になると思います。これは、ストアドプロシージャ内にあるため、実行可能です。

アーロンの答えは好きですが、改善できると思います。

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()呼び出しが1つしかないことです。ソートに実際に使用されている値を除いて、すべての値はNULLになります。

于 2012-07-10T00:46:40.443 に答える