Get account information based on last login time - sql

I have this query
SELECT
c.* ,concat ( s.FirstName,'',s.LastName) as FullName
FROM [dbo].[Monitor] c
left join acc.Staff s on s.Id = c.UserId where c.UserId=1
Results:
enter image description here
How to get account information based on last login time in SQL Server.
I don't know how to get account information based on last login time.

From what I understand you want to query the very last login.
SELECT TOP 1 * FROM Monitor m Join Staff s on s.Id = m.UserId
WHERE Object = 'Login' ORDER BY AccessDate Desc
Here is an explanation of the code.
SELECT TOP 1 * FROM Monitor m
The code above is going to query only 1 result (TOP 1) and show all the columns (*) from the table Monitor. If you wish to get only specific columns, you can change * to whatever columns needed. I've given the table Monitor the alias m, because the word starts with that letter, but you can name your alias however you please, for as long as you remember it, or it's easy to realize what column it refers to.
Join Staff s ON s.Id = m.UserID
I've used Join, because you haven't really specified what exact result you are expecting, your question is more about getting the last login, so whatever join is used depends on your expectations. The same goes with the columns I've joined the two tables on. I just copied yours, but they would depend on demanded result and obviously if you have a foreign key in any of the tables, then use that key to join them.
WHERE Object = 'Login' ORDER BY AccessDate DESC
This is the important part of the code for your question. By specifying that we only need rows WHERE the column Object has value of 'Login', we are making sure that only Logins, are shown and all the Logouts are excluded. With ORDER BY AccessDate DESC, we are making sure that the biggest date value is at the top. The way dates work in SQL Server, if you compare two dates, the later date is considered bigger, so the last login would be at the very top, and since we have SELECT TOP 1 at the beginning we are making sure that we are going to get only the very last row.

Related

Query build to find records where all of a series of records have a value

Let me explain a little bit about what I am trying to do because I dont even know the vocab to use to ask. I have an Access 2016 database that records staff QA data. When a staff member misses a QA we assign a job aid that explains the process and they can optionally send back a worksheet showing they learned about what was missed. If they do all of these ina 3 month period they get a credit on their QA score. So I have a series of records all of whom have a date we assigned the work(RA1) and MAY have a work returned date(RC1).
In the below image "lavalleer" has earned the credit because both of her sheets got returned. "maduncn" Did not earn the credit because he didn't do one.
I want to create a query that returns to me only the people that are like "lavalleer". I tried hitting google and searched here and access.programmers.co.uk but I'm only coming up with instructions to use Not null statements. That wouldn't work for me because if I did a IS Not Null on "maduncn" I would get the 4 records but it would exclude the null.
What I need to do is build a query where I can see staff that have dates in ALL of their RC1 fields. If any of their RC1 fields are blank I dont want them to return.
Consider:
SELECT * FROM tablename WHERE NOT UserLogin IN (SELECT UserLogin FROM tablename WHERE RCI IS NULL);
You could use a not exists clause with a correlated subquery, e.g.
select t.* from YourTable t where not exists
(select 1 from YourTable u where t.userlogin = u.userlogin and u.rc1 is null)
Here, select 1 is used purely for optimisation - we don't care what the query returns, just that it has records (or doesn't have records).
Or, you could use a left join to exclude those users for which there is a null rc1 record, e.g.:
select t.* from YourTable t left join
(select u.userlogin from YourTable u where u.rc1 is null) v on t.userlogin = v.userlogin
where v.userlogin is null
In all of the above, change all occurrences of YourTable to the name of your table.

Sum column total based on criteria sql

