Get record with min time difference - sql

I have an requirement where I need to get a record with min time difference with current record.
Let us assume that in a table I have insert date, group Id and Id column.
I have selected a record and not want to get another record for which difference between insert date of selected record and another record is min.
I have tried outer apply, but that query takes forever to run.
Query:
select e.id
from B.Emp t
where id = 5
outer apply (
select top 1 *
from B.Emp
where t.group_id = group_id
order by insert_time desc ) e

select * From B.Emp emp
Inner Join
(
select MAX(emp1.insert_time) maxTime, emp1.id From B.Emp emp1 group by emp1.id
) maxDateRec ON maxDateRec.id = emp.id AND maxDateRec.maxTime = emp.insert_time
where emp.id = 5
Try with this second one.

If you indeed want to find closest insert time for the selected record' group, regardless of the direction, then something like this might help:
select t.insert_date, ca.*
from B.Emp t
outer apply (
select top (1) * from B.Emp e
where e.group_id = t.group_id
and e.id != t.id
order by abs(datediff(ms, t.insert_date, e.insert_date))
) ca
where t.Id = 5;
EDIT: You will definitely need to check indexing options, though. For starters, assuming you have a clustered primary key on Id column, this should help:
create index [IX_B_Emp_GroupInsert] on B.Emp (group_id, insert_time);

This Query is not tested.
Please reply me is any error or changes needs to be done in the query.
CREATE TABLE Emp
(
group_Id INT,
ID INT,
date DATETIME
)
INSERT INTO EMP
(group_Id,ID,date)
values
(1,5,'11-Jan-2014'),
(1,5,'12-Jan-2014')
--
select ID,date from Emp t
group by
ID,
date having id = 5
and
date =
(select max(date) from Emp where id = 5)

Related

Select the newest record

I would like to run a select statement that runs and select only the newest record by Recored_timestampe field for the keys teacher_id and student_id. So any time, it runs it needs to provide only one record. how could I do it, please? The output could be without the field Recored_timestampe. Thanks
Using the window function,partitioned by teacher_id and student_id and sorting it by recorded_timestamp will give you the desired result.
select * from(select teacher_id,student_id,teacher_name,comment ,recorded_timestamp, row_number() over(partition by teacher_id,student_id order by recorded_timestamp desc)as rownum from temp0607)out1 where rownum=1
Also you may have to look at the way recorded_timestamp is stored. If it is stored as string, you can convert it into timestamp using from_unixtime(unix_timestamp(recorded_timestamp,'dd/MM/yyyy HH:mm'),'dd/MM/yyyy HH:mm')
First, arrange the record by datetime
SELECT *,RANK() OVER (PARTITION BY student_id ORDER BY Recored_timestamp desc) as ranking
FROM #temp
Then, if you want to know the newest record with student_id which is not null, then you can use OUTER APPLY to add a column which is non-NULL student_id.
OUTER APPLY (SELECT student_id
FROM #temp
WHERE #temp.teacher_id = ranktable.teacher_id
AND student_id IS NOT NULL
) AS jointable
Here is an example:
Create Table #temp
(
teacher_id int
,student_id int
,teacher_name varchar(40)
,comment varchar(100)
,Recored_timestamp datetime
)
INSERT INTO #temp
VALUES
(449,111,'lucy','Could be better','2021-05-04 07:00:00.000')
,(449,null,'lucy','smily','2021-05-11 07:00:00.000')
,(449,111,'lucy','not listening','2021-05-08 07:00:00.000')
,(448,null,'Toni','Good','2021-06-04 09:00:00.000')
,(448,222,'Toni','not doing as expected','2021-06-04 08:00:00.000')
SELECT DISTINCT teacher_id,
jointable.student_id,
teacher_name,
comment,
Recored_timestamp,
ranking
FROM
(
SELECT *,RANK() OVER (PARTITION BY teacher_id ORDER BY Recored_timestamp DESC) AS ranking
FROM #temp
) AS ranktable
OUTER APPLY (SELECT student_id
FROM #temp
WHERE #temp.teacher_id = ranktable.teacher_id
AND student_id IS NOT NULL
) AS jointable
WHERE ranking = 1 --only newest record will be extracted
Drop table #temp
You can base from this query to get the newest data.
SELECT TOP 1 * FROM tablename T1
INNER JOIN(SELECT teacher_id, Max(Recored_timestamp) as MaxDate from tablename GROUP BY teacher_id) T2 ON T2.teacher_id = T1.teacher_id AND T1.Recored_timestamp = T2.MaxDate

