Problems finding the MAX value

2005-11-04 Thread KEVIN ZEMBOWER
My organization runs an online auction on our intranet server for the United 
Way. I'm having a hard time printing out a list of the winning bidders (I'm 
under a lot of pressure; the baked goods are getting stale).

In these examples, I've just printed out my bidder's first names, to protect 
their privacy.

This output seems correct. I could just manually scan this for the maximum 
value for each item:
mysql SELECT CONCAT(a.title,  (, LEFT(b.auction,4), )) AS FullTitle, 
SUBSTRING_INDEX(u.name,  , 1) AS fname, b.bid FROM PHPAUCTION_bids AS b, 
PHPAUCTION_users AS u, PHPAUCTION_auctions AS a WHERE b.bidder=u.id AND 
b.auction=a.id ORDER BY FullTitle LIMIT 35;
+--+---+-+
| FullTitle| fname 
| bid |
+--+---+-+
| 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | Lisa  
|  2. |
| 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | Saori 
|  3. |
| 2 dozen chocolate chip cookies (30c1)| Anne  
|  5. |
| 2 dozen chocolate chip cookies (30c1)| ucantoutbidme 
|  6. |
| 2 dozen chocolate chip cookies (30c1)| Anne  
| 10. |
| 2 dozen chocolate chip cookies (30c1)| ucantoutbidme 
| 11. |
| 2 dozen chocolate chip cookies (a3aa)| Donna 
|  3. |
| 2 dozen chocolate chip cookies (a3aa)| Linda 
|  4. |
| 2 dozen chocolate chip cookies (a3aa)| Donna 
|  5. |
| 2 dozen chocolate chip cookies (a3aa)| ucantoutbidme 
|  6. |
| 2 dozen chocolate chip cookies (a3aa)| Donna 
|  7. |
| 2 dozen chocolate chip cookies (d8e5)| Cheryl
|  2. |
| 2 dozen chocolate chip cookies (d8e5)| ucantoutbidme 
|  3. |
| 2 dozen chocolate chip cookies (d8e5)| Cheryl
|  5. |
| 2 dozen chocolate chip cookies (d8e5)| ucantoutbidme 
|  6. |
| 2 dozen chocolate chip cookies (d8e5)| Donna 
|  8. |
| 2 Gold Rings (d9c1)  | Mandy 
|  2. |
| 2 Gold Rings (d9c1)  | Isabelle  
|  3. |
| 2 Gold Rings (d9c1)  | Hugh  
|  4. |
| 2 Gold Rings (d9c1)  | Isabelle  
|  5. |
| 2 Gold Rings (d9c1)  | Hugh  
|  6. |
| 2 Gold Rings (d9c1)  | Roslyn
|  7. |
| 2 Gold Rings (d9c1)  | Hugh  
|  8. |
| 2 Gold Rings (d9c1)  | Roslyn
| 10. |
| 2 Gold Rings (d9c1)  | Hugh  
| 12. |
| 2 Gold Rings (d9c1)  | Roslyn
| 15. |
| 2 Gold Rings (d9c1)  | Hugh  
| 16. |
| 2 Gold Rings (d9c1)  | Linda 
| 20. |
| 2 Gold Rings (d9c1)  | Hugh  
| 21. |
| 2 Gold Rings (d9c1)  | t 
| 22. |
| 2 Gold Rings (d9c1)  | Hugh  
| 23. |
| 2 Gold Rings (d9c1)  | Linda 
| 25. |
| 2 Gold Rings (d9c1)  | t 
| 26. |
| 2 piece outfit (purple and white) (d60d) | Mandy 
|  1. |
| 2 piece outfit (purple and white) (d60d) | Susan 
|  3. |
+--+---+-+
35 rows in set (0.06 sec)

mysql 

Note that there were actually three different batches of 2 dozen chocolate 
chip cookies. I printed the internal ID numbers to distinguish them.

However, when I try to get fancy and print out just the winners, the winning 
amount comes out, but with the name of the FIRST, not the winning, bidder:
mysql SELECT CONCAT(a.title,  (, LEFT(b.auction,6), )) as FullTitle, 
SUBSTRING_INDEX(u.name,  , 1) AS fname, MAX(b.bid) FROM PHPAUCTION_bids AS b, 
PHPAUCTION_users AS u, PHPAUCTION_auctions AS a WHERE b.bidder=u.id AND 
b.auction=a.id GROUP BY FullTitle ORDER BY FullTitle LIMIT 5;
++++
| FullTitle 

