Something like rank() in SQL Server - sql

How can I write a query in SQL Server such as rank() but a bit different calculate.
For example rank is:
rankNumber uniqeId
1 160
2 159
3 158
4 157
5 156
5 156
7 152
8 151
8 151
10 150
I need the result like these:
rankNumber uniqeId
1 160
2 159
3 158
4 157
5 156
5 156
6 152
7 151
7 151
8 150
How can I do this? Is there such a function in SQL Server?

SELECT DENSE_RANK() OVER (ORDER BY TotCnt DESC) AS TopCustomers, CustomerID, TotCnt
FROM (SELECT CustomerID, COUNT(*) AS TotCnt
FROM Orders Group BY CustomerID) AS Cust
OUTPUT

To expand on the DENSE_RANK comment, the full query is short and sweet:
SELECT
DENSE_RANK() OVER (ORDER BY uniqueId DESC) AS rankNumber,
uniqueId
FROM myTable
ORDER BY rankNumber
There's a SQL Fiddle here

Related

Grouping a column in oracle

I have three columns within my table:
Amount, OrderNumber, Customerid
For each customerid there will be ordernumber and amount.
Now i need to display customerid,Ordernumber and Amount(total Amount- for each customerid).
custid srcnumber amount
112 4344 20
112 7678 10
112 8766 30
34 6577 15
34 4566 5
Expected:
custid srcnumber amount
112 4344 60
112 7678 60
112 8766 60
34 6577 20
34 4566 20
Use sum() over (partition by ..) analytic function to sum up the amount per each row :
select Customerid as custid,
OrderNumber as srcnumber,
sum(amount) over ( partition by Customerid ) as amount
from tab
order by custid desc
Demo

Max 3 values of every group

I sorted my data to something like this and now I want to get top 3 max person_occurence by every company but I couldn't figure out how to do it.
person_occurence company person_id
67 company_1 110
66 company_2 176
64 company_3 100
64 company_3 196
63 company_4 127
62 company_1 150
61 company_5 120
60 company_3 140
59 company_5 154
59 company_5 162
59 company_4 194
58 company_4 109
58 company_3 128
58 company_1 156
I used this query to get max of every company but can't get top 3 max person_occurence
SELECT max(agent_occurence), company FROM table GROUP BY company;
Use window functions:
select t.*
from (select t.*,
row_number() over (partition by company order by person_occurrence desc) as seqnum
from t
) t
where seqnum <= 3;
Now, this assumes that you want the top 3 regardless of ties -- that is, if 4 are tied with the same highest value, this returns three of them. Ties make things more difficult. You may want dense_rank() or rank() instead.
You can use correlated subquery :
SELECT t1.*
FROM table t1
WHERE t1.person_occurencee = (SELECT max(t2.person_occurence) FROM table t2 WHERE t1.company = t2.company);
If your DBMS supports analytical function then you can also do :
select t.*
from (select t.*,
rank() over (partition by company order by person_occurrence desc) as seq
from t
) t
where seq <= 3;

SQL sum by month with the previous values

I have following data:
cohort activity counter
-----------------------------
2010-12 0 470
2010-12 1 2
2010-12 2 1
2010-12 3 1
2010-12 6 1
2011-01 0 550
2011-01 1 1
2011-01 6 1
I want to sum counter of different activities by month, so the final table looks like:
cohort activity counter sumResult
-------------------------------------------
2010-12 0 470 470
2010-12 1 2 472
2010-12 2 1 473
2010-12 3 1 474
2010-12 6 1 475
2011-01 0 550 550
2011-01 1 1 551
2011-01 6 1 552
I've tried to do it like this:
select
a.activity, a.counter, a.cohort,
(
select sum(b.counter)
from data_table as b
where b.cohort = a.cohort and b.counter >= a.counter
) as sumResult
from data_table as a;
GO;
but it gave me strange results as:
cohort activity counter sumResult
-------------------------------------------
2010-12 0 470 470
2010-12 1 2 472
2010-12 2 1 475
2010-12 3 1 475
2010-12 6 1 475
2011-01 0 550 550
2011-01 1 1 552
2011-01 6 1 552
What could be a problem?
Depends on your RDBMS , some(SQL Server,Oracle,Postgresql) of them will accept SUM() OVER() :
SELECT t.*,
SUM(t.counter) OVER(PARTITION BY t.cohort ORDER BY t.activity) as sumResult
FROM YourTable t
If it's another, that's a bit more complicated and can be dealt with JOINS
The normal way to do this uses the ANSI standard cumulative sum function:
select dt.*,
sum(dt.counter) over (partition by dt.cohort order by dt.counter desc)
from data_table dt
order by cohort, counter desc;
If you want to use a subquery, the you need a stable sort, and activity can give you one. You can use this in the cumulative sum syntax:
select dt.*,
sum(dt.counter) over (partition by dt.cohort order by dt.counter desc, dt.activity)
from data_table dt
order by cohort, counter desc, activity;
Or using a subquery:
select dt.*,
(select sum(dt2.counter)
from data_table dt2
where dt2.cohort = dt.cohort and
(dt2.counter > dt.counter or
dt2.counter = dt.counter and dt2.activity < dt.activity)
)
from data_table dt
order by cohort, counter desc, activity;

