How can I get row's index from a table in SQL Server? - sql

I have a Toplist table and I want to get a user's rank. How can I get the row's index?
Unfortunately, I am getting all rows and checking in a for loop the user's ID, which has a significant impact on the performance of my application.
How could this performance impact be avoided?

You can use ROW.NUMBER
This is a example syntax for MySQL
SELECT t1.toplistId,
#RankRow := #RankRow+ 1 AS Rank
FROM toplist t1
JOIN (SELECT #RankRow := 0) r;
This is a example syntax for MsSQL
SELECT ROW_NUMBER() OVER(ORDER BY YourColumn) AS Rank,TopListId
FROM TopList

You may also do something like this:
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS MyIndex
FROM TopList

ROW_NUMBER() MS SQL
Use in your code analytic functions

Related

How to get sample data from a table or a view in Aster Teradata without using order by?

I am trying to get sample data from a table in Aster Teradata using order by using the following code:
SELECT "col"
FROM (SELECT "col",
Row_number()
OVER (
ORDER BY 1) AS RANK
FROM "nisha_test"."test_table") a
WHERE rank <= 10000
I want to get random 10000 rows without using order by.
If you want a sample you should use the built-in sample feature.
For Aster (or Vantage MLE, but with a slightly different syntax) there's a RandomSample operator, e.g.
SELECT * FROM RandomSample (
ON (SELECT 1) PARTITION BY 1 -- dummy data, but needed
InputTable ('nisha_test.test_table')
NumSample ('10000')
)
For Teradata there's the SAMPLE clause, e.g.
select *
from nisha_test.test_table
SAMPLE 10000
You can also use the QUALIFY clause in Teradata to remove the outer SELECT:
SELECT col
FROM nisha_test.test_table
QUALIFY ROW_NUMBER() OVER (ORDER BY NULL) <= 10000
In Teradata, I think you can use a constant value in the ORDER BY. You may even be able to exclude the ORDER BY altogether: ROW_NUMBER() OVER()
We can use the LIMIT keyword to get random values from a table or a view in Aster DB.
select * from "nisha_test"."test_table" limit 10000;

How to add serial number over a randomly generated resultset in SQL Server?

I am stuck in a situation where I have to add a 'Serial No.' over a resultset in SQL.
The scenario is like below:
MyTable is like,
Now, after using the following query,
SELECT *
FROM MyTable
ORDER BY CHECKSUM(NEWID())
I am getting output like this,
Now, I want an output like this,
Using ROW_NUMBER() OVER (ORDER BY ID) AS SlNo gives me the serial number just same as my ID, which is not at serially ordered (and this is logically correct too).
Please help me out with some solutions. I am using SQL Server 2008 R2.
Pardon me for my mistakes. Thank you.
In SQL Server, the following will work - it will order by the first column of the result. It still provides a random order.
SELECT ROW_NUMBER() OVER (ORDER BY NEWID()) AS SlNo, *
FROM MyTable ORDER BY 1
You can order by the first column
SELECT CHECKSUM(NEWID()), *
FROM MyTable
ORDER BY 1
Or you can make a subquery so you can order by column name
SELECT * FROM
(
SELECT CHECKSUM(NEWID()) AS SLNo, *
FROM MyTable
) TBL
ORDER BY SLNo

Select every nth row with NHibernate

How would you implement a query that selects every nth row, with NHibernate QueryOver, HQL or Criteria?
Currently I use the following T-SQL query:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY Id) AS [Row]
FROM [TABLE_NAME]
) x WHERE (x.[Row] % 100) = 0
(Thanks to Marc Gravell)
Have you considered the solution of using an indexing table in a cross join? What I mean is that you have a table with as many rows as you think you will need with an indexed column of integers going from 1-n in each row. This can be in a master database perhaps with a date column beside it - its amazing how useful this method is. The query would then look like
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY Id) AS [Row]
FROM [TABLE_NAME]
) x INNER JOIN [Index_Table] i ON i.Id*100=x.[Row]
Same as L2S - there's no easy way to do this without SQL. And the syntax would be DBMS-specific anyway.

How to enumerate returned rows in SQL?

I was wondering if it would be possible to enumerate returned rows. Not according to any column content but just yielding a sequential integer index. E.g.
select ?, count(*) as usercount from users group by age
would return something along the lines:
1 12
2 78
3 4
4 42
it is for https://data.stackexchange.com/
try:
SELECT
ROW_NUMBER() OVER(ORDER BY age) AS RowNumber
,count(*) as usercount
from users
group by age
If it's Oracle, use rownum.
SELECT SOMETABLE.*, ROWNUM RN
FROM SOMETABLE
WHERE SOMETABLE.SOMECOLUMN = :SOMEVALUE
ORDER BY SOMETABLE.SOMEOTHERCOLUMN;
The final answer will entirely depend on what database you're using.
For MySql:
SELECT #row := #row + 1 as row FROM anytable a, (SELECT #row := 0) r
use rownumber function available in sql server
SELECT
ROW_NUMBER() OVER (ORDER BY columnNAME) AS 'RowNumber',count(*) as usercount
FROM users
How you'd do that depends on your database server. In SQL Server, you could use row_number():
select row_number() over (order by age)
, age
, count(*) as usercount
from users
group by
age
order by
age
But it's often easier and faster to use client side row numbers.
for Mysql
set #row:=0;
select #row:=#row+1 as row, a.* from table_name as a;
In contrast to majority of other answers, and in accordance of the actual OP question, to
enumerate returned rows (...) NOT according to any column content
but rather in the order of returned query, one could use a dummy ordinal variable to ORDER BY in an ROW_NUMBER function, e.g.
ROW_NUMBER() OVER(ORDER BY (SELECT 0)) AS row_num
where one could actually use anything as an argument to the SELECT-statement, like SELECT 100, SELECT ‘A’, SELECT NULL, etc..
This way, the row numbers will be enumerated in the same order the data was added to the table.

