28

I have two columns the first one I want top 10 products (1-10)

That is

SELECT TOP 10 * FROM Product   

In the second column I want the next 10 results (11-20)

How do I do that?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Nicklas
  • 283
  • 1
  • 3
  • 4
  • 1
    What version of SQL Server please? – Martin Smith Sep 07 '11 at 11:04
  • What platform MySql or SQLServer? – Hogan Sep 07 '11 at 11:06
  • @Nicklas Visit these threads : http://stackoverflow.com/questions/216673/emulate-mysql-limit-clause-in-microsoft-sql-server-2000 http://stackoverflow.com/questions/364292/sql-server-2005-select-top-n-plus-other – KV Prajapati Sep 07 '11 at 11:12
  • 5
    In SQL Server 2011 (codenamed "denali") you'll be able to do `SELECT * FROM Table ORDER BY Something OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY` which is quite awesome :) – Alex Bagnolini Sep 07 '11 at 12:22
  • 1
    @AlexBagnolini Can you put that as the answer as it really is the more correct one now? - and without it being an answer people might miss it in the comments. – monty Sep 09 '16 at 04:47
  • @monty - it might be helpful to people who come across this from search results but it is not an answer to the question here. The question here is about putting rows 1-10 into the first column and rows 11-20 in the second column. Not something `OFFSET ... FETCH` helps with – Martin Smith Jun 08 '20 at 16:55
  • 1
    @MartinSmith True, rereading the questions 5 years later I can see that :) – monty Jun 08 '20 at 22:06

16 Answers16

31
WITH T AS
(
SELECT TOP 20 name, 
       row_number() OVER (ORDER BY id) AS RN
FROM Products
ORDER BY id
)
SELECT 
       MAX(CASE WHEN RN <=10 THEN name END) AS Col1,
       MAX(CASE WHEN RN > 10 THEN name END) AS Col2
FROM T       
GROUP BY RN % 10
Martin Smith
  • 438,706
  • 87
  • 741
  • 845
  • 3
    I must admit how much I enjoy reading Martin's and Marc's solution's. +1 for both – niktrs Sep 07 '11 at 11:51
  • 3
    +1 darn - this is even a lot smarter and less "taxing" on the execution plan than my solution - congrats! – marc_s Sep 07 '11 at 12:03
  • 1
    @marc_s this is what I mean I enjoy reading. Different approaches & solutions make me (at least) think in a better way :) – niktrs Sep 07 '11 at 12:10
  • @niktrs: indeed - I enjoy seeing other (very smart!) guy's solutions, too - helps me get better at my stuff every day! :-) (and Martin here is one of the top SQL gurus around for sure - saved my bacon a couple of times already :-) Thanks Martin!) – marc_s Sep 07 '11 at 12:24
  • Thanks for the ego boosting comments! – Martin Smith Sep 07 '11 at 12:39
14

I would do this:

SELECT [columns] FROM [table names] ORDER BY [column name] DESC LIMIT 10 OFFSET 10;

This is simpler and less complex....

What do you guys think?

George Hilliard
  • 15,402
  • 9
  • 58
  • 96
Nabmeister
  • 755
  • 1
  • 11
  • 20
  • 2
    It does not seem to work on SQL Server, but if you replace LIMIT 10 OFFSET 10 WITH OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY; Then it'll work on SQL Server. – Eugene Apr 17 '20 at 18:44
9
select top 10 wwwhid from wwwh  where wwwhid not in(select top 10 wwwhid from wwwh)
senthilkumar2185
  • 2,536
  • 3
  • 22
  • 36
5

Starting with SQL server 2012 order by offset/fetch feature:

SELECT *
FROM SomeTable
ORDER BY someIdField 
    OFFSET 10 ROWS
    FETCH NEXT 10 ROWS ONLY;
Access Denied
  • 8,723
  • 4
  • 42
  • 72
4

In SQL Server, it's bit tricky to get this done. If you're on SQL Server 2005 or newer, you can use a CTE with a CROSS JOIN and some trickery to get the result you're looking for:

;WITH TopProducts AS
(
    SELECT 
        ProductID, ProductName,
        ROW_NUMBER() OVER(ORDER BY --some-column-here-- DESC) 'RN'
    FROM dbo.Products
)
SELECT 
    p1.ProductID, p1.ProductName,
    p2.ProductID, p2.ProductName
FROM 
    TopProducts p1
CROSS JOIN 
    TopProducts p2
WHERE 
    p1.RN BETWEEN 1 AND 10        -- get rows 1-10 from the first CTE
    -- AND p2.RN BETWEEN 11 AND 20   redundant, as niktrs pointed out
    AND p1.RN + 10 = p2.RN        -- join rows from P1 and P2 so you don't get a cartesian product

