How to select a row based on its row number? - sql

I'm working on a small project in which I'll need to select a record from a temporary table based on the actual row number of the record.
How can I select a record based on its row number?

A couple of the other answers touched on the problem, but this might explain. There really isn't an order implied in SQL (set theory). So to refer to the "fifth row" requires you to introduce the concept
Select *
From
(
Select
Row_Number() Over (Order By SomeField) As RowNum
, *
From TheTable
) t2
Where RowNum = 5
In the subquery, a row number is "created" by defining the order you expect. Now the outer query is able to pull the fifth entry out of that ordered set.

Technically SQL Rows do not have "RowNumbers" in their tables. Some implementations (Oracle, I think) provide one of their own, but that's not standard and SQL Server/T-SQL does not. You can add one to the table (sort of) with an IDENTITY column.
Or you can add one (for real) in a query with the ROW_NUMBER() function, but unless you specify your own unique ORDER for the rows, the ROW_NUMBERS will be assigned non-deterministically.

What you're looking for is the row_number() function, as Kaf mentioned in the comments.
Here is an example:
WITH MyCte AS
(
SELECT employee_id,
RowNum = row_number() OVER ( order by employee_id )
FROM V_EMPLOYEE
ORDER BY Employee_ID
)
SELECT employee_id
FROM MyCte
WHERE RowNum > 0

There are 3 ways of doing this.
Suppose u have an employee table with the columns as emp_id, emp_name, salary. You need the top 10 employees who has highest salary.
Using row_number() analytic function
Select * from
( select emp_id,emp_name,row_number() over (order by salary desc) rank
from employee)
where rank<=10
Using rank() analytic function
Select * from
( select emp_id,emp_name,rank() over (order by salary desc) rank
from employee)
where rank<=10
Using rownum
select * from
(select * from employee order by salary desc)
where rownum<=10;

This will give you the rows of the table without being re-ordered by some set of values:
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT '1')) AS RowID, * FROM #table

If using SQL Server 2012 you can now use offset/fetch:
declare #rowIndexToFetch int
set #rowIndexToFetch = 0
select
*
from
dbo.EntityA ea
order by
ea.Id
offset #rowIndexToFetch rows
fetch next 1 rows only

Related

Distinct rows in a table in sql

I have a table with multiple rows of the same member id. I need only distinct rows based on 2 unique columns
Ex: there are 100 different customers, the table has 1000 rows because every customer has multiple cities and segments assigned to him.
I need 100 distinct rows for these customers depending on a unique segment and city combination. There is no specific requirement for this combination, just the first from the table is fine.
So, currently the table is somewhat like this,
Hope this helps.
use row_number()
select * from (select *,row_number() over(partition by memberid order by sales) rn
from table_name
) a where a.rn=1
Handy sql-server top(1) with ties syntax for that
select top(1) with ties t.*
from table_name t
order by row_number() over(partition by memberid order by sales)
As you have no paticular requirement for which exactly row to select, any column will do at order by, it can be null as well
select top(1) with ties t.*
from table_name t
order by row_number() over(partition by memberid order by (select null))
The simplest way to do this is to use the ROW_NUMBER() OVER(GROUP BY...) syntax. You have no need to use an order by, since you want an arbitrary row, but only one, for each member.
Since you need only the expected data, and not the Row_Number value, make sure that you detail the fields returned, like below:
SELECT
MemberId,
city,
segment,
sales
FROM (
SELECT *
ROW_NUMBER() OVER (GROUP BY MemberId) as Seq
FROM [Status]
) src
WHERE Seq = 1

SQL MAX(COUNT(*)) GROUP BY Alternatives?

I've seen many topics about this and none of them is what I'm looking for.
Say we have this simple table:
CREATE TABLE A (
id INT,
date DATETIME
);
I want to retrieve the MAX value after grouping.
So I do it as follow:
DECLARE #tmpTable TABLE(id INT, count INT);
INSERT INTO #tmpTable SELECT id, COUNT(*) FROM A GROUP BY id;
SELECT MAX(count) FROM #tmpTable;
Is there a better way of doing that?
I've seen a solution in a book that I'm reading that they do it as follows:
SELECT MAX(count) FROM (SELECT COUNT(*) AS count FROM A GROUP BY id);
But this won't work :/ Could be that it works in newer T-SQL servers? Currently I'm using 2008 R2.
You can make use of TOP
SELECT TOP 1 Id,COUNT(*) AS MAXCOUNT
FROM A
GROUP BY Id
ORDER BY MAXCOUNT DESC
If you wants the result with same max count use TOP WITH TIES
SELECT TOP 1 WITH TIES Id,COUNT(*) AS MAXCOUNT
FROM A
GROUP BY Id
ORDER BY MAXCOUNT DESC
Is there a better way of doing that?
We could try using analytic functions:
WITH cte AS (
SELECT id, COUNT(*) cnt, ROW_NUMBER() OVER (ORDER BY COUNT(*) DESC) rn
FROM A
GROUP BY id
)
SELECT cnt
FROM cte
WHERE rn = 1;
This approach is to turn out a row number, ordered descending by the count, during your original aggregation query by id. The id with the highest count then should be the first record (and this result should hold valid even if more than one id be tied for the highest count).
Regarding your original max query, see the answer by #apomene, and you are just missing an alias.
You also need to add an alias name for your sub query. Try like:
SELECT MAX(sub.count1) FROM (SELECT COUNT(*) AS count1 FROM A GROUP BY id) sub;

