Select most recent status for each ID and department code - sql

I have the following table:
I want to get the most recent status for each dept_code that a CL_ID has. So the desired output would be this:
I have tried the following but this give me just the most recent status for each client and not each of their dept_codes.
SELECT *
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT] C
INNER JOIN
(SELECT CLIENT_NUMBER, MAX(STATUS_DATE) AS SDATE
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT]
GROUP BY CLIENT_NUMBER) X
ON X.CLIENT_NUMBER = C.CLIENT_NUMBER
AND X.SDATE = C.STATUS_DATE
ORDER BY C.CLIENT_NUMBER
Any help would be much appreciated. Thanks.

A convenient method that works in SQL Server is:
select top (1) cl.*
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl
order by row_number() over (partition by cl_id, dept_code order by status_date desc);
A method that is efficient with the right indexes in almost any database is:
select cl.*
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl
where cl.status_date = (select max(cl2.status_date)
from [CIMSHR6_MERGED].[dbo].[C3CLSTAT] cl2
where cl2.cl_id = cl.cl_id and cl2.dept_code = cl.dept_code
);
The right index is on (cl_id, dept_code, status_date).

I would also use ROW_NUMBER, but with a subquery:
SELECT CL_ID, Status_date, Status, Dept_code
FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CL_ID, Dept_code ORDER BY Status_date DESC) rn
FROM CIMSHR6_MERGED].[dbo].[C3CLSTAT]
) t
WHERE rn = 1;

1) Firstly group everything on Dept_Code,CL_ID and assign rank for each row with in the group in descending order.
2) Select all the rows with rnk=1 which would display your desired result.
SELECT Z.CL_ID,
Z.Status_Date,
Z.Status,
Z.Dept_Code
FROM
(
SELECT *,
RANK() OVER( PARTITION BY Dept_Code,CL_ID, ORDER BY Status_Date DESC ) AS rnk
FROM [CIMSHR6_MERGED].[dbo].[C3CLSTAT]
) Z
WHERE Z.rnk = 1;

This would work for almost all databases
select * from c3clstat c
where exists
(select 1 from c3clstat c1
where c1.cl_id=c.cl_id
and c1.dept_code=c.dept_code
group by cl_id,dept_code
having c.status_date=max(c1.status_date)
)

Related

Selecting the latest order

I need to select the data of all my customers with the records displayed in the image. But I need to get the most recent record only, for example I need to get the order # E987 for John and E888 for Adam. As you can see from the example, when I do the select statement, I get all the order records.
You don't mention the specific database, so I'll answer with a generic solution.
You can do:
select *
from (
select t.*,
row_number() over(partition by name order by order_date desc) as rn
from t
) x
where rn = 1
You can use analytical function row_number.
Select * from
(Select t.*,
Row_number() over (partition by customer_id order by order_date desc) as rn
From your_table t) t
Where rn = 1
Or you can use not exists as follows:
Select *
From yoir_table t
Where not exists
(Select 1 from your_table tt
Where t.customer_id = tt.custome_id
And tt.order_date > t.order_date)
You can do it with a subquery that finds the last order date.
SELECT t.*
FROM yoir_table t
JOIN (SELECT tt.custome_id,
MAX(tt.order_date) MaxOrderDate
FROM yoir_table tt
GROUP BY tt.custome_id) AS tt
ON t.custome_id = tt.custome_id
AND t.order_date = tt.MaxOrderDate

SQL query to get first and last of a sequence

With the following query ...
select aa.trip_id, aa.arrival_time, aa.departure_time, aa.stop_sequence, aa.stop_id, bb.stop_name
from OeBB_Stop_Times aa
left join OeBB_Stops bb on aa.stop_id = bb.stop_id
I get the following table:
Now I want the first and last line/value from the column stop_sequence referring to column trip_id, so the result should be:
How can I do that?
Thanks
You can do a sub-query to get the min and max and join against that data.
Like this:
select aa.trip_id, aa.arrival_time, aa.departure_time, aa.stop_sequence, aa.stop_id, bb.stop_name
from OeBB_Stop_Times aa
join (
SELECT trip_id, max(stop_sequence) as max_stop, min(stop_sequence) as min_stop
FROM OeBB_Stop_Times
GROUP BY trip_di
) sub on aa.trip_id = sub.trip_id AND (aa.stop_sequence = sub.max_stop or aa.stop_sequence = sub.min_stop)
left join OeBB_Stops bb on aa.stop_id = bb.stop_id
You can use the ROW_NUMBER() window function twice to filter out rows, as in:
select *
from (
select *,
row_number() over(partition by trip_id order by arrival_time) as rn,
row_number() over(partition by trip_id order by arrival_time desc) as rnr
from OeBB_Stop_Times
) x
where rn = 1 or rnr = 1
order by trip_id, arrival_time
You can use row_number():
select s.*
from (select st.trip_id, st.arrival_time, st.departure_time,
st.stop_sequence, st.stop_id, s.stop_name,
row_number() over (partition by st.trip_id order by st.stop_sequence) as seqnum_asc,
row_number() over (partition by st.trip_id order by st.stop_sequence desc) as seqnum_desc
from OeBB_Stop_Times st left join
OeBB_Stops s
on st.stop_id = s.stop_id
) s
where 1 in (seqnum_asc, seqnum_desc);
Note that I fixed the table aliases so they are meaningful rather than arbitrary letters.
Actually, if the stop_sequence is guaranteed to start at 1, this is a bit simpler:
select s.*
from (select st.trip_id, st.arrival_time, st.departure_time,
st.stop_sequence, st.stop_id, s.stop_name,
max(stop_sequence) over (partition by st.trip_id) as max_stop_sequence
from OeBB_Stop_Times st left join
OeBB_Stops s
on st.stop_id = s.stop_id
) s
where stop_sequence in (1, max_stop_sequence);