I am not even sure if I am asking this question correctly. Algorithmically I know what I want to do, but don't know the appropriate syntax in SQL.
I have created a table that contains total online session times by customer number, IP, session start time, and total session length. Here is an example of what this table looks like(ip and CustNo is masked, also not sure how to make tables so excuse the weirdness):
CustNo minDate maxDate ClientIp timeDiff
123456 2017-11-14-02:39:27.093 2017-11-14-02:39:59.213 1.1.1.1 0.000372
I then create another table looking for a specific type of activity and want to know how long this specific user has used that IP for before this specific activity. The second table contains each activity as a separate row, customerID, IP and a timestamp.
Up to here no issue and the tables look fine.
I now need to write the part that will look into the first table based on customer ID and IP, then sum all usage of that IP for that customer as long as session min start time is less than the activity time but I have no idea how to do this. Here is the current function (not working obviously). I am doing a left join because it is possible this will be a new IP and it may not be in the first table.
SELECT
*,
SUM(##finalSessionSums.timeDiff)
FROM
##allTransfersToDiffReceip
LEFT JOIN
##finalSessionSums ON ##allTransfersToDiffReceip.CustNo = ##finalSessionSums.CustNo
AND ##allTransfersToDiffReceip.ClientIp = ##finalSessionSums.ClientIp
AND ##allTransfersToDiffReceip.[DateTime] < ##finalSessionSums.minDate
I get an aggregate function error here but I don't know how to approach this at all.
You have a SELECT * (return all columns) and an aggregate function (In this case SUM). Whenever you combine specific columns for return alongside aggregate, summarised values you need to stipulate each column specified in the SELECT clause in the GROUP BY clause. For example
SELECT
A, B, SUM(C) as CSum
FROM
Table
GROUP BY
A, B
In cause of the few information, I can't provide a perfect solution, but I'll give it a try:
First, like Alan mentioned, you have to select only columns that you need for your aggregate-function, which is CustomerNo and Ip. To get the sums of the query, you have to group it like this:
SELECT sum(s.timeDiff) as Sum, s.custNo, s.Ip
FROM ##finalSessionSums s
INNER JOIN ##allTransfersToDiffReceip a on a.CustNo = s.CustNo
AND a.ClientIp = s.ClientIp
AND a.[DateTime] < s.minDate
GROUP BY s.custNo, s.Ip;

SQL - Where Field has Changed Over Time

I'm running SQL server management studio and my table/dataset contains approximately 700K rows. The table is a list of accounts each month. So at the begining of each month, a snapshot is taken of all the accounts (and who owns them), etc. etc. etc. and that is used to update the data-set. The 2 fields in question are AccountID and Rep (and I guess you could say month). This query really should be pretty easy but TBH, I have to move-on to other things so I thought I'd throw it up here to get some help.
Essentially, I need to extract distinct AccountIDs that at some point changed reps. See a screenshot below of what I'm thinking:
Thoughts?
--- I should note for instance that AccountID ABC1159 is not included in the results b/c it appears only once and is never handled by any other rep.
--- Also, another parameter is if the first time an account appears and the rep name appears in a certain list and then moves to another rep, that's fine. For instance, if the first instance of a Rep was say "Friendly Account Manager" or "Support Specialist" and then moves to another name, those can be excluded from the result field. So we essentially need a where statement or something that eliminates those results if the first instance appears in this list, then there is an instance where the name changed but non after that. The goal is to see if after the rep received a human rep (so they didn't have a name in that list), did they then change human reps at a certain point in time.
Try this:
SELECT t.AccountID
FROM [table] t
WHERE NOT EXISTS(SELECT * FROM [reps table] r WHERE r.Rep = t.Rep AND r.[is not human])
GROUP BY t.AccountID
HAVING COUNT(DISTINCT t.Rep) > 1;
You want to first isolate the distinct AccountID and Rep combinations, then you want to use GROUP BY and HAVING to find AccountID values that have multiple Rep values:
SELECT AccountID
FROM (SELECT DISTINCT AccountID, Rep
FROM YourTable
WHERE Rep NOT IN ('Support Specialist','Friendly Account Manager')
)sub
GROUP BY AccountID
HAVING COUNT(*) > 1
Try a SELECT DISTINCT on the table and join the table to itself - something like this - with Account being the name I gave your table:
SELECT DISTINCT A1.AccountID, A1.Rep, A1.ReportMonth
FROM AccountTable.AccountID A1
INNER JOIN AccountTable A2
ON A1.AccountID = A2.AccountID
AND A1.Rep <> A2.Rep
ORDER BY A1.AccountD

