私は、次の利点があるため、このような状況で Common Table Expressions (CTE) を使用することを大いに気に入っています。
- ロジックのさまざまな部分を分離し、可読性を高めます。
- 複雑さの軽減 (たとえば、多数のフィールドを GROUP BY する必要や、同じ結合を複数回繰り返す必要があるなど)。
したがって、私の提案するアプローチは次のようなものになります。
-- semi-colon must precede CTE
;
-- collect bid info
WITH item_bids AS (
SELECT
i.item_id, i.item_name, i.item_reserve, b.bid_id, b.bid_amount,
(u.first_name + ' ' + u.last_name) AS bid_user_name
FROM vb_items i
JOIN vb_bids b ON i.item_id = b.bid_item_id
JOIN vb_users u ON b.user_id = u.user_id
WHERE b.bid_status = 'ok'
AND i.item_sold = 'no'
),
-- group bid info
item_bid_info AS (
SELECT item_id, item_name, item_reserve
COUNT(bid_id) AS number_of_bids, MIN(bid_amount) AS lowest_bid, MAX(bid_amount) AS highest_bid
FROM item_bids
GROUP BY item_id, item_name, item_reserve
)
-- assemble final result
SELECT
bi.item_name, bi.item_reserve, bi.number_of_bids,
bi.low_bid, low_bid.bid_user_name AS low_bid_user,
bi.high_bid, high_bid.bid_user_name AS high_bid_user
FROM item_bid_info bi
JOIN item_bids AS low_bid ON bi.lowest_bid = low_bid.bid_amount AND bi.item_id = low_bid.bid_item_id
JOIN item_bids AS high_bid ON bi.lowest_bid = high_bid.bid_amount AND bi.item_id = high_bid.bid_item_id
ORDER BY bi.item_reserve;
SQL ステートメント全体 (先頭から のWITH
後の最後のセミコロンまでORDER BY
) は単一のステートメントであり、オプティマイザーによってそのように評価されることに注意してください。(一部の人々は、一時テーブルのように各部分が個別に評価され、すべての行が最後のステップで最後に結合されると考えています。それはどのように機能するかではありません。CTE はサブクエリと同じくらい効率的です。)
また、このアプローチはJOIN
入札金額に基づいているため、1 つのアイテムに対して同じ入札があった場合は失敗することに注意してください。(とにかく、それは無効な状態であるべきだと思われますよね?) また、以下に応じて効率上の懸念があるかもしれません:
- あなたのテーブルのサイズ
- ルックアップでインデックスを使用できるかどうか
一意の制約を含めることで両方の問題に対処できます (これには、外部キーのbid_item_idにもインデックスを付けるという追加の利点があります。常に良い方法です):
ALTER TABLE [dbo].[vb_bids] ADD CONSTRAINT [UK_vbBids_item_amount]
UNIQUE NONCLUSTERED (bid_item_id, bid_amount)
GO
それが役立つことを願っています!