1

我想编写一个选择语句输出,除其他外,它同时具有最低出价和最高出价列。我知道该怎么做,但我还想要将用户(user_firstname 和 user_lastname 合并到他们自己的列中)显示为最低出价和最高出价。到目前为止,我所拥有的是:

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

( ??? 是列应该去的地方,一旦我弄清楚该放什么!)

4

3 回答 3

1

为了获得用户,我将聚合分解到他们自己的表中,通过 连接它们item_id并通过派生值过滤它们,该值是 的最小值或最大值bid_amount。我本可以vb_bids第三次加入并保留聚合函数,但那将是多余的。

如果您对同一项目有两个完全相同金额的低出价,这将失败,因为连接是 on bid_amount。如果你使用它,那么你会想要在 Coverage 上创建一个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
于 2013-10-03T20:47:52.303 回答
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

于 2013-10-03T21:10:09.840 回答
1

我非常喜欢在这种情况下使用公用表表达式 (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

希望有帮助!

于 2013-10-04T00:40:48.103 回答