rank function with sum - sql-server

I have two tables.
abc(CID(pk), cname,)
order(order_id(pk), CID(fk), number_of_rentals)
I want to determine top 10 customers on the basis of number of movies they rented.
select
orders.cid,orders.no_rentals, abc.name,
rank() over (order by no_rentals desc) "rank"
from abc
inner join orders on orders.CID = abc.CID;
I used this query but it's not universal. How can I use sum function on number_of_rentals with this query?

Select Top 10
orders.cid
, abc.name
, SUM(orders.no_rentals) TotalRentals
, rank() over (order by SUM(orders.no_rentals) desc) [rank]
from abc
inner join orders on orders.CID = abc.CID
Group By orders.cid, abc.name
Order By TotalRentals DESC

Related

Latest Customer Donation And Amount

I have two tables:
Customer which has an Id column representing the customer Id.
CustomerDonation that contains CustomerId (FK), Amount and DatePayed
I'd like have all the customers together with their latest donation and the amount of that donation.
I am receiving duplicate values on my query so I will not paste it here.
You could also use the WITH TIES option
Select Top 1 With Ties *
From YourTable
Order By Row_Number() over (Partition By CustomerId Order By DatePayed Desc)
WITH
SortedDonation AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY CustomerId ORDER BY DatePayed DESC) AS SeqID,
*
FROM
CustomerDonation
)
SELECT
*
FROM
Customer
LEFT JOIN
SortedDonation
ON SortedDonation.CustomerId = Customer.Id
AND SortedDonation.SeqId = 1
If the same customer can make multiple donations with the same DatePayed, then this will arbitrarily pick just one of them.
If you add additional fields to the ORDER BY you can deterministically pick which one you want.
Or, if you want all of them use DENSE_RANK() instead of ROW_NUMBER()
Use Row_Number() Analytic function .
Select * from (
Select customerId,Amount,DatePayed, row_number() over (partition by CustomerId order by DatePayed desc) as rowN)
as tab where rowN = 1
You only need the CustomerDonation table for this. You can join with the Customer table if you want other information of the customer.
WITH cte AS (
SELECT
CustomerId
, MAX(DatePayed) AS LastDate
FROM
CustomerDonation
)
SELECT
cd.CustomerId
, cd.Amount
, cd.DatePayed
FROM
CustomerDonation cd
JOIN cte ON cd.CustomerId = cte.CustomerId
AND cd.DatePayed = cte.LastDate

SQL select top 10 for each year

I have a fact database from which I want to make a trendline based on top 10 items based on sum quantity for each item per year.
I've done the following, but it does for example select more than 10 entities for my year 2007:
select TOP 10 sum(Quantity) as Quantity,DIM_Time.Year, DIM_Item.Name as Name
from Fact_Purchase
join DIM_Item on DIM_Item.BKey_ItemId = Fact_Purchase.DIM_Item
join DIM_Time on DIM_Time.ID = Fact_Purchase.DIM_Time_DeliveryDate
where Fact_Purchase.DIM_Company = 2 and DIM_Time.ID = FACT_Purchase.DIM_Time_DeliveryDate
Group by dim_item.Name, DIM_Time.Year
Order by Quantity DESC
How do I select top 10 items with the highest quantity through all my years, with only 10 top entities for each year?
As you can guess, the company is individual, and Is going to be a parameter in my report
I think this is what you're going for. My apologies if I messed up on translating your tables across.
select *
from (
select DIM_Time.[Year], dim_item.Name, SUM(Quantity) Quantity, RANK() OVER (PARTITION BY DIM_Time.[Year] ORDER BY SUM(Quantity) DESC) salesrank
from Fact_Purchase
join DIM_Item on DIM_Item.BKey_ItemId = Fact_Purchase.DIM_Item
join DIM_Time on DIM_Time.ID = Fact_Purchase.DIM_Time_DeliveryDate
where Fact_Purchase.DIM_Company = 2 and DIM_Time.ID = FACT_Purchase.DIM_Time_DeliveryDate
group by dim_item.Name, DIM_Time.[Year]
) tbl
where salesrank <= 10
order by [Year], salesrank
The subquery groups by name/year, and the RANK() OVER part sets up a sort of row index that increments by SUM(Quantity) and restarts for each Year. From there you just have to filter out anything with a salesrank (index) that's over 10.
SELECT
_year,
Name,
_SUM,
RANK_iD
FROM
(
SELECT
_year,
Name,
_SUM,
DENSE_RANK()OVER(PARTITION BY _year,_Month ORDER BY _SUM DESC) AS RANK_iD
FROM(
Select
DIM_Time AS _year,
DIM_Item as Name,
sum(Quantity) AS _SUM
from
#ABC
GROUP BY
_year,
Name
)A
)B
WHERE RANK_iD<=10

Cannot put where into query

