我想编写一个select语句输出,除其他外,它还包含lowest_bid和highest_bid列。我知道如何做到这一点,但我希望我也想要将用户(user_firstname和user_lastname组合成他们自己的列)显示为lowest_bidder和highest_bidder。到目前为止我所拥有的是:
select item_name, item_reserve, count(bid_id) as number_of_bids,
min(bid_amount) as lowest_bid, ???, max(big_amount) as highest_bid,
???
from vb_items
join vb_bids on item_id=bid_item_id
join vb_users on item_seller_user_id=user_id
where bid_status = ‘ok’ and
item_sold = ‘no’
sort by item_reserve
(一旦我弄清楚要把那些放在那里,那么柱子应该去哪里了!)
答案 0 :(得分:1)
为了获取用户,我将聚合分解为他们自己的表,由item_id
加入它们,并使用bid_amount
的最小值或最大值的派生值对其进行过滤。我本可以第三次加入vb_bids
并保留聚合函数,但那将是多余的。
如果您对同一项目的两个完全相同金额的出价较低,则会失败,因为该联接位于bid_amount
。如果您使用此功能,那么您需要在vb_bids
上创建涵盖bid_amount
的索引。
select item_name, item_reserve, count(bid_id) as number_of_bids,
low_bid.bid_amount as lowest_bid, low_user.first_name + ' ' + low_user.last_name,
high_bid.bid_amount as highest_bid, high_user.first_name + ' ' + high_user.last_name
from vb_items
join vb_bids AS low_bid on item_id = low_bid.bid_item_id
AND low_bid.bid_amount = (
SELECT MIN(bid_amount)
FROM vb_bids
WHERE bid_item_id = low_bid.bid_item_id)
join vb_bids AS high_bid on item_id = high_bid.bid_item_id
AND high_bid.bid_amount = (
SELECT MAX(bid_amount)
FROM vb_bids
WHERE bid_item_id = high_bid.bid_item_id)
join vb_users AS low_user on low_bid.user_id=user_id
join vb_users AS high_user on high_bid.user_id=user_id
where bid_status = ‘ok’ and
item_sold = ‘no’
group by item_name, item_reserve,
low_bid.bid_amount, low_user.first_name, low_user.last_name,
high_bid.bid_amount, high_user.first_name, high_user.last_name
order by item_reserve
答案 1 :(得分:1)
这似乎很好地利用了窗口函数。我假设了一列vb_bids.bid_user_id
。如果出价和用户之间没有链接,则无法回答此问题
With x as (
Select
b.bid_item_id,
count(*) over (partition by b.bid_item_id) as number_of_bids,
row_number() over (
partition by b.bid_item_id
order by b.bid_amount desc
) as high_row,
row_number() over (
partition by b.bid_item_id
order by b.bid_amount
) as low_row,
b.bid_amount,
u.user_firstname + ' ' + u.user_lastname username
From
vb_bids b
inner join
vb_users u
on b.bid_user_id = u.user_id
Where
b.bid_status = 'ok'
)
Select
i.item_name,
i.item_reserve,
min(x.number_of_bids) number_of_bids,
min(case when x.low_row = 1 then x.bid_amount end) lowest_bid,
min(case when x.low_row = 1 then x.username end) low_bidder,
min(case when x.high_row = 1 then x.bid_amount end) highest_bid,
min(case when x.high_row = 1 then x.username end) high_bidder
From
vb_items i
inner join
x
on i.item_id = x.bid_item_id
Where
i.item_sold = 'no'
Group By
i.item_name,
i.item_reserve
Order By
i.item_reserve
<强> Example Fiddle 强>
答案 2 :(得分:1)
由于以下优点,我非常喜欢在这种情况下使用通用表格(CTE):
所以,我建议的方法是这样的:
-- 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
希望有所帮助!