Finding least and highest month revenue - sql

I was having a problem for organizing a table where shows me
the month with the highest revenue and the lowest order by revenue
all the information is in the same table (Ordertable)
So I have orderdate and orderfinalprice.
select orderdate as MonthsSales, Highestrevenue, Lowestrevenue
from
(select months
, max (orderfinalprice) as Highestrevenue, min (orderfinalprice) as Lowestrevenue
From hologicOrder_T)
order by monthsales;

What's missing is the grouping by month based on orderdate.
select orderdate as MonthsSales, Highestrevenue, Lowestrevenue
from
(select to_char(orderdate, 'Month') orderdate, max(orderfinalprice) as Highestrevenue
, min (orderfinalprice) as Lowestrevenue
from hologicOrder_T
group by to_char(orderdate, 'Month'))
order by monthsales;

As far as I understood your problem, you want two months data, one with highest revenue and one with lowest revenue.
You can get it by following:
Select max(case when minrn = 1 then month_ end) lowestrevenue_month,
max(case when minrn = 1 then totalrevenue end) lowestrevenue,
max(case when maxrn = 1 then month_ end) highestrevenue_month,
max(case when maxrn = 1 then totalrevenue end) highestrevenue
From
(Select trunc(orderdate, 'month') month_,
Sum(orderfinalprice) as totalrevenue,
Row_nuumber() over (partition by trunc(orderdate, 'month') order by Sum(orderfinalprice)) as minrn,
Row_nuumber() over (partition by trunc(orderdate, 'month') order by Sum(orderfinalprice) desc) as maxrn
From hologicOrder_T
Group by trunc(orderdate, 'month') )
Where 1 in (minrn, maxrn);
You should not use to_char(orderdate, 'Month') because it will be same for the month regardless of its year.
In output, highestrevenue_month and lowestrevenue_month will be first date of the month, you can format it accordingly using to_char.
Cheers!!

Related

SQL - get start & end balance for each member each year

so I'd like to effectively get for each year the starting and end balance for each member for every year there is a record. for example the below would give me the latest balance for each member each year based on the date column
SELECT
T.MemberID,
T.DateCol,
T.Amount
FROM
(SELECT T.MemberID,
T.DateCol,
Amount,
ROW_NUMBER() OVER (PARTITION BY MemberID,
YEAR(DateCol)
ORDER BY
DateCol desc) AS seqnum
FROM
Tablet T
GROUP BY DateCol, MemberID, Amount
) T
WHERE
seqnum = 1 AND
MemberID = '1000009'
and the below would give me the earliest balance for each year
SELECT
T.MemberID,
T.DateCol,
T.Amount
FROM
(SELECT T.MemberID,
T.DateCol,
Amount,
ROW_NUMBER() OVER (PARTITION BY MemberID,
YEAR(DateCol)
ORDER BY
DateCol) AS seqnum
FROM
Tablet T
GROUP BY DateCol, MemberID, Amount
) T
WHERE
seqnum = 1 AND
MemberID = '1000009'
This would give me a result set like the below, column titles (MemberID, Date, Amount)
What I'm looking for is one query which is done by YEAR, MEMBERID, STARTBALANCE, ENDBALANCE as the columns. And would look like the below
What would be the best way to go about this?
commented above

How to get the difference between (multiple) two different rows?