LIMIT 10..20 in SQL Server

I'm trying to do something like :
SELECT * FROM table LIMIT 10,20
or
SELECT * FROM table LIMIT 10 OFFSET 10
but using SQL Server
The only solution I found looks like overkill:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases
) a WHERE row > 5 and row <= 10
I also found:
SELECT TOP 10 * FROM stuff;
... but it's not what I want to do since I can't specify the starting limit.
Is there another way for me to do that ?
Also, just curious, is there a reason why doesn't SQL Server support the LIMIT function or something similar? I don't want to be mean, but that really sounds like something a DBMS needs ... If it does, then I'm sorry for being so ignorant! I've been working with MySQL and SQL+ for the past 5 years so...
For SQL Server 2012 + you can use.
SELECT *
FROM sys.databases
ORDER BY name
OFFSET 5 ROWS
FETCH NEXT 5 ROWS ONLY
The LIMIT clause is not part of standard SQL. It's supported as a vendor extension to SQL by MySQL, PostgreSQL, and SQLite.
Other brands of database may have similar features (e.g. TOP in Microsoft SQL Server), but these don't always work identically.
It's hard to use TOP in Microsoft SQL Server to mimic the LIMIT clause. There are cases where it just doesn't work.
The solution you showed, using ROW_NUMBER() is available in Microsoft SQL Server 2005 and later. This is the best solution (for now) that works solely as part of the query.
Another solution is to use TOP to fetch the first count + offset rows, and then use the API to seek past the first offset rows.
See also:
"Emulate MySQL LIMIT clause in Microsoft SQL Server 2000"
"Paging of Large Resultsets in ASP.NET"
as you found, this is the preferred sql server method:
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY name) as row FROM sys.databases
) a WHERE a.row > 5 and a.row <= 10
How about this?
SET ROWCOUNT 10
SELECT TOP 20 *
FROM sys.databases
ORDER BY database_id DESC
It gives you the last 10 rows of the first 20 rows. One drawback is that the order is reversed, but, at least it's easy to remember.
If you are using SQL Server 2012+ vote for Martin Smith's answer and use the OFFSET and FETCH NEXT extensions to ORDER BY,
If you are unfortunate enough to be stuck with an earlier version, you could do something like this,
WITH Rows AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY [dbo].[SomeColumn]) [Row]
, *
FROM
[dbo].[SomeTable]
)
SELECT TOP 10
*
FROM
Rows
WHERE Row > 10
I believe is functionaly equivalent to
SELECT * FROM SomeTable LIMIT 10 OFFSET 10 ORDER BY SomeColumn
and the best performing way I know of doing it in TSQL, before MS SQL 2012.
If there are very many rows you may get better performance using a temp table instead of a CTE.
Unfortunately, the ROW_NUMBER() is the best you can do. It's actually more correct, because the results of a limit or top clause don't really have meaning without respect to some specific order. But it's still a pain to do.
Update: Sql Server 2012 adds a limit -like feature via OFFSET and FETCH keywords. This is the ansi-standard approach, as opposed to LIMIT, which is a non-standard MySql extension.
SELECT TOP 10 *
FROM TABLE
WHERE IDCOLUMN NOT IN (SELECT TOP 10 IDCOLUMN FROM TABLE)
Should give records 11-20.
Probably not too efficient if incrementing to get further pages, and not sure how it might be affected by ordering.
Might have to specify this in both WHERE statements.
A good way is to create a procedure:
create proc pagination (#startfrom int ,#endto int) as
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (ORDER BY name desc) as row FROM sys.databases
) a WHERE a.row > #startfrom and a.row <= #endto
just like limit 0,2
///////////////
execute pagination 0,4
Just for the record solution that works across most database engines though might not be the most efficient:
Select Top (ReturnCount) *
From (
Select Top (SkipCount + ReturnCount) *
From SourceTable
Order By ReverseSortCondition
) ReverseSorted
Order By SortCondition
Pelase note: the last page would still contain ReturnCount rows no matter what SkipCount is. But that might be a good thing in many cases.
The equivalent of LIMIT is SET ROWCOUNT, but if you want generic pagination it's better to write a query like this:
;WITH Results_CTE AS
(
SELECT
Col1, Col2, ...,
ROW_NUMBER() OVER (ORDER BY SortCol1, SortCol2, ...) AS RowNum
FROM Table
WHERE <whatever>
)
SELECT *
FROM Results_CTE
WHERE RowNum >= #Offset
AND RowNum < #Offset + #Limit
select * from (select id,name,ROW_NUMBER() OVER (ORDER BY id asc) as row
from tableName1) tbl1
where tbl1.row>=10 and tbl1.row<=15
Will print rows from 10 to 15.
So far this format is what is working for me (not the best performance though):
SELECT TOP {desired amount of rows} *
FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY {order columns} asc)__row__ FROM {table})tmp
WHERE __row__ > {offset row count}
A note on the side, paginating over dynamic data can lead to strange/unexpected results.
From the MS SQL Server online documentation (http://technet.microsoft.com/en-us/library/ms186734.aspx
), here is their example that I have tested and works, for retrieving a specific set of rows. ROW_NUMBER requires an OVER, but you can order by whatever you like:
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,
ROW_NUMBER() OVER (ORDER BY OrderDate) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate, RowNumber
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
Use all SQL server:
;with tbl as (SELECT ROW_NUMBER() over(order by(select 1)) as RowIndex,* from table)
select top 10 * from tbl where RowIndex>=10
SELECT * FROM users WHERE Id Between 15 and 25
it will print from 15 to 25 as like limit in MYSQl