The CTE (Common Table Expression) numbers the products - this needs to be based on some column from your Products table, but you didn't mention what column defines the order.

We then select rows 1-10 from the CTE, as well as rows 11-20 from a second instance of the CTE. If you leave this as is, you'll get 100 rows - each combination of rows 1-10 from the first result set against each of the 10 rows from the second result set.

That's why you need an additional condition, based on the row numbers, to "join" one row from each result set, and thus you'll get ten rows - the first column has the items 1-10 from the Products table, the second column has rows 11-20

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 1
    Althought I thought this would perform better than my code, in my test enviroment makes two index scan's instead of Index seek?! Also I think AND p2.RN BETWEEN 11 AND 20 is redudant because of AND p1.RN + 10 = p2.RN – niktrs Sep 07 '11 at 11:36
  • 1
    @niktrs: you're right about the redundancy - one can even write this as an INNER JOIN and put that `p1.RN = p2.RN - 10` as the JOIN condition - works too – marc_s Sep 07 '11 at 12:02
  • @marc_s: Logically this *is* an inner join, I think. Anyway, +1, it does its job right. – Andriy M Sep 07 '11 at 16:45
2
declare @FromRange int
declare @ToRange int
set @FromRange =11
set @ToRange =20
SELECT top(@ToRange-@FromRange+1) * FROM [tbl] 
where tbl_id not in (select top (@FromRange-1) tbl_id from tbl)
ORDER BY tbl_id 
R.Ghanbari
  • 29
  • 1
2

I am not sure this is the best way to do it but it works

select *
from
(
SELECT top 10 ROW_NUMBER() OVER(ORDER BY product) linenum, product
FROM products
) t1
 JOIN 
(
SELECT top 20 ROW_NUMBER() OVER(ORDER BY product) linenum, product
FROM products
) t2 ON t1.linenum+10 = t2.linenum
niktrs
  • 9,858
  • 1
  • 30
  • 30
  • I think this will result in the first 10 rows displayed twice, in both columns, once alone and once together with the other 10. Maybe you meant `INNER JOIN` instead of `FULL JOIN`? Or am I missing something? – Andriy M Sep 07 '11 at 16:47
1
WITH result_set AS 
    (SELECT ROW_NUMBER() OVER 
        (ORDER BY Product.ID DESC) AS 
     [row_number], Product.intId AS id, Product.Title As Title
     FROM Product WHERE Product.Price > 11)
SELECT * FROM result_set WHERE [row_number] BETWEEN 10 AND 19 
1

Use the code:

select top 20 * from [table Name] 
except
select top 10 * from [table Name]
ChrisM
  • 1,576
  • 6
  • 18
  • 29
1
SELECT * FROM Product LIMIT(10,10)
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
tonekk
  • 470
  • 3
  • 16
1

Try this one :

SELECT * 
FROM 
( 
    SELECT TOP 10 ROW_NUMBER() OVER(ORDER BY ColName) RowNo, ColName
    FROM TableName 
) table1 
INNER JOIN  
( 
    SELECT TOP 20 ROW_NUMBER() OVER(ORDER BY ColName) RowNo, ColName 
    FROM TableName 
) table2 ON table1.RowNo + 10 = table2.RowNo 
0
SELECT p.* FROM 
(
 SELECT *, ROW_NUMBER() OVER (ORDER BY /*some column*/) AS row_num
 FROM Product
) AS p
WHERE p.row_num BETWEEN 11 AND 20
gaffcz
  • 3,469
  • 14
  • 68
  • 108
0
select *
from (select *
      from <table>
      order by id asc)
where rownum <= 20

minus
select *
from (select *
      from <table>
      order by id asc)
where rownum <= 10
Breeze
  • 2,010
  • 2
  • 32
  • 43
0

Try this:

SELECT * FROM
  (SELECT ROW_NUMBER() OVER (ORDER BY ColumnName) AS MyRowNumber, *
  FROM TableName) tbl
WHERE MyRowNumber BETWEEN 20 AND 30
Nehal
  • 1,542
  • 4
  • 17
  • 30
Masum
  • 119
  • 11
0

You can perform that by using the following SQL query:

SELECT * FROM [table] LIMIT 10 OFFSET 10

This will select rows from my table, it will give me 10 rows, and will skip the first 10 rows.

toshiro92
  • 1,287
  • 5
  • 28
  • 42
Saad Ahmed
  • 23
  • 3
-1

This my be the most specific:

SELECT Col1, Col2, Col3  FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Id) AS MyRowNumber, * FROM table) tbl
WHERE MyRowNumber BETWEEN 11 AND 20;
Shahid Malik
  • 163
  • 13