I have a set of data containing some fields: month, customer_id, row_num (RANK), and verified_date.
The rank field indicates the first (1) and second (2) purchase of each customer. I would like to know the time difference between first and second purchase for each customer and show only its first month = month where row_num = 1.
https://i.ibb.co/PjJk5Y0/Capture.png
So my expected result is like below image:
https://i.ibb.co/y5Mww7k/Capture-2.png
I'm using StandardSQL in Google Bigquery.
row_num, verified_date
from table
GROUP BY 1, 2```
We can try using a pivot query here, aggregating by the customer_id:
SELECT
MAX(CASE WHEN row_num = 1 THEN month END) AS month,
customer_id,
1 AS row_num,
DATE_DIFF(MAX(CASE WHEN row_num = 2 THEN verified_date END),
MAX(CASE WHEN row_num = 1 THEN verified_date END), DAY) AS difference
FROM yourTable
GROUP BY
customer_id;

SQL sequence numbers and start/end date analysis

I am fairly new to SQL (SQL Management Studio 2016) and I only joined the site this morning...so my first post! I have been looking for a solution on the site regarding my issue. I have found a few links but none that (I think) will work having tried a few. I have a table that holds boiler service data. One address can have multiple dates/sequence numbers. I am looking to create a script that proves the latest sequential numbers start date is less than or equal to the latest sequential end date. So, in my example, I'd want to select the MAX seq_no for the start_date field and the 2nd MAX seq_no for the end_date field to make sure they haven't breached timescale.
My sample data has been added as an image (hopefully!)...just two addresses but there are 1000's in reality):
I have tried SLQ to get max seq_no's for just the end date initially but it just keeps bringing back all the entries:
select max (seq_no) as SEQNO, end_date, cmpnt_ref, prty_id
FROM hgmpcych
where prty_id in ('ABBEY10_TD12','ABBEY12_TD12') and cmpnt_ref='Boiler' and cycle_no='5'
group by end_date,prty_id,cmpnt_ref,seq_no
order by prty_id
This will probably be quite basic, but I am still pretty new to SQL. Any hints, advice or tips would be very much appreciated.
You could use ROW_NUMBER() to mark the rows in each group and only select the rows marked with 1 or 2 (The two "latest" rows)...
WITH
enumerated_hgmpcych AS
(
SELECT
seq_no, start_date, end_date, cmpnt_ref, prty_id,
ROW_NUMBER() OVER (PARTITION BY prty_id, cmpnt_ref
ORDER BY seq_no DESC
)
desc_seq_enumerator
FROM
hgmpcych
WHERE
prty_id in ('ABBEY10_TD12','ABBEY12_TD12')
AND cmpnt_ref='Boiler'
AND cycle_no='5'
)
SELECT
*
FROM
enumerated_hgmpcych
WHERE
desc_seq_enumerator <= 2
ORDER BY
prty_id,
cmpnt_ref,
seq_no
If you wanted to, you could collapse that to one row per group...
WITH
enumerated_hgmpcych AS
(
SELECT
seq_no, start_date, end_date, cmpnt_ref, prty_id,
ROW_NUMBER() OVER (PARTITION BY prty_id, cmpnt_ref
ORDER BY seq_no DESC
)
desc_seq_enumerator
FROM
hgmpcych
WHERE
prty_id in ('ABBEY10_TD12','ABBEY12_TD12')
AND cmpnt_ref='Boiler'
AND cycle_no='5'
)
SELECT
prty_id,
cmpnt_ref,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN seq_no END) AS final_seq_no,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN start_date END) AS final_start_date,
MAX(CASE WHEN desc_seq_enumerator = 1 THEN end_date END) AS final_end_date,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN seq_no END) AS prev_seq_no,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN start_date END) AS prev_start_date,
MAX(CASE WHEN desc_seq_enumerator = 2 THEN end_date END) AS prev_end_date
FROM
enumerated_hgmpcych
WHERE
desc_seq_enumerator <= 2
GROUP BY
prty_id,
cmpnt_ref
ORDER BY
prty_id,
cmpnt_ref
If you have max(seq_no), then you don't want it in the group by:
select max (seq_no) as SEQNO, end_date, cmpnt_ref, prty_id
from hgmpcych
where prty_id in ('ABBEY10_TD12', 'ABBEY12_TD12') and
cmpnt_ref = 'Boiler' and cycle_no = '5'
group by end_date, prty_id, cmpnt_ref
order by prty_id;

SQL query for Pricing analysis

Facing issue to find the Min and Max pricing status on the column YearMonth,
Below is my table data
YearMonth STATE ProductGroup LocaProdname Price
201407 MH AIRTEL AIRTEL-3G 10,000
201208 GJ IDEA IDEA-3G 1,200
201406 WB AIRCEL AIRCEL PERPAID 5,866
201407 DL TATA DOCOMA TATA LANDLINE 8,955
201207 KAR VODAFONE VODAFONE-3G 7,899
201312 MH AIRTEL AIRTEL-3G 15,000
201408 GJ IDEA IDEA-3G 25,000
I require below output:
YearMonth STATE ProductGroup LocaProdname Price Indictor-YEAR
201407 MH AIRTEL AIRTEL-3G 10,000 MAX
201312 MH AIRTEL AIRTEL-3G 15,000 MIN
201408 GJ IDEA IDEA-3G 25,000 MAX
201208 GJ IDEA IDEA-3G 1,200 MIN
I need the Max yearmonth and min Year values values.
If I understand correctly, you can do this with row_number():
select YearMonth, STATE, ProductGroup, LocaProdname, Price,
(case when seqnum_asc = 1 then 'MIN' else 'MAX' end) as Indicator
from (select d.*,
row_number() over (partition by state, productgroup, localprodname
order by price asc) as seqnum_asc,
row_number() over (partition by state, productgroup, localprodname
order by pricedesc) as seqnum_desc
from data
) d
where seqnum_asc = 1 or seqnum_desc = 1;
EDIT:
Does this do what you want?
select YearMonth, STATE, ProductGroup, LocaProdname, Price,
(case when seqnum_asc = 1 then 'MIN' else 'MAX' end) as Indicator
from (select d.*,
row_number() over (partition by YearMonth
order by price asc) as seqnum_asc,
row_number() over (partition by YearMOnth
order by pricedesc) as seqnum_desc
from data
) d
where seqnum_asc = 1 or seqnum_desc = 1;
Please use Row_number with partition BY and remove unwanted code as per your need,
SELECT yearmonth,state,productgroup,locaprodname,price,operation
FROM (
SELECT * FROM (SELECT p.yearmonth,p.state,p.productgroup,p.locaprodname,p.price,'MAX' AS Operation,
Row_number() OVER( partition BY p.productgroup, p.locaprodname
ORDER BY p.price DESC) AS Row
FROM pricingtest p) AS Maxx
WHERE Maxx.row = 1
UNION ALL
SELECT * FROM (SELECT p.yearmonth,p.state,p.productgroup,p.locaprodname,p.price,'MIN' AS Operation,
Row_number() OVER( partition BY p.productgroup, p.locaprodname
ORDER BY p.price ASC) AS Row
FROM pricingtest p) AS Minn
WHERE Minn.row = 1
) AS whole
ORDER BY yearmonth,productgroup
This can be done by finding the MAX/MIN values associated with the LocaProdname,ProductGroup and State then joining in on the table where everything matches. See below, or view the fiddle at http://sqlfiddle.com/#!3/4d6bd/2
NOTE: I've added in HAVING COUNT(*) > 1 as you seem to only want ones which have changed price. (Ie. Have more than 1 entry)
SELECT p.YearMonth
,p.State
,p.ProductGroup
,p.LocaProdname
,p.Price
,CASE
WHEN p.Price = a.MaxPrice
THEN 'MAX'
WHEN p.Price = a.MinPrice
THEN 'MIN'
END AS [Indicator-YEAR]
FROM PricingTest p
INNER JOIN (
SELECT LocaProdname
,ProductGroup
,State
,MAX(Price) AS MaxPrice
,MIN(Price) AS MinPrice
FROM pricingTest
GROUP BY LocaProdname
,ProductGroup
,State
HAVING COUNT(*) > 1
) a ON a.LocaProdname = p.LocaProdname
AND a.ProductGroup = p.ProductGroup
AND a.State= p.State
AND (
a.MaxPrice = p.Price
OR a.MinPrice = p.Price
)
ORDER BY LocaProdname
EDIT: Or I just noticed it's the max/min YearMonth the user might be looking, if this is the case check out http://sqlfiddle.com/#!3/4d6bd/4 It is basically just replacing all references to Price to YearMonth.
Once you get the last and first record you can UNION results:
SELECT t.*, 'MIN' AS Indicator
FROM
myTable t LEFT JOIN
myTable t2 ON t.YearMonth = t2.YearMonth AND t2.price < t.price
WHERE t2.YearMonth IS NULL
UNION
SELECT t.*, 'MAX' AS Indicator
FROM
myTable t LEFT JOIN
myTable t2 ON t.YearMonth = t2.YearMonth AND t2.price > t.price
WHERE t2.YearMonth IS NULL
If you have several records with same highest price, above query will return all of them. Also if you only have one record in a month, it will be returned twice as both MIN and MAX.

sql server - returning text for multiple vendors based on average values

I have a table giving ratings for various suppliers/areas. The format is below.
I would like to know, for each distinct month, and supplier (exp_id)
What was the highest and lowest rated pickup_ward_text
My expected output is similar to:
[year][month][exp_id] [highest rated pickup_ward] [lowest rated pickup_ward]
Where the 'rated' is an average of rating_driver, rating_punctuality & rating_vehicle
I am completely lost on how to achieve this, I have tried to past the first line of the table correctly below. a
Year Month exp_id RATING_DRIVER RATING_PUNCTUALITY RATING_VEHICLE booking_id pickup_date ratingjobref rating_date PICKUP_WARD_TEXT
2013 10 4 5.00 5.00 5.00 1559912 30:00.0 1559912 12/10/2013 18:29 N4
There's a common pattern using row_number() to find either the minimum or the maximum. You can combine them with a little trickery:
select
year,
month,
exp_id,
max(case rn1 when 1 then pickup_ward_text end) as min_pickup_ward_text,
max(case rn2 when 1 then pickup_ward_text end) as max_pickup_ward_text
from (
select
year,
month,
exp_id,
pickup_ward_text,
row_number() over (
partition by year, month, exp_id
order By rating_driver + rating_punctuality + rating_vehicle
) rn1,
row_number() over (
partition by year, month, exp_id
order By rating_driver + rating_punctuality + rating_vehicle desc
) rn2
from
mytable
) x
where
rn1 = 1 or rn2 = 1 -- this line isn't necessary, but might make things quicker
group by
year,
month,
exp_id
order by
year,
month,
exp_id
It may actually be faster to do two derived tables, for each part and inner join them. Some testing is in order:
select
n.year,
n.month,
n.exp_id,
n.pickup_ward_text as min_pickup_ward_text,
x.pickup_ward_text as max_pickup_ward_text
from (
select
year,
month,
exp_id,
pickup_ward_text,
row_number() over (
partition by year, month, exp_id
order By rating_driver + rating_punctuality + rating_vehicle
) rn
from
mytable
) n
inner join (
select
year,
month,
exp_id,
pickup_ward_text,
row_number() over (
partition by year, month, exp_id
order By rating_driver + rating_punctuality + rating_vehicle desc
) rn
from
mytable
) x
on n.year = x.year and n.month = x.month and n.exp_id = x.exp_id
where
n.rn = 1 and
x.rn = 1
order by
year,
month,
exp_id