Hack 72. Extract a Subset of the Results

You have an ordered table, and you want to see only the first 10, 100, or 1,000 results. Here's how to get the chunks you want.

Suppose you have a high-score table to display. The table itself has thousands of entries, but you want only the first 10. For testing purposes you have the following:

CREATE TABLE highscore (username VARCHAR(20),score INT);
INSERT INTO highscore VALUES ('gordon',10);
INSERT INTO highscore VALUES ('user01',20);
...
INSERT INTO highscore VALUES ('user11',120);

To get the top 10, you might write the following PHP:

9) {break;}
 print "Position ".$i.", ".$line{username}.", ".$line{score}."
";
}
?>

The example output would be:

[gordon@db book]$ php -q ./do.php
Position 1, user11, 120
Position 2, user10, 110
Position 3, user09, 100
Position 4, user08, 90
Position 5, user07, 80
Position 6, user06, 70
Position 7, user05, 60
Position 8, user04, 50
Position 9, user03, 40
Position 10, user02, 30

Although this works, you should be worried about caching and unnecessary data processing. The database system may be churning through thousands of records, getting ready to pass all the result rows to your program (it has no way of knowing that the application will stop requesting data after 10 rows). Your database drivers may be caching thousands of records, ready for you to ask for the next row. If you want only 10 records, all this memory and CPU effort are going to waste.

You can sometimes let the query optimizer know you want initial rows quickly. In Oracle, you can change the optimizer behavior for the duration of your opened database connection handle using ALTER SESSION:

ALTER SESSION SET optimizer_goal=first_rows_10

Per-query changes may also be possible. For instance, in Oracle you can introduce optimizer hints using special comments:

SELECT /*+ first_rows(10) */ username,score
 FROM highscore
 ORDER BY score DESC

In SQL Server, you can use the hint OPTION(FAST 10) to instruct the optimizer to return the first 10 rows as fast as possible, even if this impacts the time taken to return the whole result set:

SELECT username,score
 FROM highscore
 ORDER BY score DESC
 OPTION (FAST 10)

Neither of these changes stops the query from returning more than 10 rows. They only ask the database system to try to get the first 10 rows worked out quickly. So, you also need to specify that the SQL should filter out all but the first 10 rows.

Oracle numbers each row for you automatically in a query. The number of the row is called rownum:

SELECT username,score FROM
(SELECT username,score FROM highscore ORDER BY score DESC) t
 WHERE rownum <= 10

SQL Server and Access allow the TOP keyword:

SELECT TOP 10 username,score FROM highscore ORDER BY score DESC

MySQL and PostgreSQL use the LIMIT instruction:

SELECT username,score FROM highscore ORDER BY score DESC LIMIT 10

 

9.9.1. Hacking the Hack

If you were querying lots of rows, but wanted to query them out of the database only 10 rows at a time, you could use the preceding techniques to get the first 10 rows. But how would you get the next 10 rows?

Oracle needs no special syntax to support this type of query, as you can do it with rownum. Unfortunately, rownum is calculated before ORDER BY, and the more obvious WHERE rownum >10 AND rownum <=20 never returns any rows. You can still use rownum, but you need three SELECT statements:

SELECT username,score FROM
 (SELECT rownum rnum,username,score FROM
 (SELECT username,score FROM highscore ORDER BY score DESC) 
 )
WHERE rnum >10 and rnum <=20

Both MySQL and PostgreSQL support the OFFSET instruction:

SELECT username,score FROM highscore 
ORDER BY score 
DESC LIMIT 10 OFFSET 10

SQL Server does not support OFFSET. It is possible to emulate this in a number of different ways. For instance:

SELECT TOP 10 username,score
FROM highscore
WHERE username not in
 (SELECT TOP 10 username
 FROM highscore
 ORDER BY score DESC)
ORDER BY score DESC


SQL Fundamentals

Joins, Unions, and Views

Text Handling

Date Handling

Number Crunching

Online Applications

Organizing Data

Storing Small Amounts of Data

Locking and Performance

Reporting

Users and Administration

Wider Access

Index



SQL Hacks
SQL Hacks
ISBN: 0596527993
EAN: 2147483647
Year: 2004
Pages: 147

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net