Query only latest entry for each user - sql

The goal of the following query is, to check whether a user has been terminated in the system in time. So there is a table that contains information about the system termination (how and when the user has been terminated) and one with the termination date of the user. Since there are three ways to terminate a user, some users have several termination entries. In the end, I only want to see the latest entry before their termination date if they have been terminated at all. All Date fields are INT fields.
Current Query:
Select
B.TerminationApproach,
B.SystemTerminationDate,
A.UserName,
A.LastName,
A.FirstName,
A.TerminationDate,
Case
When B.SystemTerminationDate <= A.TerminationDate Then 0
Else 1
End As EvalCheck
From A
Left Join B On B.User = A.UserName
Current Result:
TerminationApproach SystemTerminationDate TerminationDate UserNAme LastName FirstName EvalCheck
No profiles 20180301 20180226 AWALL Wall Aaron 1
Locally locked 20181027 20180226 AWALL Wall Aaron 1
Deleted 20180301 20180226 AWALL Wall Aaron 1
No profiles 20180301 20180301 CBLAIR Blair Carlos 0
Locally locked 20181027 20180301 CBLAIR Blair Carlos 1
No profiles 20180301 20180301 CBLAIR Blair Carlos 0
Then there is a third table which contains user activity. I need to map the results of my first query to the user activity, to see whether the user has performed changes after in the system after his termination date. The third table looks like this:
UserID Date Activity
AWALL 20180227 Table Change
So with my example, the end result of my query should look like this:
TerminationApproach SystemTerminationDate TerminationDate UserNAme LastName FirstName EvalCheck ActivityAfterTermination
No profiles 20180301 20180226 AWALL Wall Aaron 1 Yes
No profiles 20180301 20180301 CBLAIR Blair Carlos 0 No

Your question and your query are rather disconnected. It is not clear what columns represent a user or the date you care about.
But the basic idea is:
with t as (
<your query here>
)
select t.*
from (select t.*,
row_number() over (partition by UserId order by date desc) as seqnum
from t
) t
where seqnum = 1;

Related

SQL Server Group By UserID and Pivot By DateTime

Unlike the many similar questions, I haven't yet come across one like my requirement.
I need to report when users are logging on & off. This is the data in the table. UserID is unique.
Logged
UserID
Status
202103010657
Peter
On
202103010710
Peter
Off
202103011856
Corey
On
202103011904
Corey
Off
202103011206
Peter
On
202103011211
Peter
Off
I need to "pivot" it to be:
User
Logged On
Logged Off
Peter
202103010657
202103010710
Corey
202103011856
202103011904
Peter
202103011206
202103011211
I think you need LEAD/LAG here:
SELECT
UserID AS [User],
Logged AS [Logged On],
NextLogged AS [Logged Off]
FROM (
SELECT *,
LEAD(CASE WHEN Status = 'Off' THEN Logged END) OVER
(PARTITION BY UserID ORDER BY Logged) AS NextLogged
FROM table
) t
WHERE t.Status = 'On'
Admnittedly, this will ignore cases when there are two Off statuses consecutively.

Matching 3 tables one by one and geting a final column value