Re: Problems finding the MAX value

2005-11-04 Thread SGreen
KEVIN ZEMBOWER [EMAIL PROTECTED] wrote on 11/04/2005 11:05:05 AM:

 My organization runs an online auction on our intranet server for 
 the United Way. I'm having a hard time printing out a list of the 
 winning bidders (I'm under a lot of pressure; the baked goods are 
 getting stale).
 
 In these examples, I've just printed out my bidder's first names, to
 protect their privacy.
 
 This output seems correct. I could just manually scan this for the 
 maximum value for each item:
 mysql SELECT CONCAT(a.title,  (, LEFT(b.auction,4), )) AS 
 FullTitle, SUBSTRING_INDEX(u.name,  , 1) AS fname, b.bid FROM 
 PHPAUCTION_bids AS b, PHPAUCTION_users AS u, PHPAUCTION_auctions AS 
 a WHERE b.bidder=u.id AND b.auction=a.id ORDER BY FullTitle LIMIT 35;
 +--
 +---+-+
 | FullTitle| 
 fname | bid |
 +--
 +---+-+
 | 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | 
 Lisa  |  2. |
 | 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | 
 Saori |  3. |
 | 2 dozen chocolate chip cookies (30c1)| 
 Anne  |  5. |
 | 2 dozen chocolate chip cookies (30c1)| 
 ucantoutbidme |  6. |
 | 2 dozen chocolate chip cookies (30c1)| 
 Anne  | 10. |
 | 2 dozen chocolate chip cookies (30c1)| 
 ucantoutbidme | 11. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 Donna |  3. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 Linda |  4. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 Donna |  5. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 ucantoutbidme |  6. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 Donna |  7. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 Cheryl|  2. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 ucantoutbidme |  3. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 Cheryl|  5. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 ucantoutbidme |  6. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 Donna |  8. |
 | 2 Gold Rings (d9c1)  | 
 Mandy |  2. |
 | 2 Gold Rings (d9c1)  | 
 Isabelle  |  3. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  |  4. |
 | 2 Gold Rings (d9c1)  | 
 Isabelle  |  5. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  |  6. |
 | 2 Gold Rings (d9c1)  | 
 Roslyn|  7. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  |  8. |
 | 2 Gold Rings (d9c1)  | 
 Roslyn| 10. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  | 12. |
 | 2 Gold Rings (d9c1)  | 
 Roslyn| 15. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  | 16. |
 | 2 Gold Rings (d9c1)  | 
 Linda | 20. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  | 21. |
 | 2 Gold Rings (d9c1)  | t 
 | 22. |
 | 2 Gold Rings (d9c1)  | 
 Hugh  | 23. |
 | 2 Gold Rings (d9c1)  | 
 Linda | 25. |
 | 2 Gold Rings (d9c1)  | t 
 | 26. |
 | 2 piece outfit (purple and white) (d60d) | 
 Mandy |  1. |
 | 2 piece outfit (purple and white) (d60d) | 
 Susan |  3. |
 +--
 +---+-+
 35 rows in set (0.06 sec)
 
 mysql 
 
 Note that there were actually three different batches of 2 dozen 
 chocolate chip cookies. I printed the internal ID numbers to 
 distinguish them.
 
 However, when I try to get fancy and print out just the winners, the
 winning amount comes out, but with the name of the FIRST, not the 
 winning, bidder:
 mysql SELECT CONCAT(a.title,  (, LEFT(b.auction,6), )) as 
 FullTitle, SUBSTRING_INDEX(u.name,  , 1) AS fname, MAX(b.bid) FROM
 PHPAUCTION_bids AS b, PHPAUCTION_users AS u, PHPAUCTION_auctions AS 
 a WHERE b.bidder=u.id AND b.auction=a.id GROUP BY FullTitle 

Re: Problems finding the MAX value

2005-11-04 Thread SGreen
[EMAIL PROTECTED] wrote on 11/04/2005 11:22:35 AM:


 This is such a FAQ that they put the answer in the manual: 
 http://dev.mysql.com/doc/refman/5.0/en/index.html
 

OOPS! I copied the wrong link. It should have been:
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html

Sorry all! 
Shawn Green
Database Administrator
Unimin Corporation - Spruce Pine