Latest Data based on DateTime or CustMCId

I have a table in which different Clients are assign to different MC. Like Client (84) switch the MC 3 times. Now I want to get the latest MC of Client=84. I make this Query
select max(cstmrMC.CustMCId),cstmrMC.CustId,cstmrMC.MCID,cstmrMC.AssignDate
from CustomerMC cstmrMC
where cstmrMC.CustId=84
group by cstmrMC.CustMCId,cstmrMC.CustId,cstmrMC.MCID,cstmrMC.AssignDate
ORDER BY cstmrMC.CustMCId,cstmrMC.CustId,cstmrMC.MCID,cstmrMC.AssignDate
which shows this result
CustMCId CustId MCID AssignDate
52 84 18 2013-10-01 18:21:56.000
59 84 7 2013-09-09 16:10:06.000
80 84 19 2013-10-09 03:54:00.000
156 84 21 2013-11-11 00:00:00.000
NOw I want only this
156 84 21 2013-11-11 00:00:00.000
How can I get this result????
Use the row_number function to partition and order the customers so that the most recent MCID (based on AssignDate) is first within each customer.
WITH cteCustomers AS (
SELECT CustMCId, CustId, MCID, AssignDate,
ROW_NUMBER() OVER(PARTITION BY CustId ORDER BY AssignDate DESC) AS RowNum
FROM CustomerMC
)
SELECT CustMCId, CustId, MCID, AssignDate
FROM cteCustomers
WHERE RowNum = 1;

Sql get latest records of the month for each name

This question is probably answered before but i cant find how to get the latest records of the months.
The problem is that I have a table with sometimes 2 row for the same month. I cant use the aggregate function(I guess) cause in the 2 rows, i have different data where i need to get the latest.
Example:
name Date nuA nuB nuC nuD
test1 05/06/2013 356 654 3957 7033
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 06/22/2013 37 37 6 25
test4 06/27/2013 50 76 20 84
test4 05/15/2013 34 43 34 54
I need to get a result like:
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 05/15/2013 34 43 34 54
test4 06/27/2013 50 76 20 84
** in my example the data is in order but in my real table the data is not in order.
For now i have something like:
SELECT Name, max(DATE) , nuA,nuB,nuC,nuD
FROM tableA INNER JOIN
Group By Name, nuA,nuB,nuC,nuD
But it didn't work as i want.
Thanks in advance
Edit1:
It seems that i wasn't clear with my question...
So i add some data in my example to show you how i need to do it.
Thanks guys
Use SQL Server ranking functions.
select name, Date, nuA, nuB, nuC, nuD from
(Select *, row_number() over (partition by name, datepart(year, Date),
datepart(month, Date) order by Date desc) as ranker from Table
) Z
where ranker = 1
Try this
SELECT t1.* FROM Table1 t1
INNER JOIN
(
SELECT [name],MAX([date]) as [date] FROM Table1
GROUP BY [name],YEAR([date]),MONTH([date])
) t2
ON t1.[date]=t2.[date] and t1.[name]=t2.[name]
ORDER BY t1.[name]
Can you not just do an order
select * from tablename where Date = (select max(Date) from tablename)
followed by only pulling the first 3?