我非常喜欢在这种情况下使用公用表表达式 (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
对投标金额进行了计算,因此如果单个项目有相同的投标,它将失败。(无论如何,这似乎应该是一个无效状态,对吧?)此外,您可能会遇到效率问题,具体取决于:
您可以通过包含唯一约束来解决这两个问题(它还具有索引外键 bid_item_id 的额外优势;始终是一个好习惯):
ALTER TABLE [dbo].[vb_bids] ADD CONSTRAINT [UK_vbBids_item_amount]
UNIQUE NONCLUSTERED (bid_item_id, bid_amount)
GO
希望有帮助!