Re: Problems finding the MAX value

2005-11-04 Thread KEVIN ZEMBOWER
Man, you're awesome. Only two typos in the whole procedure. However, for the 
life of me, I'm puzzled over how it works. If you have more patience can you 
explain?

Correct query (table is singular, not PHPAUCTIONS_...):
CREATE TEMPORARY TABLE tmpWinners SELECT auction, max(bid) as winningbid 
FROM PHPAUCTION_bids GROUP BY auction;

The temporary table tmpWinners doesn't even contain a field for the ID of the 
winning bidder. This is the first puzzling point and significant diference 
between our two solutions.

Correct query (changed line 8 from AND b.bit...):
SELECT
CONCAT(a.title,  (, LEFT(b.auction,4), )) AS FullTitle
, SUBSTRING_INDEX(u.name,  , 1) AS fname
, b.bid
FROMtmpWinners AS w
INNER JOIN PHPAUCTION_bids AS b
ON b.auction = w.auction
AND b.bid = w.winningbid
INNER JOIN PHPAUCTION_users AS u
ON b.bidder=u.id
INNER JOIN PHPAUCTION_auctions AS a
ON b.auction=a.id
ORDER BY FullTitle
LIMIT 5;

- \g
+--+---+-+
| FullTitle| fname 
| bid |
+--+---+-+
| 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | Saori 
|  3. |
| 2 dozen chocolate chip cookies (30c1)| ucantoutbidme 
| 11. |
| 2 dozen chocolate chip cookies (a3aa)| Donna 
|  7. |
| 2 dozen chocolate chip cookies (d8e5)| Donna 
|  8. |
| 2 Gold Rings (d9c1)  | t 
| 26. |
+--+---+-+
5 rows in set (0.15 sec)

mysql 

So, the SELECT query goes through the tmpWinniing table and, for each record, 
finds a record in the bids table that has the same item ID and same bid price. 
It then uses the bidder's ID it found to look up the bidder's name, and the 
auction item's ID to look up the item's title.

It seems to me that the significant difference between our solutions is your 
use of two conditional clauses in the INNER JOIN between tmpWinner and 
PHPAUCTION_bids. I don't think I've ever seen a join done on more than one 
field between two tables before. Would this query still work if more than one 
person bid the same amount on the same item? The business rules built into 
phpAuction prevent this, but in a more generic situation, would this query 
still work correctly? I guess one anwer to this is 'yes,' because the MAX() 
function returns the first of two equal maximum values it finds, doesn't it?

Despite my puzzlement at how you were able to come up with such a great 
solution, I'm very grateful for your help and explanations. If you're ever in 
Baltimore, MD, I owe you a beer. Thanks.

-Kevin

 [EMAIL PROTECTED] 11/04/05 11:22AM 

This is such a FAQ that they put the answer in the manual: 
http://dev.mysql.com/doc/refman/5.0/en/index.html 

What you are looking for is the row that contains the maximum bid for each 
itemname. The easiest first step it to actually determine what the highest 
bid for each item actually is then use that information to build the rest 
of what you wanted. 

The most portable and easiest to write solution to this is the two-table 
method ( I think I divined your column names correctly, maybe not...):

# begin example #

CREATE TEMPORARY TABLE tmpWinners SELECT auction, max(bid) as winningbid 
FROM PHPAUCTIONS_bids GROUP BY auction;

SELECT 
CONCAT(a.title,  (, LEFT(b.auction,4), )) AS FullTitle
, SUBSTRING_INDEX(u.name,  , 1) AS fname
, b.bid 
FROMtmpWinners AS w
INNER JOIN PHPAUCTION_bids AS b
ON b.auction = w.auction
AND b.bit = w.winningbid
INNER JOIN PHPAUCTION_users AS u
ON b.bidder=u.id
INNER JOIN PHPAUCTION_auctions AS a 
ON b.auction=a.id
ORDER BY FullTitle 
LIMIT 35;

DROP TEMPORARY TABLE tmpWinners;

# end example #

Does that make sense? You should be able to expand on that pattern to 
build whatever list you want. I showed the full-chain of how each table 
relates to another but you could have simplified the query above, can you 
see where?


Shawn Green
Database Administrator
Unimin Corporation - Spruce Pine


--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:http://lists.mysql.com/[EMAIL PROTECTED]



Re: Problems finding the MAX value