Sql query to fetch 3rd lowest value

I have a table called employee_salary, having two columns(emp_id, emp_salary) in it.
I have a requirement to fetch 3rd lowest emp_salary from this table. In this case, what should be my query so that i can get the exact value.
I have tested this in Postgres Database. I hope this query work in all type of database. please try this.
SELECT
[emp_salary]
FROM [employee_salary]
GROUP BY [emp_salary]
ORDER BY [emp_salary] LIMIT 1 OFFSET 2;
This may be one solution
select top 1 * from
(
select top 3 * from
(
select distinct emp_sal from employee order by asc emp_sal
) d orderby desc emp_sal
)
SELECT TOP 1 * FROM employee_salary WHERE emp_salary in (SELECT TOP 3 emp_salary FROM employee_salary ORDER BY emp_salary) ORDER BY emp_salary DESC
However, this does not work in all DBs. You need to find out alternative. For eg. in Informix, the statement will be SELECT FIRST 1 *
Using windowing functions... this construct is for SQL Server:
;WITH CTE AS
(
SELECT ..., ROW_NUMBER() OVER (ORDER BY emp_salary) AS rn
FROM myTable
)
SELECT ...
FROM CTE
WHERE rn = 3
for identical salaries you can get using RANK () function in SQL Server
;WITH CTE AS
(
SELECT ..., RANK() OVER (ORDER BY emp_salary) AS rn
FROM myTable
)
SELECT ...
FROM CTE
WHERE rn = 3
I got the answer by executing the following query in sql server 2008
Select MIN(emp_salary) from MyTable Where emp_salary in
(Select DISTINCT TOP 3 emp_salary from MyTable order by 1 DESC)
I got the 3rd minimum value.
DISTINCT is used to when one or more salary are same.
select * from table_name where col_name = (select (min(col_name) from table_name where col_name > (select min(col_name) from table_name where col_name > (select min(col_name) from table_name)));
You need 3rd lowest Salary. Let dive deep in the question.
1st requirement is Need Salary , 2nd requirement is need lowest salary and 3rd requirement is 3rd Lowest Salary
SELECT * FROM employee_salary // "It will give us Salary"
ORDER BY emp_salary DESC //"It will show lowest salary on top"
LIMIT 2,1 // As wee need 3rd salary , i am saying LIMIT 2,1 skip first 2 and show 3rd one

Retrieving the second most highest value from a table

How do I retrieve the second highest value from a table?
select max(val) from table where val < (select max(val) form table)
In MySQL you could for instance use LIMIT 1, 1:
SELECT col FROM tbl ORDER BY col DESC LIMIT 1, 1
See the MySQL reference manual: SELECT Syntax).
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15
select top 2 field_name from table_name order by field_name desc limit 1
SELECT E.lastname, E.salary FROM employees E
WHERE 2 = (SELECT COUNT(*) FROM employess E2
WHERE E2.salary > E.salary)
Taken from here
This works in almost all Dbs
Select Top 1 sq.ColumnToSelect
From
(Select Top 2 ColumnToSelect
From MyTable
Order by ColumnToSelect Desc
)sq
Order by sq.ColumnToSelect asc
Cool, this is almost like Code Golf.
Microsoft SQL Server 2005 and higher:
SELECT *
FROM (
SELECT
*,
row_number() OVER (ORDER BY var DESC) AS ranking
FROM table
) AS q
WHERE ranking = 2
Try this
SELECT * FROM
(SELECT empno, deptno, sal,
DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal DESC NULLS LAST) DENSE_RANK
FROM emp)
WHERE DENSE_RANK = 2;
This works in both Oracle and SQL Server.
Try this
SELECT TOP 1 Column FROM Table WHERE Column < (SELECT MAX(Column) FROM Table)
ORDER BY Column DESC
SELECT TOP 1 Column FROM (SELECT TOP <n> Column FROM Table ORDER BY Column DESC)
ORDER BY ASC
change the n to get the value of any position
Maybe:
SELECT * FROM table ORDER BY value DESC LIMIT 1, 1
one solution would be like this:
SELECT var FROM table ORDER BY var DESC LIMIT 1,1

SQL question: how to select arbitrary numbers of records in each record group?

I have a table 'articles' : id / uid / last_update / content.
I want to construct a sql statement that selects an arbitrary number(say 3) of records of each user(identified by uid) that are most recently updated from the table. How can I do that?
In SQL Server and Oracle, you can use ROW_NUMBER() to label records per user. The following query tags rn=1 on the latest row for that user, rn=2 on the second latest, and so on:
select *
from (
select
row_number() over (partition by uid order by UpdateDt desc)
as rn
, *
from YourTable
) sub
where rn <= 3
The subquery is required because you can't use ROW_NUMBER() in a WHERE clause directly.
If you're using MySQL, this problem is much harder. Here's a link to a solution with user variables.
DECLARE #Top tinyint;
SELECT #Top = ABS(CHECKSUM(NEWID())) % 5 + 1;
;WITH MyCTE AS
(
SELECT
stuff, things,
ROW_NUMBER() OVER (PARTITION BY uid ORDER BY UpdatedDateTime DESC) AS Ranking
FROM
MyTable
)
SELECT
stuff, things
FROM
MyCTE
WHERE
Ranking <= #Top