Listing 15.13 is a variation of Listing 15.12 that finds all regions of length 2. See Figure 15.13 for the result. Note that over- lapping subregions are listed. To return regions of length n, change the WHERE clause’s second condition to: AND t2.id - t1.id = n - 1 420 Chapter 15 Finding Sequences, Runs, and Regions Listing 15.13 List all regions of length 2. See Figure 15.13 for the result. SELECT t1.id AS StartReg, t2.id AS EndReg, t2.id - t1.id + 1 AS RegLen FROM temps t1, temps t2 WHERE (t1.id < t2.id) AND t2.id - t1.id = 1 AND NOT EXISTS( SELECT * FROM temps t3 WHERE (t3.hi_temp <> 50 AND t3.id BETWEEN t1.id AND t2.id) ); Listing StartReg EndReg RegLen 4 5 2 5 6 2 10 11 2 Figure 15.13 Result of Listing 15.13. Limiting the Number of Rows Returned In practice it’s common to use queries that return a certain number (n) of rows that fall at the top or the bottom of a range specified by an ORDER BY clause. SQL doesn’t require an ORDER BY clause, but if you omit it, the query will return an arbitrary set of rows (because SQL doesn’t promise to deliver query results in any particular order without an ORDER BY clause). The examples in this section use the table empsales (Listing 15.14 and Figure 15.14), which lists sales figures by employee. Note that some employees have the same sales amounts. A correct query for the top three salespeople in empsales actually will return four rows: employees E09, E02, E10, and E05. Ties shouldn’t force the query to choose arbitrarily between equal values (E10 and E05 in this case). No standard terminology exists, but queries that return at most n rows (regardless of ties) sometimes are called limit queries. Queries that include ties and return possibly more than n rows are top-n queries or quota queries. The SQL:2003 standard introduced the functions ROW_NUMBER() and RANK() to use in limit and top-n queries. Microsoft SQL Server 2005 and later, Oracle, and DB2 support both functions. Queries that use pre-2003 SQL are complex, unintuitive, and run slowly (see the Tips at the end of this section for an SQL-92 exam- ple). The SQL standard has lagged DBMSs, which for years have offered nonstandard extensions to create these types of queries. Some DBMSs also let you return a percent- age of rows (rather than a fixed n) or return offsets by skipping a specified number of initial rows (returning rows 3–8 instead of 1–5, for example). This section covers the DBMS extensions individually. 421 SQL Tricks Limiting the Number of Rows Returned Listing 15.14 List employees by descending sales. See Figure 15.14 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E10 700 E05 700 E01 600 E04 500 E03 500 E06 500 E08 400 E07 300 Figure 15.14 Result of Listing 15.14. ✔ Tips ■ You also can use these queries to limit the number of rows affected by an UPDATE or DELETE (see Chapter 10). ■ Some of these queries might be illegal in some contexts (such as in subqueries or views); see your DBMS documentation. ■ Some of the following examples are based on the ideas in Troels Arvin’s “Comparison of Different SQL Implementations” ( http://troels.arvin.dk/db/rdbms ). Microsoft Access Listing 15.15 lists the top three salespeo- ple, including ties. See Figure 15.15 for the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.16 lists the bottom 40 percent of salespeople, including ties. See Figure 15.16 for the result. This query orders lowest to highest; to reverse the order, change ASC to DESC in the ORDER BY clause. The TOP clause always includes ties. Its syntax is: TOP n [PERCENT] ✔ Tip ■ The following offset query returns n rows but excludes the topmost skip rows from the result. This query orders highest to lowest; to reverse the order, change ASC to DESC and DESC to ASC in each ORDER BY clause. SELECT * FROM ( SELECT TOP n * FROM ( SELECT TOP n + skip * FROM table ORDER BY sort_col DESC) ORDER BY sort_col ASC) ORDER BY sort_col DESC; 422 Chapter 15 Limiting the Number of Rows Returned Listing 15.15 List the top three salespeople, with ties. See Figure 15.15 for the result. SELECT TOP 3 emp_id, sales FROM empsales ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E10 700 E05 700 Figure 15.15 Result of Listing 15.15. Listing 15.16 List the bottom 40 percent of salespeople, with ties. See Figure 15.16 for the result. SELECT TOP 40 PERCENT emp_id, sales FROM empsales ORDER BY sales ASC; Listing emp_id sales E07 300 E08 400 E06 500 E04 500 E03 500 Figure 15.16 Result of Listing 15.16. Microsoft SQL Server Listing 15.17 lists the top three salespeo- ple, not including ties. See Figure 15.17 for the result. Note that this query is inconsis- tent when ties exist; rerunning it can return either E10 or E05, depending on how ORDER BY sorts the table. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.18 lists the top three salespeo- ple, including ties. See Figure 15.18 for the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. 423 SQL Tricks Limiting the Number of Rows Returned Listing 15.17 List the top three salespeople, without ties. See Figure 15.17 for the result. SELECT TOP 3 emp_id, sales FROM empsales ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E05 700 Figure 15.17 Result of Listing 15.17. Listing 15.18 List the top three salespeople, with ties. See Figure 15.18 for the result. SELECT TOP 3 WITH TIES emp_id, sales FROM empsales ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E05 700 E10 700 Figure 15.18 Result of Listing 15.18. Listing 15.19 lists the bottom 40 percent of salespeople, including ties. See Figure 15.19 for the result. This query orders lowest to highest; to reverse the order, change ASC to DESC in the ORDER BY clause. The TOP clause’s syntax is: TOP n [PERCENT] [WITH TIES] ✔ Tips ■ The statement SET ROWCOUNT n provides an alternative method returning n rows. ■ To retrieve a specific subset of ordered rows, you can use a cursor (not covered in this book). The following offset query returns n rows but excludes the topmost skip rows from the result. This query orders highest to lowest; to reverse the order, change ASC to DESC and DESC to ASC in each ORDER BY clause. SELECT * FROM ( SELECT TOP n * FROM ( SELECT TOP n + skip * FROM table ORDER BY sort_col DESC) AS any_name1 ORDER BY sort_col ASC) AS any_name2 ORDER BY sort_col DESC; 424 Chapter 15 Limiting the Number of Rows Returned Listing 15.19 List the bottom 40 percent of sales- people, with ties. See Figure 15.19 for the result. SELECT TOP 40 PERCENT WITH TIES emp_id, sales FROM empsales ORDER BY sales ASC; Listing emp_id sales E07 300 E08 400 E06 500 E03 500 E04 500 Figure 15.19 Result of Listing 15.19. Oracle Use the built-in ROWNUM pseudocolumn to limit the number or rows returned. The first row selected has a ROWNUM of 1, the second has 2, and so on. Use the window function RANK() to include ties. Listing 15.20 lists the top three salespeo- ple, not including ties. See Figure 15.20 for the result. Note that this query is inconsis- tent when ties exist; re-running it can return either E10 or E05, depending on how ORDER BY sorts the table. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.21 lists the top three salespeo- ple, including ties. See Figure 15.21 for the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. ✔ Tips ■ The function ROW_NUMBER() provides an alternative method of assigning unique numbers to rows. ■ To retrieve a specific subset of ordered rows, you can use a cursor (not covered in this book). The following offset query returns n rows but excludes the topmost skip rows from the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY sort_col DESC) AS rnum, columns FROM table) WHERE rnum > skip AND rnum <= (n + skip); 425 SQL Tricks Limiting the Number of Rows Returned Listing 15.20 List the top three salespeople, without ties. See Figure 15.20 for the result. SELECT emp_id, sales FROM ( SELECT * FROM empsales ORDER BY sales DESC) WHERE ROWNUM <= 3; Listing emp_id sales E09 900 E02 800 E05 700 Figure 15.20 Result of Listing 15.20. Listing 15.21 List the top three salespeople, with ties. See Figure 15.21 for the result. SELECT emp_id, sales FROM ( SELECT RANK() OVER (ORDER BY sales DESC) AS sales_rank, emp_id, sales FROM empsales) WHERE sales_rank <= 3; Listing emp_id sales E09 900 E02 800 E05 700 E10 700 Figure 15.21 Result of Listing 15.21. IBM DB2 Listing 15.22 lists the top three salespeo- ple, not including ties. See Figure 15.22 for the result. Note that this query is inconsis- tent when ties exist; re-running it can return either E10 or E05, depending on how ORDER BY sorts the table. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.23 lists the top three salespeo- ple, including ties. See Figure 15.23 for the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. The FETCH clause’s syntax is: FETCH FIRST n ROW[S] ONLY ✔ Tip ■ To retrieve a specific subset of ordered rows, you can use a cursor (not covered in this book). The following offset query returns n rows but excludes the topmost skip rows from the result. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. SELECT * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY sort_col DESC) AS rnum, columns FROM table) AS any_name WHERE rnum > skip AND rnum <= n + skip; 426 Chapter 15 Limiting the Number of Rows Returned Listing 15.22 List the top three salespeople, without ties. See Figure 15.22 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC FETCH FIRST 3 ROWS ONLY; Listing emp_id sales E09 900 E02 800 E05 700 Figure 15.22 Result of Listing 15.22. Listing 15.23 List the top three salespeople, with ties. See Figure 15.23 for the result. SELECT emp_id, sales FROM ( SELECT RANK() OVER (ORDER BY sales DESC) AS sales_rank, emp_id, sales FROM empsales) AS any_name WHERE sales_rank <= 3; Listing emp_id sales E09 900 E02 800 E05 700 E10 700 Figure 15.23 Result of Listing 15.23. MySQL Listing 15.24 lists the top three salespeo- ple, not including ties. See Figure 15.24 for the result. Note that this query is inconsis- tent when ties exist; re-running it can return either E10 or E05, depending on how ORDER BY sorts the table. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.25 lists the top three salespeople, including ties. The OFFSET value is n – 1 = 2. COALESCE() ’s second argument lets the query work in case the table has fewer than n rows; see “Checking for Nulls with COALESCE() ” in Chapter 5. See Figure 15.25 for the result. This query orders highest to lowest; to reverse the order, change >= to <= in the comparison, change MIN() to MAX() in the second subquery, and change DESC to ASC in each ORDER BY clause. 427 SQL Tricks Limiting the Number of Rows Returned Listing 15.24 List the top three salespeople, without ties. See Figure 15.24 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC LIMIT 3; Listing emp_id sales E09 900 E02 800 E10 700 Figure 15.24 Result of Listing 15.24. Listing 15.25 List the top three salespeople, with ties. See Figure 15.25 for the result. SELECT emp_id, sales FROM empsales WHERE sales >= COALESCE( (SELECT sales FROM empsales ORDER BY sales DESC LIMIT 1 OFFSET 2), (SELECT MIN(sales) FROM empsales)) ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E05 700 E10 700 Figure 15.25 Result of Listing 15.25. Listing 15.26 lists the top three sales- people, skipping the initial four rows. See Figure 15.26 for the result. Note that this query is inconsistent when ties exist. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. The LIMIT clause’s syntax is: LIMIT n [OFFSET skip] or LIMIT [skip,] n The offset of the initial row is 0 (not 1). PostgreSQL Listing 15.27 lists the top three salespeo- ple, not including ties. See Figure 15.27 for the result. Note that this query is inconsis- tent when ties exist; re-running it can return either E10 or E05, depending on how ORDER BY sorts the table. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. Listing 15.28 lists the top three salespeople, including ties. The OFFSET value is n – 1 = 2. See Figure 15.28 for the result. This query orders highest to lowest; to reverse the order, change >= to <= in the comparison and change DESC to ASC in each ORDER BY clause. Listing 15.29 lists the top three sales- people, skipping the initial four rows. See Figure 15.29 for the result. Note that this query is inconsistent when ties exist. This query orders highest to lowest; to reverse the order, change DESC to ASC in the ORDER BY clause. The LIMIT clause’s syntax is: LIMIT n [OFFSET skip] The offset of the initial row is 0 (not 1). 428 Chapter 15 Limiting the Number of Rows Returned Listing 15.26 List the top three salespeople, skipping the initial four rows. See Figure 15.26 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC LIMIT 3 OFFSET 4; Listing emp_id sales E01 600 E04 500 E03 500 Figure 15.26 Result of Listing 15.26. Listing 15.27 List the top three salespeople, without ties. See Figure 15.27 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC LIMIT 3; Listing emp_id sales E09 900 E02 800 E05 700 Figure 15.27 Result of Listing 15.27. ✔ Tips ■ When using a inconsistent query to pre- sent results to end-users, it’s a good practice to include a tie-breaking ORDER BY column so users see ties ranked consistently across queries. Adding emp_id after sales in the (outermost) ORDER BY clause in the queries in this section, for example, guar- antees that employees with the same sales value always will sort the same way. ■ Fabian Pascal’s Practical Issues in Database Management (Addison-Wesley) discusses quota queries. His SQL-92 solution (which is too slow for practical use) to list the top three salespeople, including ties, is: SELECT emp_id, sales FROM empsales e1 WHERE ( SELECT COUNT(*) FROM empsales e2 WHERE e2.sales > e1.sales ) < 3; This query orders highest to lowest; to reverse the order, change > to < in the innermost WHERE clause. 429 SQL Tricks Limiting the Number of Rows Returned Listing 15.28 List the top three salespeople, with ties. See Figure 15.28 for the result. SELECT emp_id, sales FROM empsales WHERE ( sales >= ( SELECT sales FROM empsales ORDER BY sales DESC LIMIT 1 OFFSET 2) ) IS NOT FALSE ORDER BY sales DESC; Listing emp_id sales E09 900 E02 800 E10 700 E05 700 Figure 15.28 Result of Listing 15.28. Listing 15.29 List the top three salespeople, skipping the initial four rows. See Figure 15.29 for the result. SELECT emp_id, sales FROM empsales ORDER BY sales DESC LIMIT 3 OFFSET 4; Listing emp_id sales E01 600 E06 500 E03 500 Figure 15.29 Result of Listing 15.29. . functions. Queries that use pre-2003 SQL are complex, unintuitive, and run slowly (see the Tips at the end of this section for an SQL- 92 exam- ple). The SQL standard has lagged DBMSs, which for. are top-n queries or quota queries. The SQL: 2003 standard introduced the functions ROW_NUMBER() and RANK() to use in limit and top-n queries. Microsoft SQL Server 2005 and later, Oracle, and. range specified by an ORDER BY clause. SQL doesn’t require an ORDER BY clause, but if you omit it, the query will return an arbitrary set of rows (because SQL doesn’t promise to deliver query results