2005-11-04 Thread SGreen
How it works...

KEVIN ZEMBOWER [EMAIL PROTECTED] wrote on 11/04/2005 12:40:50 PM:

 Man, you're awesome. Only two typos in the whole procedure. However,
 for the life of me, I'm puzzled over how it works. If you have more 
 patience can you explain?
 
 Correct query (table is singular, not PHPAUCTIONS_...):
 CREATE TEMPORARY TABLE tmpWinners SELECT auction, max(bid) as winningbid 

 FROM PHPAUCTION_bids GROUP BY auction;
 
 The temporary table tmpWinners doesn't even contain a field for the 
 ID of the winning bidder. This is the first puzzling point and 
 significant diference between our two solutions.
 

The CREATE TABLE command can make tables out of query results. No need to 
define the columns as they will be auto-typed to fit the results. In this 
case I chose to create a TEMPORARY table instead of a static table.

http://dev.mysql.com/doc/refman/4.1/en/create-table.html


 Correct query (changed line 8 from AND b.bit...):
 SELECT
 CONCAT(a.title,  (, LEFT(b.auction,4), )) AS FullTitle
 , SUBSTRING_INDEX(u.name,  , 1) AS fname
 , b.bid
 FROMtmpWinners AS w
 INNER JOIN PHPAUCTION_bids AS b
 ON b.auction = w.auction
 AND b.bid = w.winningbid
 INNER JOIN PHPAUCTION_users AS u
 ON b.bidder=u.id
 INNER JOIN PHPAUCTION_auctions AS a
 ON b.auction=a.id
 ORDER BY FullTitle
 LIMIT 5;
 
 - \g
 +--
 +---+-+
 | FullTitle| 
 fname | bid |
 +--
 +---+-+
 | 101 Dalmations, Oliver  Company, A Goofy Movie - VHS (d7b4) | 
 Saori |  3. |
 | 2 dozen chocolate chip cookies (30c1)| 
 ucantoutbidme | 11. |
 | 2 dozen chocolate chip cookies (a3aa)| 
 Donna |  7. |
 | 2 dozen chocolate chip cookies (d8e5)| 
 Donna |  8. |
 | 2 Gold Rings (d9c1)  | t 
 | 26. |
 +--
 +---+-+
 5 rows in set (0.15 sec)
 
 mysql 
 
 So, the SELECT query goes through the tmpWinniing table and, for 
 each record, finds a record in the bids table that has the same item
 ID and same bid price. It then uses the bidder's ID it found to look
 up the bidder's name, and the auction item's ID to look up the item's 
title.

exactly.

 
 It seems to me that the significant difference between our solutions
 is your use of two conditional clauses in the INNER JOIN between 
 tmpWinner and PHPAUCTION_bids. I don't think I've ever seen a join 
 done on more than one field between two tables before. Would this 
 query still work if more than one person bid the same amount on the 
 same item? The business rules built into phpAuction prevent this, 
 but in a more generic situation, would this query still work 
 correctly? I guess one anwer to this is 'yes,' because the MAX() 
 function returns the first of two equal maximum values it finds, doesn't 
it?

You have surmised correctly. If more than one row matches your maximum 
condition (as determined by the rows in tmpWinners) then all matching rows 
will be returned in the final query.
 
 Despite my puzzlement at how you were able to come up with such a 
 great solution, I'm very grateful for your help and explanations. If
 you're ever in Baltimore, MD, I owe you a beer. Thanks.
 
 -Kevin

SQL is a language that tends towards patterns. Learn the patterns and you 
get better at SQL.  This happens to be a very well-known pattern so I 
can't take any of the credit as it was around long before I started 
programming. I am just glad I could share. Do I still get that beer? ;-)

About multiple terms in the ON phrases of the JOIN clauses... It is 
sometimes to your advantage to move terms out of the WHERE clause and into 
the ON clause (especially when it comes to the LEFT and RIGHT joins). Not 
only can it make the logic of your query correct but sometimes it opens 
the optimizer up to using indexes it may not have considered before. 
Almost any logical statement is permissible in an ON clause. See 
http://dev.mysql.com/doc/refman/5.0/en/join.html for more details on what 
will and won't work based on the order your tables are JOINed into the 
query.

Sorry about the typos. Glad they didn't mess you up :-)

Shawn Green
Database Administrator
Unimin Corporation - Spruce Pine