Write Cross Apply to select last row with condition

I'm trying to make request for SQL Table which looks like:
CREATE TABLE StudentMark (
Id int NOT NULL IDENTITY(1,1),
StudentId int NOT NULL,
Mark int
);
Is that possible to select StudentMark rows where row should be last row for each user with mark greater than 4.
I'm trying to accomplish that by doing:
SELECT *
FROM [dbo].StudentMark outer
CROSS APPLY (
SELECT TOP(1) *
FROM [dbo].StudentMark inner
WHERE inner.StudentId= outer.StudentId AND inner.Mark>4
) cApply
But that doesn't do what's needed. Could anyone help?
I am curious if something like this will actually get what you are looking for:
SELECT Data.StudentId,
Data.Id,
Data.Mark
FROM
(
SELECT ROW_NUMBER() OVER (PARTITION BY StudentMark.StudentId ORDER BY StudentMark.Id DESC) AS RowNumber,
StudentMark.StudentId,
StudentMark.Id,
StudentMark.Mark
FROM dbo.StudentMark
) AS Data
WHERE Data.RowNumber = 1
What this will do is get the row number of each and then let you filter by the row number on what is returned. I changed it to look for the first row instead of the last row, but sorted DESC, such that you will get what effectively would have been the last row entered for a student id.
Presumably, "last row" is based on id. If so:
SELECT *
FROM [dbo].StudentMark sm CROSS APPLY
(SELECT TOP (1) sm2.*
FROM [dbo].StudentMark sm2
WHERE sm2.StudentId = sm.StudentId AND sm2.Mark > 4
ORDER BY sm2.id DESC
) sm2;
EDIT:
If you only want the last row per student with Mark > 4, then use filtering:
select sm.*
from dbo.StudentMark sm
where sm.id = (select max(sm2.id)
from dbo.StudentMark sm2
where sm2.studentId = sm.studentId and sm2.Mark > 4
);
SELECT *
FROM StudentMark A
CROSS APPLY
(
SELECT TOP 1 Mark
FROM StudentMark B
WHERE A.StudentId = B.StudentId
ORDER BY StudentId
)M
WHERE M.Mark > 4

Insert into another table after fetching latest date and and performing an inner join

I have a table called "Member_Details" which has multiple records for each member_ID. For Example,
I have another table called "BMI_Data" that looks like the following.
The goal is to fetch the names of those members whose "BMI" in "Member_Details" is less than the "target_BMI" in "BMI_Data" table and insert it into a new table called "results" with "Member_ID, First_Name and BMI" as its schema.
Also, one consideration is to fetch the latest data available in the "Member_Details" for each member (based on date) and then do the comparison
The result for the above scenario would be something like this.
I tried using the following query
INSERT INTO results_table (Member_ID, First_Name, BMI)
select c.Member_ID, First_Name, BMI
from
(SELECT *, ROW_NUMBER() OVER (PARTITION BY Member_ID ORDER BY Date desc)
AS ROWNUM FROM Member_Details) x
JOIN
BMI_Data c ON x.Member_ID = c.Member_ID
where
x.BMI < c.Target_BMI
The above query doesn't fetch the latest date and simply loads all records in which member BMI is less than target_BMI.
Please help !
An alternate query might be
INSERT INTO results_table (Member_ID, First_Name, BMI)
select md2.member_ID, md2.First_Name, md2.BMI
from BMI_Data bd
inner join (select distinct md.member_ID ,md.First_Name ,(select top 1 BMI from Member_Details where member_ID = md.member_ID order by Date desc) BMI from Member_Details md) md2 on md2.member_ID = bd.member_ID
where md2.BMI < bd.Target_BMI
First you haven't specify the condition after row_numbers defined
INSERT INTO results_table (Member_ID, First_Name, BMI)
select c.Member_ID, First_Name, BMI
from (SELECT *,
ROW_NUMBER() OVER (PARTITION BY Member_ID ORDER BY Date desc) AS ROWNUM
FROM Member_Details
) x JOIN BMI_Data c
ON x.Member_ID = c.Member_ID
where x.ROWNUM = 1 and x.BMI < c.Target_BMI;
Wanted to note - there is no such date as '31-April-2018'! You might meant '1-May-2018'
In any case - it is important to make sure that when you are ordering by Date you first cast it to data type of DATE otherwise ordering is not correct. Below makes this ordering proper and in addition proposes alternative way by using ARRAY_AGG() with ORDER BY and LIMIT 1
#standardSQL
INSERT INTO results_table (Member_ID, First_Name, BMI)
SELECT * EXCEPT(Target_BMI)
FROM (
SELECT Member_ID, First_Name,
ARRAY_AGG(BMI ORDER BY PARSE_DATE('%d-%B-%Y', Date) DESC LIMIT 1)[OFFSET(0)] BMI
FROM `project.dataset.member_details`
GROUP BY Member_ID, First_Name
) d
JOIN `project.dataset.bmi_data` t
USING(Member_ID)
WHERE BMI < Target_BMI

