SQL: SyntaxError: order by with row_number() function - sql

I have the following table Employee:
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 150 |
| 2 | 290 |
| 3 | 302 |
+----+--------+
I am using the following code to find the second highest salary:
with t as
(
select
Salary,
row_number() over (order by Salary desc) as salary_ord
from
Employee
)
select Salary
from t
where salary_ord == 2
However, I get an error:
SyntaxError: near 't as (
select Salary, row_number() over (order by Salary desc) as salary_ord'
What did I do wrong here? Thanks!

In SQL, the correct comparison operator is =, not ==. So, this is the ANSI SQL version of your query:
with t as (
select Salary, row_number() over (order by Salary desc) as salary_ord
from Employee
)
select Salary
from t
where salary_ord = 2;
However, your error suggests that your database doesn't support with or window functions.

In SQL Server,
You can do:
select top 1 Salary
from Employee
order by Salary desc
offset 1 row fetch next 1 row only

Related

Row Number by Certain Column in SQL

I have a table that contains customer transactions. It looks like this:
Tha data is sorted by Total Transaction. I want to create a column that contains number by City. For Example, the first row shows City is London so the values is 1, second row becaus it's from London too, the value is also 1. When the Next Row is not London, the value is 2. So it looks like this:
Is there a way to create that row number in SQL Server?
You can try using dense_rank()
select *,dense_rank() over(order by city) as cityNumber
from tablename
order by total_transaction desc
I believe the question is valid and as per my understanding on the requirement , you need a two level of sub query to get to the final result,
Here I have used max as the data first has to be sorted by Total Transaction and then we can use dense_rank to give a row number using the max value and city.
select t.city as "City"
,dense_rank() over (order by max_total_per_city desc,city) as "City Number"
,t.customer as "Customer"
,t.total_transaction as "Total Transaction"
from
(
select *
,max(total_transaction) over (partition by city) as max_total_per_city
from tableName t
) t
order by total_transaction desc
You can get the CityNumbers with ROW_NUMBER() window function:
select City, row_number() over (order by max(TotalTransaction) desc) CityNumber
from tablename
group by City
so you can join the above query to the table:
select t.City, c.CityNumber, t.Customer, t.Totaltransaction
from tablename t inner join (
select City, row_number() over (order by max(TotalTransaction) desc) CityNumber
from tablename
group by City
) c on c.City = t.City
order by t.TotalTransaction desc
Or with DENSE_RANK() window function:
select t.City,
dense_rank() over (order by (select max(TotalTransaction) from tablename where City = t.City) desc) as cityNumber,
t.Customer,
t.TotalTransaction
from tablename t
order by t.TotalTransaction desc
See the demo.
Results:
> City | CityNumber | Customer | Totaltransaction
> :--------- | ---------: | :------- | ---------------:
> London | 1 | Michael | 250
> London | 1 | Edward | 180
> Paris | 2 | Michael | 160
> Madrid | 3 | Luis | 153
> London | 1 | Serena | 146
> Madrid | 3 | Lionel | 133
> Manchester | 4 | Frank | 96

Query to delete last two rows as one row is duplicate in SQL Server

+-------+--------+
| EMPID | SALARY |
+-------+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
| 4 | 400 |
| 4 | 400 |
| 5 | 500 |
+-------+--------+
Help me to find out the query which deletes last two rows. I have already tried using where condition but last three rows are being deleted as (4,400) is a duplicate.
You can set limit for that
DELETE `employee` ORDER BY `EMPID` DESC LIMIT 2
AS you can add your where clause like. WHERE EMPID = '104', EMPID = '105'
Try to use this query:
WITH CTE AS(
SELECT [EMPID], [SALARY],
RN = ROW_NUMBER()OVER(PARTITION BY [EMPID], [SALARY] ORDER BY (SELECT 0))
FROM dbo.myTable
)
DELETE FROM CTE WHERE RN > 1
Try this. If you want to all the duplicate records, this will delete a employee if he has duplicate salary since you said you want to delete two records.
WITH CTE
AS (SELECT *,
cnt= Count(1)OVER(PARTITION BY EMPID
ORDER BY (select null))
FROM yourTable)
DELETE FROM CTE
WHERE cnt > 1
Assuming you want to delete the last 2 rows as stated (one of which is duplicate), this should work.
Query
;WITH D as (
SELECT ROW_NUMBER() OVER(ORDER BY EMPID DESC) as rn,EMPID, SALARY
FROM YourTable
)
DELETE FROM D
WHERE rn <= 2;
SQL Fiddle