SQL Stored procedure

I have 3 tables:
tbl_Image from which a list of all images will be obtained
A user table from which User ID will be obtained
and an association table of Image and Member called tbl_MemberAssociation.
My work flow is that a user can upload image and this will be stored in to image table. Then all users can view this image and select one of three choice provided along with the image. If user selects an option it will be added to Association table. No user can watch same image more than once. So multiple entries will not be there.
Now I want to find the % of match by getting the list of members choose the same option and different option corresponding to all common images for which they have provided their option.
I.e. say if 3 users say A, B and C view an image of tajmahal. If A and B opted beautiful as choice and C as "Not Good ". For another image say Indian Flag A B and C opted same as Salute. Then for User A: B have 100 % match (since they selected same option both times). For A : C have 50% match one among 2 same.
So this is my scenario, in which I have to find all matched corresponding to currently logged in User.
Please help me.... I am totally disturbed with this procedure.
I have made some assumptions about the actual structure of your tables, but if I understand what you are looking for then I think this query will get the results you are wanting. You may have to make a few modifications to match your table structures.
SELECT
matches.UserName,
CAST(matches.SameRatings AS FLOAT) / CAST(ratings.UserRatingCount AS FLOAT) AS MatchPercent
FROM
tbl_User
CROSS APPLY
(
SELECT
COUNT(*) UserRatingCount
FROM
tbl_MemberAssociation
WHERE
UserId = tbl_User.UserId
) ratings
CROSS APPLY
(
SELECT
u1.UserId,
u1.UserName,
COUNT(*) AS SameRatings
FROM
tbl_MemberAssociation ma
INNER JOIN
tbl_MemberAssociation ma1
ON
ma.ImageId = ma1.ImageId
AND ma.Rating = ma1.Rating
AND ma.UserId <> ma1.UserId
INNER JOIN
tbl_User u1
ON
ma1.userId = u1.UserId
WHERE
ma.UserId = tbl_User.UserId
GROUP BY
u1.UserId,
u1.UserName
) matches
WHERE
tbl_User.UserId = #UserId
ORDER BY
MatchPercent DESC
#UserId could be passed as an input to the stored procedure.
The 1st CROSS APPLY "ratings" is getting a count of for the total number of ratings for the logged in user.
The 2nd CROSS APPLY "matches" is getting a count of the number of like ratings for the other users in the database.
The result set uses the counts calculated by the two CROSS APPLY queries to compute the match percentage between the logged in user and the other users who have rated the same images as the logged in user.

Extract Both Counts AND Earliest Instance from my Dataset

Using Microsoft Sql 2000
I have a requirement to be able to email a monthly report that details a number of events.
(I have got the email bit sussed).
Amongst the data I need to email is a report on the number of certain courses people have attended. (so far so easy, couple of inner joins and a Count() and Im there.)
To add to that, some of the internal courses that we run have an expiry date which prompts a referesher course. I have been able to crudely get the data I need by using the sql code for part one and sticking the result set into a temp table, then by iterating over each row in that table, getting the user Id, querying the users course attendences, sorting it on date so that the earliest is at the top, and just taking the TOP 1 record.
This seems so inefficient, so is there any way I can ammend my current query so that I can also get the date of just the earliest course that the user attended?
i.e.
SELECT uName, COUNT(uId), [ not sure what would go in here] FROM UserDetails
INNER JOIN PassDates
ON PassDates.fkUser = uId)
GROUP BY uName, uId
where, for examples sake
UserDetails
uId
uName
and
PassDates
fkUser
CourseId
PassDate
Hope Ive explained this well enough for someone to help me.
To put an answer to the question..
SELECT uName, COUNT(uId), MIN(PassDate)
FROM UserDetails
INNER JOIN PassDates ON PassDates.fkUser = uId
GROUP BY uName, uId
You can turn it into a left join if you have users without any courses (yet)