Select MAX Value for Each ROW - Oracle Sql

I have one doubt.
I need to find what is the latest occurrence for a specific list of Customers, let's say to simplify, I need it for 3 Customers out of 100.
I need to check when it was the last time each of them got a bonus.
The table would be:
EVENT_TBL
Fields: Account ID, EVENT_DATE, BONUS ID, ....
Can you suggest a way to grab the latest (MAX) EVENT DATE (that means one row each)
I'm using SELECT...IN to specify the Account ID but not sure how to use MAX, Group BY etc etc (if ever needed).
Use the ROW_NUMBER() analytic function:
SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( PARTITION BY Account_id ORDER BY event_date DESC ) AS rn
FROM EVENT_TBL t
WHERE Account_ID IN ( 123, 456, 789 )
)
WHERE rn = 1
You can try
with AccountID_Max_EVENT_DATE as (
select AccountID, max(EVENT_DATE) MAX_D
from EVENT_TBL
group by AccountID
)
SELECT E.*
FROM EVENT_TBL E
INNER JOIN AccountID_Max_EVENT_DATE M
ON (E.AccountID = M.AccountID AND M.MAX_D = E.EVENT_DATE)

need query syntax to fetch latest by PKID after joining multiple tables

I have 3 tables:
select * from company
select * from emp_profile
select * from emp_salary_upgrade_tracker
table 1, company_pkid, company_code, company_name
table 2, emp_profile_pkid,company_fk_id, emp_number, emp_name, salary
table 3, salary_pk_id,emp_profile_fk_id,emp_number, old_salary, current salary
whenever an employee's salary is changed, its tracked in emp_salary_upgrade_tracker.
I need to write a query to fetch
company_code, emp_number, emp_name, old_salary, current salary
Here the result should have the latest entry ,ie latest salary change from emp_salary_upgrade_tracker.
After joining the tables, i need to fetch the latest from emp_salary_upgrade_tracker(order by pkid may be).
But am clueless of the query syntax. Please help
Use a subquery to get lates ids:
select c.company_code,
e.emp_number,
e.emp_name,
t.old_salary,
t.current_salary
from(select emp_profile_fk_id, max(salary_pk_id) as salary_pk_id
from emp_salary_upgrade_tracker group by emp_profile_fk_id) m
join emp_salary_upgrade_tracker t on m.salary_pk_id = t.salary_pk_id
join emp_profile e on t.emp_profile_fk_id = e.emp_profile_pk_id
join company c on e.company_fk_id = c.company_pkid
Here's a way using row_number to select the row containing the latest value in the emp_salary_upgrade_tracker table when ordered by its primary key.
select * from (
select *,
row_number() over (partition by esut.emp_number order by esut.salary_pk_id desc) rn
from emp_salary_upgrade_tracker esut
join emp_profile ep on ep.emp_profile_pk_id = esut.emp_profile_fk_id
join company c on c.company_pk_id = ep.company_fk_id
) t where rn = 1