GROUP BY With ORDER BY ASC & DESC - sql

I have a table, spa, that has most of the information I need:
And I join another table, client, to grab the last_name field:
What I need is to get the first room_code, service_detail, & provider_start_time for each sba_date and provider_code, and the last provider_end_time.
Using my images as examples, the expected result would be:

I think that this can be done with window functions row_number() and last_value():
select
room_code,
service_detail,
sba_date,
provider_start_time,
provider_end_time,
last_name
from (
select
s.*,
c.last_name,
row_number() over(
partition by s.sba_date, s.provider_code
order by s.provider_start_time
) rn,
last_value(provider_end_time) over(
partition by s.sba_date, s.provider_code
order by s.provider_start_time
range between unbounded preceding and unbounded following
) provider_end_time
from spa s
inner join client c on c.client_code = s.provider_code
) t
where rn = 1
The inner query joins the two tables and ranks the records within groups of records having the same sba_date and provider_code, by ascending provider_start_time; it also computes the last value of the provider_end_time within the same group. Then, the outer query filters on the first record in each group.

Also you can use some CTE or sub-query:
;WITH cte AS ( --getting min and max time for particular provider on some date
SELECT sba_date,
MIN(provider_start_time) as provider_start_time,
MAX(provider_end_time) as provider_end_time,
provider_code
FROM spa
GROUP BY sba_date, provider_code
)
-- here goes join to clients (last_name) and original table to get room and detail
SELECT s.room_code,
s.service_detail,
c.sba_date,
c.provider_start_time,
c.provider_end_time,
cl.last_name
FROM cte c
INNER JOIN client cl
ON c.provider_code = cl.client_code
INNER JOIN spa s
ON s.sba_date = c.sba_date0
AND s.provider_code = c.provider_code
AND s.provider_start_time = c.provider_start_time

Related

How can I write a Oracle SQL query to extract the count of all orders 4 weeks before the last order?

I am looking to extract all order 4 weeks before the last order. I have 3 tables Customer, Order and Date | I tried this:
SELECT DISTINCT LOWER(FO.EMAIL) AS EMAIL,
count(FOI.ORDER_ID),
LAST_VALUE(D.DAY_DATE) OVER (PARTITION BY LOWER(C.EMAIL) ORDER BY D.DAY_DATE DESC, FOI.ORDER_ID ASC) AS LatOrderDate
FROM MTEPWDATA_CAN.MTEP_FACT_ORDER_ITEMS FOI LEFT OUTER JOIN MTEPWDATA_CAN.MTEP_DIM_DAY D ON FOI.ORDER_DATE_SKEY = D.DAY_SKEY LEFT OUTER JOIN MTEPWDATA_CAN.MTEP_DIM_CUSTOMER C ON FOI.CUSTOMER_SKEY = C.CUSTOMER_SKEY WHERE DATEADD(week,-4,lastorderDate)
group by EMAIL;
I dont think so can have both partition by and group by in the same query unless and until you use aggregate function on analytical function. So dont use partition by inside OVER() if you are using group by.
Try this:
SELECT DISTINCT LOWER(FO.EMAIL) AS EMAIL, count(FOI.ORDER_ID),
LAST_VALUE(D.DAY_DATE) OVER (ORDER BY D.DAY_DATE DESC, FOI.ORDER_ID ASC) AS LatOrderDate
FROM MTEPWDATA_CAN.MTEP_FACT_ORDER_ITEMS FOI LEFT OUTER JOIN MTEPWDATA_CAN.MTEP_DIM_DAY D
ON FOI.ORDER_DATE_SKEY = D.DAY_SKEY LEFT OUTER JOIN MTEPWDATA_CAN.MTEP_DIM_CUSTOMER C
ON FOI.CUSTOMER_SKEY = C.CUSTOMER_SKEY
WHERE DATEADD(week,-4,lastorderDate) group by EMAIL;
If I understand correctly, you can use window a function:
select t.*,
count(*) over (partition by customer
order by date
range between interval '4' weeks preceding and interval '1' second preceding
) as num_orders_prev_4_weeks
from t;

How to get the records from inner query results with the MAX value

The results are below. I need to get the records (seller and purchaser) with the max count- grouped by purchaser (marked with yellow)
You can use window functions:
with q as (
<your query here>
)
select q.*
from (select q.*,
row_number() over (order by seller desc) as seqnum_s,
row_number() over (order by purchaser desc) as seqnum_p
from q
) q
where seqnum_s = 1 or seqnum_p = 1;
Try this:
SELECT COUNT,seller,purchaser FROM YourTable ORDER BY seller,purchaser DESC
SELECT T2.MaxCount,T2.purchaser,T1.Seller FROM <Yourtable> T1
Inner JOIN
(
Select Max(Count) as MaxCount, purchaser
FROM <Yourtable>
GROUP BY Purchaser
)T2
On T2.Purchaser=T1.Purchaser AND T2.MaxCount=T1.Count
First you select the Seller from which will give you a list of all 5 sellers. Then you write another query where you select only the Purchaser and the Max(count) grouped by Purchaser which will give you the two yellow-marked lines. Join the two queries on fields Purchaser and Max(Count) and add the columns from the joined table to your first query.
I can't think of a faster way but this works pretty fast even with rather large queries. You can further-by order the fields as needed.

How to select max rownumber for each partition in SQL Server

