1

ストアド プロシージャで SQL Server をループしようとするのがいかに悪いかについての投稿がいくつかあることを知っています。しかし、私は自分がやろうとしていることを完全には見つけていません。内部で直接 Excel にリンクできるデータ接続を使用しています。

ほとんどのループを標準のクエリに変換できると言っている投稿を見たことがあります。しかし、私の人生では、これに問題があります。

custIDタイプ 38,40 のイベントの直前に注文があるすべての s が必要です。ただし、イベントと最初のクエリの順序の間に他の順序がない場合にのみ取得してください。

したがって、3 つの部分があります。最初に、時間枠に基づいてすべての注文 (orders テーブル) を一時テーブルにクエリします。

Select into temp1 odate, custId from orders where odate>'5/1/12'

次に、一時テーブルを使用してセカンダリ テーブルの内部結合を行い、現在の注文の前に過去に発生した可能性のある顧客イベント (LogEvent テーブル) を取得できます。

Select into temp2 eventdate, temp1.custID from LogEvent inner join temp1 on 
temp1.custID=LogEvent.custID where EventType in (38,40) and temp1.odate>eventdate
order by eventdate desc

ここでの問題は、実行しようとしているクエリが、各顧客の最新情報のみが必要な最初のクエリから、各顧客のすべての行を返すことです。したがって、これはクライアント側で、すべての古いものではなく 1 つのイベントのみを取得するためにループする場所です。しかし、すべてのクエリを Excel 内で実行する必要があるため、クライアント側を実際にループすることはできません。

3 番目のステップでは、2 番目のクエリの結果を使用して、最新の注文と以前の注文の間でイベントが発生したかどうかを確認できます。イベントが注文に先行し、その間に他の注文がないデータのみが必要です。

Select ordernum, shopcart.custID from shopcart right outer join temp2 on 
shopcart.custID=temp2.custID where shopcart.odate >= temp2.eventdate and
ordernum is null

これを簡素化し、クライアントで実行するある種のループの代わりに、SQL Server で実行するようにセットベースにする方法はありますか?

4

2 に答える 2

2

これは、セットベースの表記に切り替える良い例です。

まず、3つのクエリすべてを1つのクエリにまとめました。一般に、単一のクエリを使用して、クエリオプティマイザに最適な処理を実行させます。実行パスを決定します。また、マルチスレッド/マルチプロセッサマシンでのクエリの偶発的なシリアル化を防ぎます。

キーはイベントを並べ替えるためのrow_number()であるため、最新の値は1になります。これは最後のWHERE句で確認できます。

select ordernum, shopcart.custID
from (Select eventdate, temp1.custID,
             row_number() over (partition by temp1.CustID order by EventDate desc) as seqnum
      from LogEvent inner join
           (Select odate, custId
            from order
            where odate>'5/1/12'
           ) temp1 
           on temp1.custID=LogEvent.custID
      where EventType in (38,40) and temp1.odate>eventdate order by eventdate desc 
     ) temp2 left outer join
     ShopCart
     on shopcart.custID=temp2.custID
 where seqnum = 1 and shopcart.odate >= temp2.eventdate and ordernum is null

「fromorder」は構文エラーを生成するはずだと思いますが、私はあなたの命名規則を守りました。そうでない場合でも、予約されたSQLワードを使用してテーブルと列に名前を付けることは悪い習慣です。

于 2012-05-22T18:46:30.747 に答える
0

新しいバージョンの SQL サーバーを使用している場合は、ROW_NUMBER関数を使用できます。簡単に例を書きます。

;WITH myCTE AS
( 
SELECT
    eventdate, temp1.custID, 
    ROW_NUMBER() OVER (PARTITION BY temp1.custID ORDER BY eventdate desc) AS CustomerRanking 
FROM LogEvent 
JOIN temp1 
    ON temp1.custID=LogEvent.custID 
WHERE EventType IN (38,40) AND temp1.odate>eventdate
)
SELECT * into temp2 from myCTE WHERE CustomerRanking = 1;

これにより、各顧客の最新のイベントがループなしで取得されます。

また、 RANKを使用することもできますが、それは同点の重複を作成しますが、 ROW_NUMBER はパーティションの重複番号を保証しません。

于 2012-05-22T18:35:22.233 に答える