2

I have an SQL table contains data for the sale of some items. In fact, it has the logs of the sale of items.

For example, there is a sale that contains 2 items: Keyboard (id:1) and mouse(id:2). Buyers can make bids to each item and multiple times, like ebay. So let's assume there are 2 buyers(ids are 97 and 98) made bids a couple of times. The related data would be:

bid_id  |   buyer_id    |   item_id |   amount      |   time                |
1       |   97          |   1       |   44.26       |   2014-01-20 15:53:16 |
2       |   98          |   2       |   30.47       |   2014-01-20 15:54:52 |
3       |   97          |   2       |   40.05       |   2014-01-20 15:57:47 |
4       |   97          |   1       |   42.46       |   2014-01-20 15:58:36 |
5       |   97          |   1       |   39.99       |   2014-01-20 16:01:13 |
6       |   97          |   2       |   24.68       |   2014-01-20 16:05:35 |
7       |   98          |   2       |   28          |   2014-01-20 16:08:42 |
8       |   98          |   2       |   26.75       |   2014-01-20 16:13:23 |

In this table, I need to select data for first item offers for each user and last offers for each user.

So if I select first item offers for each user (distinct), return data should be like:

bid_id  |   buyer_id    |   item_id |   amount      |   time                |
1       |   97          |   1       |   44.26       |   2014-01-20 15:53:16 |
2       |   98          |   2       |   30.47       |   2014-01-20 15:54:52 |
3       |   97          |   2       |   40.05       |   2014-01-20 15:57:47 |

If I select last offers for each user, return should be like:

bid_id  |   buyer_id    |   item_id |   amount      |   time                |
5       |   97          |   1       |   39.99       |   2014-01-20 16:01:13 |
6       |   97          |   2       |   24.68       |   2014-01-20 16:05:35 |
8       |   98          |   2       |   26.75       |   2014-01-20 16:13:23 |

Since I have to bring each item for each user, I tried to GROUP BY for both buyer_id and item_id, then SELECT the MIN value of time or bid_id. But It always returned me first bid_id but latest amount rows (which are last offers actually).

Here's the query I tried:

SELECT MIN(`bid_id`) AS `bid_id`,`buyer_id`,`item_id`,`amount`,`time` FROM `offers` GROUP BY `buyer_id`,`item_id`

And the result was:

bid_id  |   buyer_id    |   item_id |   amount      |   time                |
1       |   97          |   1       |   39.99       |   2014-01-20 16:01:13 |
2       |   97          |   2       |   24.68       |   2014-01-20 16:05:35 |
3       |   98          |   2       |   26.75       |   2014-01-20 16:13:23 |

As you can see, it groups by and the IDs are correct but the rest of the row values are not.

How can I correctly SELECT first and/or last rows when grouping buy multiple columns?

kubilay
  • 5,047
  • 7
  • 48
  • 66

4 Answers4

1
SELECT o.`bid_id`,o.`buyer_id`,o.`item_id`,o.`amount`,o.`time` FROM `offers` o
JOIN
(SELECT MIN(`bid_id`) AS `bid_id`,`buyer_id`,`item_id`,`amount`,`time` FROM `offers` GROUP BY `buyer_id`,`item_id`)x
ON x.bid_id=o.bid_id  AND x.buyer_id=o.buyer_id
Mihai
  • 26,325
  • 7
  • 66
  • 81
1

Here's another take, using Quassnoi's ranking trick here

For the first bids:

SELECT x.bid_id, x.buyer_id, x.item_id, x.amount, x.time 
FROM 
(
  SELECT o.bid_id, o.buyer_id, o.item_id, o.amount, o.time, 
    @combo :=CASE WHEN NOT(@curItem = o.item_id AND @curBuyer = o.buyer_id) 
                  THEN 1 ELSE @combo+1 END AS Rank,
    @curItem:=o.item_id AS item,
    @curBuyer:=o.buyer_id AS buyer
  FROM
  (
    SELECT o.bid_id, o.buyer_id, o.item_id, o.amount, o.time 
      FROM offers o
      ORDER BY o.buyer_id, o.item_id, o.bid_id
  ) o,
  (SELECT @curItem := -1) itm,
  (SELECT @curBuyer:= -1) buy
) x
WHERE x.Rank = 1;

For the last bids query, you just need to change the ORDER BY to o.buyer_id, o.item_id, o.bid_id DESC

SqlFiddle here

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
0

first offers sql:

SELECT
*
FROM
    offers AS o1
WHERE
NOT EXISTS (
    SELECT
        1
    FROM
        offers o2
    WHERE
        o1.buyer_id = o2.buyer_id
    AND o1.item_id = o2.item_id
    AND datetime(o1.time) > datetime(o2.time)
)

last offers sql : just change to datetime(o1.time) < datetime(o2.time) (i use sqlite~)

HunkD
  • 76
  • 2
-1

Please try below query for the desired output. SQL FIDDLE LINK : http://sqlfiddle.com/#!2/916c2/15

    (select f.bid_id,f.buyer_id,f.item_id,f.amount,f.time from offers f join
    (select buyer_id,item_id,min(time) as time from offers
    group by buyer_id,item_id)t
    on f.buyer_id=t.buyer_id and f.item_id=t.item_id
    and f.time=t.time)
    union
    (select f.bid_id,f.buyer_id,f.item_id,f.amount,f.time from offers f join
    (select buyer_id,item_id,max(time) as time from offers
    group by buyer_id,item_id)t
    on f.buyer_id=t.buyer_id and f.item_id=t.item_id
    and f.time=t.time);
shruti
  • 587
  • 4
  • 6