Sql query to fetch second latest entry from a table

I have a table with below mentioned columns. I want to fetch the previous status of customer. Once customer id can have multiple entries
Customer_id status start_date end_date Active
1 Member 01-JAN-18 04-FEB-18 N
1 Explorist 05-FEB-18 30-APR-18 N
1 Globalist 01-MAY-18 31-DEC-99 Y
Desired output
Customer _id Previous_status end_date
1 Explorist 30-APR-18
Please try below query using QUALIFY keyword and ROW_NUMBER():
SELECT a.* from table a
QUALIFY ROW_NUMBER OVER(PARTITION BY customer_id order by start_date desc) = 2
Below query should work.
SELECT * from (
SELECT a.*,
ROW_NUMBER() over (partition by customer_id order by start_date desc) rn
from table a )
where rn =2
You can use below query and I guess that is very simple and that worked for me,
select * from customer order by end_date desc limit 1,1
Consider this question: Select Nth Row From A Table In Oracle
In your case, that would be:
select * from (select a.*, rownum rnum from (select * from <your table name>
order by <start_date or end_date> desc) a where rownum <= 2) where rnum >= 2;
If you are using Oracle DataBase then try below query using ROW_NUMBER() function:Let's consider the table name is customer
SELECT TEMP.CUSTOMER_ID
,TEMP.STATUS
,TEMP.START_DATE
,TEMP.END_DATE
,TEMP.ACTIVE
FROM(
SELECT ROW_NUMBER() OVER (PARTITION BY CUSTOMER_ID ORDER BY CUSTOMER_ID ASC,START_DATE DESC) AS "ROW_NUM"
,CUSTOMER_ID
,STATUS
,START_DATE
,END_DATE
,ACTIVE
FROM CUSTOMER) TEMP
WHERE TEMP."ROW_NUM" = 2;

SQL Return MAX Values from Multiple Rows

I have tried many solutions and nothing seems to work. I am trying to return the MAX status date for a project. If that project has multiple items on the same date, then I need to return the MAX ID. So far I have tried this:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT MAX(PRJSTAT_PRJA_ID) as MaxID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = MaxID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
It returns the following:
I am getting multiple records for PRJSTAT_PRJA_ID, but I only want to return the row with the MAX PRJSTAT_ID. Any thoughts?
Take out the MAX on the ID on the subquery:
SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE
From Project_Status
JOIN
(SELECT PRJSTAT_PRJA_ID as ID, MAX(PRJSTAT_DATE) as MaxDate
FROM Project_Status
Group by PRJSTAT_PRJA_ID)
On
PRJSTAT_PRJA_ID = ID and PRJSTAT_DATE = MaxDate
Order by PRJSTAT_PRJA_ID
Or remove the need to join:
SELECT * FROM
(SELECT PRJSTAT_ID, PRJSTAT_PRJA_ID, PRJSTAT_STATUS, PRJSTAT_DATE,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_DATE DESC)
AS SEQ,
ROW_NUMBER() OVER (PARTITION BY PRJSTAT_PRJA_ID ORDER BY PRJSTAT_PRJA_ID
DESC) AS IDSEQ
From Project_Status
)PR
WHERE SEQ = 1
AND IDSEQ = 1
Your problem is ties. You want the record with the maximum date per PRJSTAT_PRJA_ID and in case of a tie the record with the highest ID. The easiest way to rank records per group and only keep the best record is ROW_NUMBER:
select prjstat_id, prjstat_prja_id, prjstat_status, prjstat_date
from
(
select
project_status.*,
row_number() over (partition by prjstat_prja_id
order by prjstat_date desc, prjstat_id desc) as rn
from project_status
)
where rn = 1
order by prjstat_prja_id;

Group by clause with min

I am having the following table
I used following query and i got error message. I can identify why the error is but how can i solve it
select min(id),customer_id,created_at from thunderbolt_orders
group by customer_id
I need the minimum id's customer_id and created_at how can i achieve it.
select distinct on (customer_id)
customer_id, id, created_at
from thunderbolt_orders
order by customer_id, id
with cte as (
select
*, row_number() over(partition by customer_id order by id) as row_num
from Table1
)
select *
from cte
where row_num = 1
SELECT id,customer_id,created_at
FROM thunderbolt_orders
WHERE id IN
(SELECT MIN(id) FROM thunderbolt_orders GROUP BY customer_id);
Depending on whether or not you just want the minimum ID or whether you want the minimum ID for each customer these are the solutions.
Minimum ID:
select top 1 id,customer_id,created_at from thunderbolt_orders order by id asc
Minimum ID for each customer:
with cte as (
select min(id) as id
from thunderbolt_orders
group by customer_id
)
select *
from cte c
inner join thunderbolt_orders t on t.id = c.id