4

データの「ページ」をリストに表示する必要があるアプリケーションがあります。基本的な考え方はかなり一般的です。ディスプレイにはアイテムのリストが表示され、ディスプレイの下部には、データの次の「ページ」に移動できるようにする何らかのコントロールがあります。

すべてうまくいっています。私はこれを機能させています。

以下は、「次の」動作をサポートするために使用しているビューのSQLです。

CREATE VIEW CampaignParticipants AS
SELECT  row_number() OVER (ORDER BY TPT.LastName, TPT.FirstName, TPT.DoB) AS RowNumber
        ,CGP.*
        ,TPT.*
FROM    tblCampaignGEDPush CGP
JOIN    tblParticipants TPT
ON      CGP.PartID = TPT.PartID

これが私がVIEWを使用する方法です

SELECT  *
FROM    CampaignParticipants
WHERE   RowNumber >= 0
AND     RowNumber <= 100

これは、VIEWから100件の結果の「最初のページ」を取得することをシミュレートします。結果の各セットを通過するページは、ほんの桃色です。

素晴らしい..しかし:

これを扱ったことがある人の中にはおそらく知っている人もいるでしょうが、これには欠陥があります。検索して最初の結果セットを取得したい場合TPT.LastName like 'R%'、私は運命にあります。

見ていきたいと思いRowNumber = 0ますRowNumber = 100が、「R」の結果はおそらくその範囲外になります。結論:リストは空に戻ります。

そして、それはさらに粘り強くなります。ユーザーは、LastName、FirstName、DoB、Location、Phone、Zipなどを「フィルタリング」できるようにしたいと考えています。

**編集:ビュー内にあるため、「内部」クエリにフィルターを実際に配置することはできません。フィルターは任意に変更できます。

誰かがこの結果セットを取得する方法について何かアイデアがrow_number()ありますか?

4

3 に答える 3

5

このようなことをする必要があります...

SELECT * FROM (
SELECT  *, ROW_NUMBER() OVER (ORDER BY LastName, FirstName, DoB) AS __RN
FROM    CampaignParticipants
WHERE   LastName LIKE 'R%') innerData WHERE __RN BETWEEN 1 and 100

ただし、「*」ではなく列名を使用する必要があります。あなたのテーブルがどのように見えるか分からないので、あなたに代わって記入することはできません.

于 2012-07-20T20:39:39.587 に答える
2

これよりももう少しエレガントなものがあればいいのにと思います。これは私のストアド プロシージャ ソリューションです。私の不完全な SQL スキルが呼び起こすことができる最高のもの。

パラメーター リストの OUT パラメーターは、このセットの合計行に対するものであるため、フロント エンドは、この特定のフィルター セットと一緒に何ページかを認識します。

CREATE PROC [dbo].[procCampaignGEDPushSelect]
    @LastName       VARCHAR(50)     = null
    ,@FirstName     VARCHAR(50)     = null
    ,@Location      VARCHAR(255)    = null
    ,@DoB           DateTime        = null
    ,@Zip           VARCHAR(50)     = null
    ,@Phone         VARCHAR(50)     = null
    ,@Email         VARCHAR(255)    = null
    ,@Gender        VARCHAR(20)     = null
    ,@IsGED         Bit             = 0
    ,@IsBTT         Bit             = 0
    ,@IsOACE        Bit             = 0
    ,@Completed     Bit             = 0
    ,@TotalCount    INT             OUT
AS
BEGIN

SELECT @LastName    = @LastName     + '%'
SELECT @FirstName   = @FirstName    + '%' 
SELECT @Location    = @Location     + '%' 
SELECT @Zip         = @Zip          + '%' 
SELECT @Phone       = @Phone        + '%' 
SELECT @Email       = @Email        + '%' 
SELECT @Gender      = @Gender       + '%' 

SELECT     row_number() OVER (ORDER BY LastName, FirstName, DoB) AS RowNumber
    , TPT.LastName
    , TPT.FirstName
    , TPT.WF1Site
    , TPT.DOB
    , TPT.Zip
    , TPT.Telephone
    , TPT.CellPhone
    , TPT.Email
    , TPT.Gender
    , TPT.IsBTT
    , TPT.IsGED
    , TPT.IsOACE
    , TPT.IsSRS
    ,CGP.*

FROM        tblCampaignGEDPush CGP

