select last row after various aggregation functions - sql-server

I have this query:
select b.Project_Id,b.Id,
FIRST_VALUE(i.Number) OVER(PARTITION BY b.id ORDER BY i.Date) as FirstNumDDT
,sum( ir.Qty) OVER(PARTITION BY b.id ORDER BY i.date) as sumqty
from InvoiceRow ir
inner join Invoice i on i.id=Invoice_Id
inner join BillOfMaterial b on b.id=ir.BOM_Id
and a few part of the result is:
Project_Id
Id
FirstNumDDT
sumqty
16088
1986620
21803
1
16088
1986620
21803
4
I need only the last row. How can I filter?
Thanks

Use TOP(N) in combination with an ORDER BY clause.
SELECT TOP(1)
b.Project_Id,b.Id,
FIRST_VALUE(i.Number) OVER(PARTITION BY b.id ORDER BY i.Date) as FirstNumDDT,
SUM(ir.Qty) OVER(PARTITION BY b.id ORDER BY i.date) as sumqty
from InvoiceRow ir
INNER JOIN Invoice i on i.id=Invoice_Id
INNER JOIN BillOfMaterial b on b.id=ir.BOM_Id
ORDER BY sumqty DESC
If you want allow to retrieve all values that have the maximum sumqty values, you need to use TOP(1) WITH TIES instead.
SELECT TOP(1) WITH TIES
b.Project_Id,b.Id,
FIRST_VALUE(i.Number) OVER(PARTITION BY b.id ORDER BY i.Date) as FirstNumDDT,
SUM(ir.Qty) OVER(PARTITION BY b.id ORDER BY i.date) as sumqty
from InvoiceRow ir
INNER JOIN Invoice i on i.id=Invoice_Id
INNER JOIN BillOfMaterial b on b.id=ir.BOM_Id
ORDER BY sumqty DESC

Related

Most Recent Data

I have a schema that looks like this.
Using the recordings table , query the most recent data in the database for each entityid/accid/month combination (Main Table is the main table)
use row_number()
select * from
(
select *,row_number() over(partition by entid, accid, month order by timestamp desc) as rn
from recordings a inner join maintable b on a.logid=b.logid
)A where rn=1
use row_number()
select * from
(
select m.*, row_number() over(partition by acctid,entid,month order by timestamp desc) rn
from maintable m join racordings r on m.logid=r.logid
) a where a.rn=1
Here's your query.
select * from
(select m.*, r.*, e.*, a.*, row_number() over(partition by a.AcctID, e.EntID, Month order by r.TimeStamp desc) row_num
from maintable m
inner join racordings r on m.LogID = r.LogID
inner join Entities e on e.EntID = m.EntID
inner join AccInfo a on a.AcctID = m.AcctID
) t1
where t1.row_num = 1

How to combine two rows into a single row in CTE

I am getting data in a CTE like this.
Here I am getting two records for each ActivityId, what I want to achieve is two create a single record from the two rows. From the row where r2=1 I need only the RDate as Todate, ActualProgress as endprogress and PlannedProgress as endplannedprogress because these are the only values that will changed on both the rows.
I am getting this data in a CTE.
WITH CTE as(SELECT row_number() over (partition by pmaph.ActivityId order by date) r1, row_number() over (partition by pmaph.ActivityId order by date desc) r2,pma.PlanEndDate as PlanEndDate ,pma.PlanStartDate as PlanStartDate,pmaph.ActivityId,pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,umd.UOM_Name as UomName, pmm.MilestoneName as MilestoneName,pma.ActivityName as ActivityName ,pmp.ProjectName as ProjectName, Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate, isnull(pmaph.Actual_Progress,0) as ActualProgress,isnull(pmaph.Planned_Progress,0) as PlannedProgress FROM ProjectMilestoneActivityProgressHistory as pmaph left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id where pmaph.Client_Id=#ClientId
)
select * from CTE where r1=1 or r2=1
You can do a Group By ActivityId and including a MAX(RDate) AND MAX(ActualProgress), it should return you only one-row per ActivityId.
Maybe this can give you a hint. Make sure to keep the format of your SQL.
;WITH CTE as
(
SELECT
row_number() over (partition by pmaph.ActivityId order by date) r1,
row_number() over (partition by pmaph.ActivityId order by date desc) r2,
pma.PlanEndDate as PlanEndDate ,
pma.PlanStartDate as PlanStartDate,
pmaph.ActivityId,
pmaph.ProjectMilestoneActivProgHist_Id as ProMileAvtiID,
umd.UOM_Name as UomName,
pmm.MilestoneName as MilestoneName,
pma.ActivityName as ActivityName,
pmp.ProjectName as ProjectName,
Replace((rtrim(ltrim(Convert(varchar(12),Cast(pmaph.Date as Datetime),106)))),' ','-') as RDate,
isnull(pmaph.Actual_Progress,0) as ActualProgress,
isnull(pmaph.Planned_Progress,0) as PlannedProgress
FROM
ProjectMilestoneActivityProgressHistory as pmaph
left join dbo.PM_Project as pmp on pmaph.ProjectId=pmp.ProjectId
left join dbo.PM_Activity as pma on pmaph.ActivityId=pma.ActivityId
left join dbo.PM_Milestone as pmm on pmaph.MilestoneId=pmm.MilestoneId
left join dbo.UOMDetail as umd on pma.UOM_Id=umd.UOM_Id
where
pmaph.Client_Id=#ClientId
)
SELECT
C1.*, -- Now you have all data in one row (by Activity), select whichever columns you want
C2.*
FROM
CTE AS C1
INNER JOIN CTE AS C2 ON
C1.ActivityId = C2.ActivityId AND
C2.r2 = 1 -- ... and join against the other row
WHERE
C1.r1 = 1 -- pick 1 row by Activity

rank function with sum

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

select count over partition by

I am learning window functions in sql server. I am using AdventrueWorks2012 database for practice. I want to calculate total number of sales and purchases for each item in the store.
The classic solution can be like
SELECT ProductID,
Quantity,
(SELECT Count(*)
FROM AdventureWorks.Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetail.ProductID = p.ProductID) TotalPurchases,
(SELECT Count(*)
FROM AdventureWorks.Sales.SalesOrderDetail
WHERE SalesOrderDetail.ProductID = p.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
Trying to convert to window functions gives me wrong results:
SELECT DISTINCT d.ProductID,
Quantity,
Count(d.ProductID)
OVER(
PARTITION BY d.ProductID) TotalPurchases,
Count(d2.ProductID)
OVER(
PARTITION BY d2.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
INNER JOIN AdventureWorks.Purchasing.PurchaseOrderDetail d
ON p.ProductID = d.ProductID
INNER JOIN AdventureWorks.Sales.SalesOrderDetail d2
ON p.ProductID = d2.ProductID
ORDER BY d.ProductID
Why this is wrong? How can I correct it?
You should change INNER JOIN to LEFT JOIN
Because when you inner join, result will miss productid which from ProductInventory table does not have PurchaseOrderDetail or SalesOrderDetail.

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