I'm trying to do this task:
Find total amount of all orders for each customer, sort customers by
the value from maximum amount to minimum and show customers from 40 to
50 position in the result. Only one query.
I'm training on Northwind sample database. My query:
;WITH MyCte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY SUM(OD.UnitPrice*OD.Quantity*(1-OD.Discount)) DESC) Number
, O.CustomerID
, SUM(OD.UnitPrice*OD.Quantity*(1-OD.Discount)) TotalAmount
FROM [Order Details] OD
RIGHT JOIN Orders O ON OD.OrderID = O.OrderID
GROUP BY CustomerID
ORDER BY TotalAmount DESC
)
SELECT
Number
, CustomerID
, TotalAmount
FROM MyCte
WHERE Number BETWEEN 40 AND 50
But this doesn't work. May someone help me to put "Where" correctly to this query?
;WITH MyCte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY SUM(OD.UnitPrice*OD.Quantity*(1-OD.Discount)) DESC) Number
, O.CustomerID
, SUM(OD.UnitPrice*OD.Quantity*(1-OD.Discount)) TotalAmount
FROM [Order Details] OD
RIGHT JOIN Orders O ON OD.OrderID = O.OrderID
GROUP BY CustomerID
)
SELECT
Number
, CustomerID
, TotalAmount
FROM MyCte
WHERE Number >= 40 and Number <= 50
Main trouble was in Order By in MyCTE table. This query will work.

Group by customer name

Demo
SELECT ROW_NUMBER() OVER (ORDER BY Visit_Date DESC,P_Master.P_Name ASC) AS RowNumber,
P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%'
I have to show max date of column Visit_Date if i search on '2013-10-29' then record shows those customers have date '2013-10-29' in coloumn i have to shown max date of customer
all its working fine but How to make group by PID(I have to show only one record for the given search )
Please try below query, it will also help in pagination
SELECT ROW_NUMBER() OVER (ORDER BY Visit_Date DESC,P_Name ASC) AS RowNumber, *
FROM (SELECT DISTINCT P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%') tbl
This will work:
SELECT DISTINCT
P_Master.P_Name,
(SELECT MAX(Visit_Date) FROM P_Visit v WHERE v.PID = p_Master.PID) as Visit_Date
FROM P_Master
LEFT JOIN P_VISIT
ON P_Master.PID=P_VISIT.PID
WHERE P_Master.P_Name LIKE 'j%'

RANK() Over Partition BY not working

When I run the code below the ROWID is always 1.
I need to the ID to start at 1 for each item with the same Credit Value.
;WITH CTETotal AS (SELECT
TranRegion
,TranCustomer
,TranDocNo
,SUM(TranSale) 'CreditValue'
FROM dbo.Transactions
LEFT JOIN customers AS C
ON custregion = tranregion
AND custnumber = trancustomer
LEFT JOIN products AS P
ON prodcode = tranprodcode
GROUP BY
TranRegion
,TranCustomer
,TranDocNo)
SELECT
r.RegionDesc
,suppcodedesc
,t.tranreason as [Reason]
,t.trandocno as [Document Number]
,sum(tranqty) as Qty
,sum(tranmass) as Mass
,sum(transale) as Sale
,cte.CreditValue AS 'Credit Value'
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
FROM transactions t
LEFT JOIN dbo.Regions AS r
ON r.RegionCode = TranRegion
LEFT JOIN CTETotal AS cte
ON cte.TranRegion = t.TranRegion
AND cte.TranCustomer = t.TranCustomer
AND cte.TranDocNo = t.TranDocNo
GROUP BY
r.RegionDesc
,suppcodedesc
,t.tranreason
,t.trandocno
,cte.CreditValue
ORDER BY CreditValue ASC
EDIT
All the credit values with 400 must have the ROWID set to 1. And all the credit values with 200 must have the ROWID set to 2. And so on and so on.
Do you need something like this?
with cte (item,CreditValue)
as
(
select 'a',8 as CreditValue union all
select 'b',18 union all
select 'a',8 union all
select 'b',18 union all
select 'a',8
)
select CreditValue,dense_rank() OVER (ORDER BY item)AS ROWID from cte
Result
CreditValue ROWID
----------- --------------------
8 1
8 1
8 1
18 2
18 2
In your code replace
,RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.CreditValue)AS ROWID
by
,DENSE_RANK() OVER (ORDER BY cte.CreditValue)AS ROWID
You just don't have to use PARTITION, just DENSE_RANK() OVER (ORDER BY cte.CreditValue)
I think the problem is with the RANK() OVER (PARTITION BY clause
you have to partition it by item not by CreditValue
Try this
RANK() OVER (PARTITION BY cte.CreditValue ORDER BY cte.RegionDesc)AS ROWID
Edit: The issue here isn't actually the nesting of the subquery, it's potentially based on partition by having columns that truly make each row unique (or 1)
Rather than ranking within your complex query like this
select
rank() over(partition by...),
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
Try rank() or row_number() on the resulting data set, not within it.
For example, using the query above, remove rank() and implement it this way:
select
rank() over(partition by...),
results.*
from (
select
*
from
data_source
join table1
join table2
join table3
join table4
order by
some_column
) as results

Resources