JOIN        tblParticipants TPT
ON          CGP.PartID = TPT.PartID

WHERE       1=1

AND         1 = (CASE WHEN @LastName    IS NOT NULL THEN (CASE WHEN TPT.LastName    LIKE @LastName  THEN 1 ELSE 0 END) ELSE 1 END)  
AND         1 = (CASE WHEN @FirstName   IS NOT NULL THEN (CASE WHEN TPT.FirstName   LIKE @Firstname THEN 1 ELSE 0 END) ELSE 1 END)
AND         1 = (CASE WHEN @Location    IS NOT NULL THEN (CASE WHEN TPT.WF1Site     LIKE @Location  THEN 1 ELSE 0 END) ELSE 1 END)  
AND         1 = (CASE WHEN @Zip         IS NOT NULL THEN (CASE WHEN TPT.Zip         LIKE @Zip       THEN 1 ELSE 0 END) ELSE 1 END) 
AND
(           1 = (CASE WHEN @Phone       IS NOT NULL THEN (CASE WHEN TPT.Telephone   LIKE @Phone     THEN 1 ELSE 0 END) ELSE 1 END) 
    OR      1 = (CASE WHEN @Phone       IS NOT NULL THEN (CASE WHEN TPT.CellPhone   LIKE @Phone     THEN 1 ELSE 0 END) ELSE 1 END) 
)
AND         1 = (CASE WHEN @Email       IS NOT NULL THEN (CASE WHEN TPT.Email       LIKE @Email     THEN 1 ELSE 0 END) ELSE 1 END) 
AND         1 = (CASE WHEN @Gender      IS NOT NULL THEN (CASE WHEN TPT.Gender      LIKE @Gender    THEN 1 ELSE 0 END) ELSE 1 END) 
AND         1 = (CASE WHEN @DoB         IS NOT NULL THEN (CASE WHEN TPT.DoB         = @DoB          THEN 1 ELSE 0 END) ELSE 1 END) 
AND         1 = (CASE WHEN @IsGED       != 0        THEN (CASE WHEN TPT.IsGED       = 1             THEN 1 ELSE 0 END) ELSE 1 END) 
AND         1 = (CASE WHEN @IsBTT       != 0        THEN (CASE WHEN TPT.IsBTT       = 1             THEN 1 ELSE 0 END) ELSE 1 END) 
AND         1 = (CASE WHEN @IsOACE      != 0        THEN (CASE WHEN TPT.IsOACE      = 1             THEN 1 ELSE 0 END) ELSE 1 END) 

AND         1 = (CASE WHEN @Completed   != 0        THEN (CASE WHEN CGP.Completed   = 1             THEN 1 ELSE 0 END) ELSE 1 END)

ORDER BY    TPT.LastName
            , TPT.FirstName
            , TPT.DoB


SELECT @TotalCount = @@ROWCOUNT

END

それで、私は考え始めました。私は .NET を使用しているので、このトリッキーでバグが発生しやすい proc (ちなみに、これはかなりうまく機能します) を使用するのではなく、適切な解決策があるかどうか疑問に思います。

元の質問が .NET とは何の関係もないことがわかったので、厳密な SQL ソリューションに関心のある人のために、上記の手順を残します。これはかなりうまく機能すると思います。

そこで、私は IQueryable インターフェイスを掘り下げ始め、ゴールドを獲得しました。

IQueryable<queryParticipant>    qparticipant = db.queryParticipants.AsQueryable();
...
qparticipant = qparticipant.Where( ... any filter you choose );
...

return qparticipant

    .OrderBy( p => p.LastName )
    .OrderBy( p => p.FirstName )
    .OrderBy( p => p.DOB )
    .Select( ... whatever you like ... )
    .Skip( StartRecordNumber )          // This is the trick! Start the query here..
    .Take( PageSize )                   // Take only as many as you need
    ;

以上です。.NET アプローチは、利用できる場合に便利です。Stored Proc は、そのような API が利用できない場合に最適です。

于 2012-07-21T01:50:33.607 に答える
2

まず最初に、ビューの代わりに proc を使用してみてください。ユーザーが非常に多くのフィルタリングを行うことを求めているため、proc はあなたが得た唯一のソリューションです。proc 内で、これらすべてのフィルターを使用してデータをフィルター処理し、row_number を生成してから、最初の 100 と表示します。レコードとか。

于 2012-07-20T20:40:56.683 に答える