I have 3 tables with the columns as example below:
Transaction Table (tran_table), which contains "Customer Number" value as:
CustomerN Date Usercode
Staff Table (staff), which contains "(staff's) Customer Number" and "PersonID" as:
CustomerN PersonID UserCode
And, staff title log (staff_history) by date which contains the info about whether a staff is active or left; "PersonID" and "Active" as
PersonID IsActive positionname StartDate EndDate UserCode
1 Yes branch Manager 01.01.2020 01.01.4570 daniel
1 Yes Sales representative 15.11.2018 31.12.2019 daniel
2 No Sales associate 01.01.2018 31.05.2020 mary
3 Yes Intern 01.01.2018 31.12.2019 josh
3 Yes Sales associate 01.01.2020 28.02.2020 josh
3 Yes Sales Representative 01.03.2020 01.01.4570 josh
I would like to get, if the customer who make a transaction is/was our staff (left or active), a column value that contains "IsActive", as "Active";"Left" or "NULL" for non-staff transactions.
I have tried this code below with no success
select b.AccountNumber, b.CustomerName ,aa.IsActive ,
(*) (select
(*) top 1 aa.positionname
(*) from staff_history
(*) where
(*) b.date between aa.StartDate and aa.EndDate
(*) and (b.username=aa.UserCode))
(*) as [Title],
from tran_table as b
left join staff_history as aa WITH (NOLOCK) ON b.UserName=aa.UserCode
left join staff  as ab WITH (NOLOCK) ON b.AccountNumber=ab.AccountNumber and ab.PersonId=aa.PersonId
where
aa.positionname is not null
order by aa.positionname
Edit #1 to DenStudent: Sure, the result with this code ise sth like:
CustomerN Date Usercode IsActive
15874 01.01.2020 josh Yes
8431 05.03.2020 mary No
55147 07.05.2020 daniel Yes
the problem here is, it matches the staff's situation who MADE the transaction instead of customer (is/was a staff or not). All usercodes belongs to a staff thus, there is no "null" value.
The result that i expect is:
CustomerN Date Usercode IsActive
15874 01.01.2020 josh Yes (1)
8431 05.03.2020 mary NULL (2)
55147 07.05.2020 daniel No (3)
(1) the customer number 15874 belongs to an active staff
(2) the customer number 8431 belongs to no a former or active staff
(3) the customer number 55147 belongs to a former staff
Edit #2 to Marc Guillot: there are tons of additional tables and columns. I wanted to short it to the ones that relevant to this query. however, yes, the date column in transaction table, matches with staff_history table to see the staff's title on the date of transaction. i have added several columns and the code (with(*) signed lines) if it works with you.
It's hard to say because I personally don't see what you are storing on staff_history. You are only storing the periods of activity ?, or you also store periods of inactivity ?, what happens with the EnDate for the current period ?, you leave it at null ?.
If you show us the content on those tables for your sample result, then we can help you better.
It seems that you are looking for something like this:
select b.AccountNumber, b.CustomerName, aa.IsActive, aa.positionname as [Title]
from tran_table as b
outer apply (select top 1 aa.positionname, IsActive
from staff_history as aa
where b.date between aa.StartDate and aa.EndDate
and b.username=aa.UserCode
order by b.StartDate desc) as aa
left join staff as ab on b.AccountNumber=ab.AccountNumber and ab.PersonId=aa.PersonId
where aa.positionname is not null
order by aa.positionname
This returns the positionname and state of activity at the day of the transaction (or null if it's not present in staff_history).
I have used outer apply, which is like a left join, but instead of using a condition you directly provide with a subquery all the records that you want to join.

SQL Server 2000: need to return record ID from a previous record in current query

I work on a help-desk and am doing some analysis of PC repair tickets.
I am needing to dump data from our call log system that returns history of tickets for issues on computers where they were recently repaired by another team. We are simply trying to improve QA on deployed machines and this data will help.
I have the query for the analysis of tickets, but I am wanting to return the ticket number of the last PC repair case.
My current query is as follows:
SELECT
CallLog.CallID,
CallLog.CustID,
Subset.Rep_num,
Subset.FirstName,
Subset.LastName,
CallLog.OpndetailCat,
CallLog.Tracker_Full,
CallLog.RecvdDate,
FROM
heatPrd.dbo.CallLog CallLog,
heatPrd.dbo.Subset Subset
WHERE
CallLog.CallID = Subset.CallID AND
CallLog.RecvdDate>='2015-10-01' AND
CallLog.OpnAreaCat='back from repair'
ORDER BY
CallLog.CallID DESC
This returns
CallID CustID Rep_num FirstName LastName OpndetailCat Tracker_Full
2182375 1234 Sarah Doe Missing Email Folde
2181831 1235 JENNIFER Doe ZOTHER
2180815 1236 123 Jason Smith ZOTHER
2180790 1237 124 DARCY Doe Wrong Proxy Config
2180787 1239 125 Jason Smith ZOTHER
I want to add a column to the query that would return something to the effect of
select max(callid)
from calllog
where calltype = 'in_for_service_pc' and custid = '1234'
where calltype = 'in_for_service_pc' resides on the CallLog table and custID would pull from the query result.
This is a lot of info so i hope my request is clear.
Disclaimer: Data resides in SQL Server 2000 so some of the newer commands may not work.
Something like this should be pretty close.
SELECT
cl.CallID,
cl.CustID,
s.Rep_num,
s.FirstName,
s.LastName,
cl.OpndetailCat,
cl.Tracker_Full,
cl.RecvdDate,
x.MaxCallID
FROM heatPrd.dbo.CallLog cl
JOIN heatPrd.dbo.Subset s ON cl.CallID = s.CallID
left join
(
select max(cl2.callid) as MaxCallID
, cl2.custid
from calllog cl2
where cl2.calltype = 'in_for_service_pc'
group by cl2.custid
) x on x.custid = cl.custid
WHERE cl.RecvdDate >= '2015-10-01' AND
cl.OpnAreaCat = 'back from repair'
ORDER BY cl.CallID DESC

SQL Oracle - display values only once per column

I'm trying to format a select statement. The assignment specifies that it has to be formatted this way.
I have a database regarding a taxi service. I have to put together a view with the company name, passenger name, and taxi number. Easy. However, the output specifies that the company name should only appear once in the output, at the top of it's own group. So I have:
CREATE VIEW TAXITRIPS(COMPANYNAME, PASSENGERNAME, TAXI#) AS
(SELECT COMPANY.NAME, BOOKING.NAME, VEHICLES.TAXI#
FROM BOOKING JOIN VEHICLES ON BOOKING.TAXI# = VEHICLES.TAXI#
RIGHT OUTER JOIN COMPANY ON VEHICLES.NAME = COMPANY.NAME);
The right outer join is so that companies with no booking recorded are still displayed. If I now run:
SELECT * FROM TAXITRIPS ORDER BY COMPANYNAME ASC;
It will give me something like
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
PREMIER CABS TIM 2169
SILVER SERVICE DAVE 18579
SILVER SERVICE TIM 18124
SILVER SERVICE AARON 18917
No result for legion cabs, all field displayed, et cetera. Assignment specification says it has to look like this.
COMPANYNAME PASSENGERNAME TAXI#
---------------------------------------------
ABC TAXIS DAVE 192
LEGION CABS
PREMIER CABS SHANE 2154
TIM 2169
SILVER SERVICE DAVE 18579
TIM 18124
AARON 18917
The company name should only be displayed on its first row. DISTINCT is not helping. Any advice?
Normally, you would do this at the application layer, because the result set relies on the ordering of the rows -- a bad thing in SQL.
But you can do it as:
SELECT (CASE WHEN ROW_NUMBER() OVER (PARTITION BY c.NAME ORDER BY v.TAXI#) = 1
THEN c.NAME
END) as CompanyName, b.NAME, v.TAXI#
FROM COMPANY c LEFT JOIN
VEHICLES v
ON v.NAME = c.NAME LEFT JOIN
BOOKING b
ON b.TAXI# = v.FLIGHT#
ORDER BY c.name, v.taxi#;
Note: I rearranged the joins to be LEFT JOINs. Most people find that easier to follow than RIGHT JOINs.

GROUP BY and aggregate function query

I am looking at making a simple leader board for a time trial. A member may perform many time trials, but I only want for their fastest result to be displayed. My table columns are as follows:
Members { ID (PK), Forename, Surname }
TimeTrials { ID (PK), MemberID, Date, Time, Distance }
An example dataset would be:
Forename | Surname | Date | Time | Distance
Bill Smith 01-01-11 1.14 100
Dave Jones 04-09-11 2.33 100
Bill Smith 02-03-11 1.1 100
My resulting answer from the example above would be:
Forename | Surname | Date | Time | Distance
Bill Smith 02-03-11 1.1 100
Dave Jones 04-09-11 2.33 100
I have this so far, but access complains that I am not using Date as part of an aggregate function:
SELECT Members.Forename, Members.Surname, Min(TimeTrials.Time) AS MinOfTime, TimeTrials.Date
FROM Members
INNER JOIN TimeTrials ON Members.ID = TimeTrials.Member
GROUP BY Members.Forename, Members.Surname, TimeTrials.Distance
HAVING TimeTrials.Distance = 100
ORDER BY MIN(TimeTrials.Time);
IF I remove the Date from the SELECT the query works (without the date). I have tried using FIRST upon the TimeTrials.Date, but that will return the first date which is normally incorrect.
Obviously putting the Date as part of the GROUP BY would not return the result set that I am after.
Make this task easier on yourself by starting with a smaller piece of the problem. First get the minimum Time from TimeTrials for each combination of MemberID and Distance.
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance;
Assuming that SQL is correct, use it in a subquery which you join back to TimeTrials again.
SELECT tt2.*
FROM
TimeTrials AS tt2
INNER JOIN
(
SELECT
tt.MemberID,
tt.Distance,
Min(tt.Time) AS MinOfTime
FROM TimeTrials AS tt
GROUP BY
tt.MemberID,
tt.Distance
) AS sub
ON
tt2.MemberID = sub.MemberID
AND tt2.Distance = sub.Distance
AND tt2.Time = sub.MinOfTime
WHERE tt2.Distance = 100
ORDER BY tt2.Time;
Finally, you can join that query to Members to get Forename and Surname. Your question shows you already know how to do that, so I'll leave it for you. :-)