plsql append rows together from select statements (similar to rbind)

Say I have a table:
CREATE TABLE Test_Scores
( last_name VARCHAR2(40),
score number(10));
And I want to select the top and bottom scores into a table. The two queries would be:
select last_name,score, 'MAX' as Score_Type from Test_Scores
where score = (select max(score) from Test_Scores)
-> Last_name | Score | Score_Type
Smith | 15 | Max
select last_name,score, 'MIN' as Score_Type from Test_Scores
where score = (select min(score) from Test_Scores)
-> Last_name | Score | Score_Type
Jones | 5 | Min
How do I set these two rows together? In SAS I would use a set statement, and in R I would use rbind. Is there a pl sql equivalent (Oracle 11g)?
The final output would be:
Last_name | Score | Score_Type
Smith | 15 | Max
Jones | 5 | Min
Thanks in advance.
This can be done using plain SQL and a window (aka "analytic") function. There is no need for PL/SQL here (PL/SQL is only used for stored procedures)
select last_name,
score
from (
select last_name,
score,
dense_rank() over (order by score desc) as ranked_first,
dense_rank() over (order by score asc) as ranked_last
from test_scores
)
where ranked_first = 1
or ranked_last = 1;

Get list of unique records

I have the following table which lists the employees and their corresponding managers:
id | employeeid | managerid
1 | 34256 | 12789
2 | 21222 | 34256
3 | 12435 | 34256
.....
.....
What is the recommended way to list out all distinct employees(id) in a single list.
Note that all managers may not be listed under the employeeid column (as he may not have a manager in turn).
If I understand this correctly:
This will unite all distict Employee IDs avoiding duplicates from between the two column (UNION)
SELECT employeeid AS Employee
FROM tableA
UNION
SELECT managerid AS Employee
FROM tableA
This should d it :
SELECT DISTINCT employeeid FROM yourtablename
But seriously, by googling the keyword "distinct" you could have found out very easily yourself ! Or did I miss something out ?
SELECT id, employeeid, managerid
FROM
(SELECT yourtablename.*,
ROW_NUMBER() OVER (PARTITION BY managerid ORDER BY employeeid DESC) AS RN
FROM yourtablename) AS t
WHERE RN = 1
ORDER BY ID

sql query distinct with Row_Number

