I have the following two tables: First is the result of my query, and the second one is the result that I want to achieve. I need help in displaying all the lastest data based on the transaction date for each concessionaire.
ConcessionaireId EndReading TransactionDate
1 3606 9/1/2022
1 3586 8/1/2022
1 3565 7/1/2022
2 4174 9/1/2022
2 4163 8/1/2022
2 4151 7/1/2022
3 7125 9/1/2022
3 7090 8/1/2022
3 7051 7/1/2022
4 6019 9/1/2022
4 5992 8/1/2022
4 5963 7/1/2022
5 3165 9/1/2022
5 3151 8/1/2022
5 3139 7/1/2022
ConcessionaireId EndReading TransactionDate
1 3606 9/1/2022
2 4174 9/1/2022
3 7125 9/1/2022
4 6019 9/1/2022
5 3165 9/1/2022
SELECT top 100 percent
ConcessionaireId, EndReading, FORMAT(TransactionDate, 'MM/dd/yyyy') AS 'TransactionDate'
FROM Transactions
WHERE EXISTS (SELECT * FROM Transactions
GROUP BY ConcessionaireId, Particulars)
AND ConcessionaireId IS NOT NULL AND Particulars = 'Billing'
GROUP BY ConcessionaireId, EndReading, TransactionDate
HAVING ConcessionaireId > 0
ORDER BY ConcessionaireId, MAX(CONVERT(int,(FORMAT(TransactionDate,'yyyyMMdd')))) DESC
You can achieve this using ROW_NUMBER() Window function in SQL server
;With CTE AS(
SELECT top 100 percent
ConcessionaireId, EndReading, FORMAT(TransactionDate, 'MM/dd/yyyy') AS 'TransactionDate',
ROW_NUMBER() OVER(PARTITION BY ConcessionaireId ORDER BY TransactionDate DESC) AS RN
FROM Transactions
WHERE EXISTS (SELECT * FROM Transactions
GROUP BY ConcessionaireId, Particulars)
AND ConcessionaireId IS NOT NULL AND Particulars = 'Billing'
GROUP BY ConcessionaireId, EndReading, TransactionDate
HAVING ConcessionaireId > 0
ORDER BY ConcessionaireId, MAX(CONVERT(int,(FORMAT(TransactionDate,'yyyyMMdd')))) DESC)
SELECT ConcessionaireId, EndReading, TransactionDate
FROM CTE
WHERE RN = 1
ORDER BY ConcessionaireId
Related
In PostgreSQL I have an orders table that represents orders made by customers of a store:
SELECT * FROM orders
order_id
customer_id
value
created_at
1
1
188.01
2020-11-24
2
2
25.74
2022-10-13
3
1
159.64
2022-09-23
4
1
201.41
2022-04-01
5
3
357.80
2022-09-05
6
2
386.72
2022-02-16
7
1
200.00
2022-01-16
8
1
19.99
2020-02-20
For a specified time range (e.g. 2022-01-01 to 2022-12-31), I need to find the following:
Average 1st order value
Average 2nd order value
Average 3rd order value
Average 4th order value
E.g. the 1st purchases for each customer are:
for customer_id 1, order_id 8 is their first purchase
customer 2, order 6
customer 3, order 5
So, the 1st-purchase average order value is (19.99 + 386.72 + 357.80) / 3 = $254.84
This needs to be found for the 2nd, 3rd and 4th purchases also.
I also need to find the average time between purchases:
order 1 to order 2
order 2 to order 3
order 3 to order 4
The final result would ideally look something like this:
order_number
AOV
av_days_since_last_order
1
254.84
0
2
300.00
28
3
322.22
21
4
350.00
20
Note that average days since last order for order 1 would always be 0 as it's the 1st purchase.
Thanks.
select order_number
,round(avg(value),2) as AOV
,coalesce(round(avg(days_between_orders),0),0) as av_days_since_last_order
from
(
select *
,row_number() over(partition by customer_id order by created_at) as order_number
,created_at - lag(created_at) over(partition by customer_id order by created_at) as days_between_orders
from t
) t
where created_at between '2022-01-01' and '2022-12-31'
group by order_number
order by order_number
order_number
aov
av_days_since_last_order
1
372.26
0
2
25.74
239
3
200.00
418
4
201.41
75
5
159.64
175
Fiddle
Im suppose it should be something like this
WITH prep_data AS (
SELECT order_id,
cuntomer_id,
ROW_NUMBER() OVER(PARTITION BY order_id, cuntomer_id ORDER BY created_at) AS pushcase_num,
created_at,
value
FROM pushcases
WHERE created_at BETWEEN :date_from AND :date_to
), prep_data2 AS (
SELECT pd1.order_id,
pd1.cuntomer_id,
pd1.pushcase_num
pd2.created_at - pd1.created_at AS date_diff,
pd1.value
FROM prep_data pd1
LEFT JOIN prep_data pd2 ON (pd1.order_id = pd2.order_id AND pd1.cuntomer_id = pd2.cuntomer_id AND pd1.pushcase_num = pd2.pushcase_num+1)
)
SELECT order_id,
cuntomer_id,
pushcase_num,
avg(value) AS avg_val,
avg(date_diff) AS avg_date_diff
FROM prep_data2
GROUP BY pushcase_num
I have the following table. Let's call it orders. I would like to add a new column to this existing table which calculates the days apart from the first order date by the customerid. If there are 0 days apart from the minimum sold date, then it should be 0.
From this
customerid orderdate
1 1/21/2018
1 1/21/2018
1 2/21/2018
1 5/22/2018
2 3/22/2018
3 4/5/2018
3 4/5/2018
to this
customerid orderdate daysapart
1 1/21/2018 0
1 1/21/2018 0
1 2/21/2018 30
1 2/21/2018 123
2 3/22/2018 0
3 4/5/2018 0
3 4/5/2018 0
Using a Windowed Aggregate:
select customerid, orderdate,
orderdate - min(orderdate) over (partition by customerid) as daysapart
from mytab
Here is one approach, using a correlated subquery:
SELECT
t1.customerid,
t1.orderdate,
t1.orderdate - (SELECT MIN(t2.orderdate)
FROM your_table t2
WHERE t1.customerid = t2.customerid) daysapart
FROM your_table t1;
Let say I have this kind of data:
Date Category Amount
01/10/2014 20:04 2 12212
01/11/2014 0:00 3 11043.38
01/11/2014 16:03 2 12082
01/11/2014 16:32 3 110.43
01/12/2014 20:41 2 12196
01/12/2014 20:42 3 103.22
31/12/2014 14:20 2 12440
31/12/2014 14:21 3 104.25
I wish to get below result:
Date Category Amount
01/10/2014 20:04 2 12212
01/11/2014 16:03 2 12082
01/11/2014 16:32 3 110.43
01/12/2014 20:41 2 12196
01/12/2014 20:42 3 103.22
So far, I am able to make this query:
select t.date, t.Category, t.Amount
from mytable t
inner join (
select Category,MONTH(date) MONTHH,YEAR(date) YEARR, max(date) as MaxDate
from mytable
group by Category,MONTH(date) MONTHH,YEAR(date) YEARR
) tm on t.date = tm.MaxDate and t.Category = tm.Category
But it returns a wrong result if there is more than 1 date in 1 month. This is the result:
Date Category Amount
01/10/2014 20:04 2 12212
01/11/2014 16:03 2 12082
01/11/2014 16:32 3 110.43
31/12/2014 14:20 2 12440
31/12/2014 14:21 3 104.25
Could anyone help please? thanks
Use row_number() and rank():
select t.*
from (select t.*,
dense_rank() over (partition by year(date), month(date) order by day(date)) as seqnum,
row_number() over (partition by year(date), month(date), day(date) order by date desc) as seqnum_d
from mytable t
) t
where seqnum = 1 and seqnum_d = 1;
Try This
;WITH CTE
AS
(
SELECT
RN = ROW_NUMBER() OVER(PARTITION BY MONTH([Date]),YEAR([Date]),Category ORDER BY [Date]),
*
FROM YourTable
)
SELECT
Date,
Category,
Amount
FROM CTE
WHERE RN = 1
Do not use reserved words as columns (i.e. Date).
No need to group, you are not using any summation/averaging:
select *
from tda t
where not exists(
-- not exists: same date, later time, cat is same
select 1
from tda b
where 1 = 1
and cast(t.dDate as date) = cast(b.dDate as date)
and t.ddate > b.ddate
and t.cat = b.cat
)
and not exists(
-- not exists: same month, earlier date
select 1
from tda b
where month(b.ddate) = month(t.ddate)
and day(b.ddate)<day(t.ddate)
)
to get (reformat the date to your liking):
ddate Cat Amount
2014-10-01T20:04:00Z 2 12212
2014-11-01T00:00:00Z 3 11043.38
2014-11-01T16:03:00Z 2 12082
2014-12-01T20:41:00Z 2 12196
2014-12-01T20:42:00Z 3 103.22
by
CREATE TABLE tda ([ddate] datetime,[Cat] int, [Amount] numeric(10,2));
INSERT INTO tda (dDate, Cat, Amount)
VALUES
('2014/10/01 20:04', 2, 12212),
('2014/11/01 0:00', 3, 11043.38),
('2014/11/01 16:03', 2, 12082),
('2014/11/01 16:32', 3, 110.43),
('2014/12/01 20:41', 2, 12196),
('2014/12/01 20:42', 3, 103.22),
('2014/12/31 14:20', 2, 12440),
('2014/12/31 14:21', 3, 104.25)
;
I am using SQL-Server and have a table of my Purchase orders (stock). But stuck in a query while I was trying to get my All Available stock with its Latest Cost Price and Latest Selling Price.
I made a query it run successfully, but i need some better and optimized way to do this, because it will get slow when table have n number of records.
Query Sample:
SELECT
po.ProductID, sum(po.AvailableQty) as AvailableQty,
(select top 1 po2.CostPrice from Sales_PurchaseOrders po2 where po2.PurchasedAt=max(po.PurchasedAt)) as CostPrice,
(select top 1 po2.SellingPrice from Sales_PurchaseOrders po2 where po2.PurchasedAt=max(po.PurchasedAt)) as SellingPrice
FROM
Sales_PurchaseOrders po
INNER JOIN Sales_Products p on p.ProductID=po.ProductID
GROUP BY po.ProductID
Table Data:
PurchaseOrderID ProductID CostPrice SellingPrice AvailableQty PurchasedAt
--------------- ----------- --------------------------------------- --------------------------------------- --------------------------------------- -----------------------
1 1 90.000000 100.000000 2.000000 2016-07-28 00:00:00.000
2 1 33.580000 50.000000 0.000000 2016-06-28 00:00:00.000
3 2 200.000000 240.000000 15.000000 2016-07-30 00:00:00.000
4 1 50.000000 60.000000 0.000000 2016-08-02 00:00:00.000
5 1 50.000000 60.000000 1.000000 2016-08-03 00:00:00.000
6 1 100.000000 110.000000 6.000000 2016-08-04 00:00:00.000
7 1 25.000000 30.000000 3.000000 2016-08-03 00:00:00.000
8 1 20.000000 30.000000 0.000000 2016-07-30 00:00:00.000
1007 1 100.000000 200.000000 2.000000 2016-09-24 00:00:00.000
Query Result:
ProductID AvailableQty CostPrice SellingPrice
----------- --------------------------------------- --------------------------------------- ---------------------------------------
1 14.000000 100.000000 200.000000
2 15.000000 200.000000 240.000000
May be via some kind of aggregate function, or any other better optimized way to do this.
Thanks,
I think this does what you want:
SELECT po.ProductID, sum(po.AvailableQty) as AvailableQty,
MAX(last_CostPrice), MAX(last_SellingPrice)
FROM (SELECT po.*,
FIRST_VALUE(CostPrice) OVER (PARTITION BY ProductId ORDER BY PurchasedAt DESC) as last_CostPrice,
FIRST_VALUE(SellingPrice) OVER (PARTITION BY ProductId ORDER BY PurchasedAt DESC) as last_SellingPrice
FROM Sales_PurchaseOrders po
) po
GROUP BY po.ProductID;
Notes:
The table Sales_Products seems totally unnecessary for the query.
You probably want the most recent cost and selling price for the product, not for all products.
You can use FIRST_VALUE() in the subquery to get this information.
Dear Mehmood Try this.
;with wt_table
as
(
select ROW_NUMBER() over(partition by po.ProductID order by PurchasedAt desc) as Num,
AvailableQty=sum(po.AvailableQty) over(partition by po.ProductID),
po.ProductID,
po.CostPrice,
po.SellingPrice,
po.PurchasedAt
From #Sales_PurchaseOrders po)
select * from wt_table where Num=1
try this:
with Sales_PurchaseOrders(PurchaseOrderID,ProductID,CostPrice,SellingPrice,AvailableQty,PurchasedAt)AS(
select 1,1,90.000000,100.000000,2.000000,'2016-07-28 00:00:00.000' union all
select 2,1,33.580000,50.000000,0.000000,'2016-06-28 00:00:00.000' union all
select 3,2,200.000000,240.000000,15.000000,'2016-07-30 00:00:00.000' union all
select 4,1,50.000000,60.000000,0.000000,'2016-08-02 00:00:00.000' union all
select 5,1,50.000000,60.000000,1.000000,'2016-08-03 00:00:00.000' union all
select 6,1,100.000000,110.000000,6.000000,'2016-08-04 00:00:00.000' union all
select 7,1,25.000000,30.000000,3.000000,'2016-08-03 00:00:00.000' union all
select 8,1,20.000000,30.000000,0.000000,'2016-07-30 00:00:00.000' union all
select 1007,1,100.000000,200.000000,2.000000,'2016-09-24 00:00:00.000'
)
select * from (
SELECT
po.ProductID, sum(po.AvailableQty)over(partition by po.ProductID) as AvailableQty,CostPrice,SellingPrice,
row_number()over(partition by po.ProductID order by po.PurchasedAt desc) as seq
FROM Sales_PurchaseOrders po
) as t where t.seq=1
ProductID AvailableQty CostPrice SellingPrice seq
1 1 14,000000 100,000000 200,000000 1
2 2 15,000000 200,000000 240,000000 1
I have some data that looks like this:
CustID EventID TimeStamp
1 17 1/1/15 13:23
1 17 1/1/15 14:32
1 13 1/1/25 14:54
1 13 1/3/15 1:34
1 17 1/5/15 2:54
1 1 1/5/15 3:00
2 17 2/5/15 9:12
2 17 2/5/15 9:18
2 1 2/5/15 10:02
2 13 2/8/15 7:43
2 13 2/8/15 7:50
2 1 2/8/15 8:00
I'm trying to use the row_number function to get it to look like this:
CustID EventID TimeStamp SeqNum
1 17 1/1/15 13:23 1
1 17 1/1/15 14:32 1
1 13 1/1/25 14:54 2
1 13 1/3/15 1:34 2
1 17 1/5/15 2:54 3
1 1 1/5/15 3:00 4
2 17 2/5/15 9:12 1
2 17 2/5/15 9:18 1
2 1 2/5/15 10:02 2
2 13 2/8/15 7:43 3
2 13 2/8/15 7:50 3
2 1 2/8/15 8:00 4
I tried this:
row_number () over
(partition by custID, EventID
order by custID, TimeStamp asc) SeqNum]
but got this back:
CustID EventID TimeStamp SeqNum
1 17 1/1/15 13:23 1
1 17 1/1/15 14:32 2
1 13 1/1/25 14:54 3
1 13 1/3/15 1:34 4
1 17 1/5/15 2:54 5
1 1 1/5/15 3:00 6
2 17 2/5/15 9:12 1
2 17 2/5/15 9:18 2
2 1 2/5/15 10:02 3
2 13 2/8/15 7:43 4
2 13 2/8/15 7:50 5
2 1 2/8/15 8:00 6
how can I get it to sequence based on the change in the EventID?
This is tricky. You need a multi-step process. You need to identify the groups (a difference of row_number() works for this). Then, assign an increasing constant to each group. And then use dense_rank():
select sd.*, dense_rank() over (partition by custid order by mints) as seqnum
from (select sd.*,
min(timestamp) over (partition by custid, eventid, grp) as mints
from (select sd.*,
(row_number() over (partition by custid order by timestamp) -
row_number() over (partition by custid, eventid order by timestamp)
) as grp
from somedata sd
) sd
) sd;
Another method is to use lag() and a cumulative sum:
select sd.*,
sum(case when prev_eventid is null or prev_eventid <> eventid
then 1 else 0 end) over (partition by custid order by timestamp
) as seqnum
from (select sd.*,
lag(eventid) over (partition by custid order by timestamp) as prev_eventid
from somedata sd
) sd;
EDIT:
The last time I used Amazon Redshift it didn't have row_number(). You can do:
select sd.*, dense_rank() over (partition by custid order by mints) as seqnum
from (select sd.*,
min(timestamp) over (partition by custid, eventid, grp) as mints
from (select sd.*,
(row_number() over (partition by custid order by timestamp rows between unbounded preceding and current row) -
row_number() over (partition by custid, eventid order by timestamp rows between unbounded preceding and current row)
) as grp
from somedata sd
) sd
) sd;
Try this code block:
WITH by_day
AS (SELECT
*,
ts::date AS login_day
FROM table_name)
SELECT
*,
login_day,
FIRST_VALUE(login_day) OVER (PARTITION BY userid ORDER BY login_day , userid rows unbounded preceding) AS first_day
FROM by_day