Can anybody tell me how to select the max row number for each partition in SQL Server using CTE.
Suppose any employee is having 4 transaction rows and another is having only one row then how to select max rows for those employees.
I am having job table I want to fetch max row number for employee to fetch the latest transaction for that employee
I'd tried following
With CTE as (
Select
My fields,
Rownum = row_number() over(partition by emplid order by date) from jobtable
Where
Myconditions
)
Select * from CTE B left outer join
CTE A on A.emplid = B.emplid
Where
A.rownum = (select max(a2.rownum) from jobtable a2)
Do left join is required above or it is not at all needed ?
Please tell me how to fetch rownum if only 1 row exist for any employees as above query is fetching only employees which are having.greatest rownum in whole table
With CTE as (
Select
My fields,
Rownum = row_number() over(partition by emplid order by date DESC)
from jobtable
Where
Myconditions
)
SELECT *
FROM
cte
WHERE
RowNum = 1
Just reverse the order of your ROW_NUMBER and and select where it equals 1. Row numbers can be ascending (ASC) or descending (DESC). So if you want the most recent date to get the latest record ORDER BY date DESC, if you want the earliest record first you would choose ORDER BY date ASC (or date)

Want result with out using subquery?

SELECT
ROW_NUMBER()over(partition by tblProductTemplateHdr.product_ID
order by tblProductTemplateHdr.product_ID, tblProcessSequence.sl_No) AS rno,
tblProductTemplateHdr.product_ID
,tblProductProcessHdr.process_ID
,tblProcessSequence.sl_No
FROM
Production.tblProcessSequence
INNER JOIN
Production.tblProductProcessHdr ON tblProductProcessHdr.product_Process_ID = tblProcessSequence.product_Process_ID AND tblProductProcessHdr.isQC_Need = 1
INNER JOIN
Production.tblProductTemplateHdr ON tblProductTemplateHdr.product_Temp_ID = tblProductProcessHdr.product_Temp_ID
I want the row with maximum sl_No in each product_Id without using a subquery, this the result obtained by running this query want to apply filtering on same query
You need to a) rewrite your query just a little, and b) I'd recommend using table aliases to make your query more readable.
Try this:
;WITH ProductData AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY pth.Product_ID
ORDER BY pth.Product_ID, ps.sl_No DESC) AS rno,
tph.product_ID,
tph.process_ID,
ps.sl_No
FROM
Production.tblProcessSequence ps
INNER JOIN
Production.tblProductProcessHdr pph ON tph.product_Process_ID = ps.product_Process_ID
AND pph.isQC_Need = 1
INNER JOIN
Production.tblProductTemplateHdr tph ON tph.product_Temp_ID = pph.product_Temp_ID
)
SELECT *
FROM
ProductData
WHERE
rno = 1
The ROW_NUMBER() function partitions your data by Product_ID and within each partition, it orders the rows by sl_No DESC - so the highest value of sl_No gets the rno = 1 value (all others get higher numbers, in each partition)
You can use another windowed function:
MAX(tblProcessSequence.sl_No) OVER(PARTITION BY tblProductTemplateHdr.product_ID)
ADDENDUM
Just to give the full query in context in case the above was not clear:
SELECT ROW_NUMBER() OVER (PARTITION BY tempHdr.Product_ID ORDER BY Seq.sl_No DESC) AS rno,
tempHdr.product_ID,
procHdr.process_ID,
Seq.sl_No,
MAX(Seq.sl_No) OVER(PARTITION BY tblProductTemplateHdr.Product_ID) AS Max_SL_No
FROM Production.tblProcessSequence Seq
INNER JOIN Production.tblProductProcessHdr procHdr
ON Seq.product_Process_ID = tblProductProcessHdr.product_Process_ID
AND procHdr.isQC_Need = 1
INNER JOIN Production.tblProductTemplateHdr tempHdr
ON tempHdr.product_Temp_ID = procHdr.product_Temp_ID

Optimizing query with two MAX columns in the same table

I need to optimize below query
SELECT
Id, -- identity
CargoID,
[Status] AS CurrentStatus
FROM
dbo.CargoStatus
WHERE
id IN (SELECT TOP 1 ID
FROM dbo.CargoStatus CS
INNER JOIN STD.StatusMaster S ON CS.ShipStatusID = S.SatusID
WHERE CS.CargoID=CargoStatus.CargoID
ORDER BY YEAR([CS.DATE]) DESC, MONTH([CS.DATE]) DESC,
DAY([CS.DATE]) DESC, S.StatusStageNumber DESC)
There are two tables
CargoStatus, and
StatusMaster
Statusmaster has columns StatusID, StatusName, StatusStageNumber(int)
CargoStatus has columns ID, StatusID (FK StatusMaster StatusID column), Date
Is there any other better way of writing this query.
I want latest status for each cargo (only one entry per cargoID).
Since you seem to be using SQL Server 2005 or newer, you can use a CTE with the ROW_NUMBER() windowing function:
;WITH LatestCargo AS
(
SELECT
cs.Id, -- identity
cs.CargoID,
cs.[Status] AS CurrentStatus
ROW_NUMBER() OVER(PARTITION BY cs.CargoID
ORDER BY cs.[Date], s.StatusStageNumber DESC) AS 'RowNum'
FROM
dbo.CargoStatus cs
INNER JOIN
STD.StatusMaster s ON cs.ShipStatusID = s.[StatusID]
)
SELECT
Id, CargoID, [Status]
FROM
LatestCargo
WHERE
RowNum = 1
This CTE "partitions" your data by CargoID, and for each partition, the ROW_NUMBER function hands out sequential numbers, starting at 1 and ordered by Date DESC - so the latest row gets RowNum = 1 (for each CargoID) which is what I select from the CTE in the SELECT statement after it.