I am fighting with the distinct keyword in sql.
I just want to display all row numbers of unique (distinct) values in a column & so I tried:
SELECT DISTINCT id, ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM table
WHERE fid = 64
however the below code giving me the distinct values:
SELECT distinct id FROM table WHERE fid = 64
but when tried it with Row_Number.
then it is not working.
This can be done very simple, you were pretty close already
SELECT distinct id, DENSE_RANK() OVER (ORDER BY id) AS RowNum
FROM table
WHERE fid = 64
Use this:
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS RowNum FROM
(SELECT DISTINCT id FROM table WHERE fid = 64) Base
and put the "output" of a query as the "input" of another.
Using CTE:
; WITH Base AS (
SELECT DISTINCT id FROM table WHERE fid = 64
)
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS RowNum FROM Base
The two queries should be equivalent.
Technically you could
SELECT DISTINCT id, ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS RowNum
FROM table
WHERE fid = 64
but if you increase the number of DISTINCT fields, you have to put all these fields in the PARTITION BY, so for example
SELECT DISTINCT id, description,
ROW_NUMBER() OVER (PARTITION BY id, description ORDER BY id) AS RowNum
FROM table
WHERE fid = 64
I even hope you comprehend that you are going against standard naming conventions here, id should probably be a primary key, so unique by definition, so a DISTINCT would be useless on it, unless you coupled the query with some JOINs/UNION ALL...
This article covers an interesting relationship between ROW_NUMBER() and DENSE_RANK() (the RANK() function is not treated specifically). When you need a generated ROW_NUMBER() on a SELECT DISTINCT statement, the ROW_NUMBER() will produce distinct values before they are removed by the DISTINCT keyword. E.g. this query
SELECT DISTINCT
v,
ROW_NUMBER() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number
... might produce this result (DISTINCT has no effect):
+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a | 1 |
| a | 2 |
| a | 3 |
| b | 4 |
| c | 5 |
| c | 6 |
| d | 7 |
| e | 8 |
+---+------------+
Whereas this query:
SELECT DISTINCT
v,
DENSE_RANK() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number
... produces what you probably want in this case:
+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a | 1 |
| b | 2 |
| c | 3 |
| d | 4 |
| e | 5 |
+---+------------+
Note that the ORDER BY clause of the DENSE_RANK() function will need all other columns from the SELECT DISTINCT clause to work properly.
All three functions in comparison
Using PostgreSQL / Sybase / SQL standard syntax (WINDOW clause):
SELECT
v,
ROW_NUMBER() OVER (window) row_number,
RANK() OVER (window) rank,
DENSE_RANK() OVER (window) dense_rank
FROM t
WINDOW window AS (ORDER BY v)
ORDER BY v
... you'll get:
+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a | 1 | 1 | 1 |
| a | 2 | 1 | 1 |
| a | 3 | 1 | 1 |
| b | 4 | 4 | 2 |
| c | 5 | 5 | 3 |
| c | 6 | 5 | 3 |
| d | 7 | 7 | 4 |
| e | 8 | 8 | 5 |
+---+------------+------+------------+
Using DISTINCT causes issues as you add fields and it can also mask problems in your select. Use GROUP BY as an alternative like this:
SELECT id
,ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM table
where fid = 64
group by id
Then you can add other interesting information from your select like this:
,count(*) as thecount
or
,max(description) as description
How about something like
;WITH DistinctVals AS (
SELECT distinct id
FROM table
where fid = 64
)
SELECT id,
ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM DistinctVals
SQL Fiddle DEMO
You could also try
SELECT distinct id, DENSE_RANK() OVER (ORDER BY id) AS RowNum
FROM #mytable
where fid = 64
SQL Fiddle DEMO
Try this:
;WITH CTE AS (
SELECT DISTINCT id FROM table WHERE fid = 64
)
SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM cte
WHERE fid = 64
Try this
SELECT distinct id
FROM (SELECT id, ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM table
WHERE fid = 64) t
Or use RANK() instead of row number and select records DISTINCT rank
SELECT id
FROM (SELECT id, ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS RowNum
FROM table
WHERE fid = 64) t
WHERE t.RowNum=1
This also returns the distinct ids
Question is too old and my answer might not add much but here are my two cents for making query a little useful:
;WITH DistinctRecords AS (
SELECT DISTINCT [col1,col2,col3,..]
FROM tableName
where [my condition]
),
serialize AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY [colNameAsNeeded] ORDER BY [colNameNeeded]) AS Sr,*
FROM DistinctRecords
)
SELECT * FROM serialize
Usefulness of using two cte's lies in the fact that now you can use serialized record much easily in your query and do count(*) etc very easily.
DistinctRecords will select all distinct records and serialize apply serial numbers to distinct records. after wards you can use final serialized result for your purposes without clutter.
Partition By might not be needed in most cases