SQL - Create "virtual" column based on data from other columns - sql

I have a some issues with a SQL query I'm working on, I'm sorry that I don't have any work-in-progress to show because nothing that I have tried until now have worked out too well, so I am hoping that someone will be able to point me in the right direction.
Tables:
Computers:
[SN][PN][ComputerName][Model][OS][Architecture][RAM][CPU]
Logons:
[SN][Username][Timestamp]
Info:
It works this way, every time a user logs on to a computer the computer info gets updated to the computer table and the username and timestamp gets inserted to the logons table.
Result
The result I am trying to acheive is the following:
[SN][PN][ComputerName][Model][OS][Architecture][RAM][CPU]**[Primary User]**
It should be only one row for each computer
The Primary User field should be based from the 5 latest logons and being the username with the most recurrences in those 5.
So I think that wraps It up, I hope someone here is able to at least point me in the right direction as every result google have to offer now show up as red.

It's a bit RBAR but something like the following should do it.
SELECT [SN],
[PN],
[ComputerName],
[Model],
[OS],
[Architecture],
[RAM],
[CPU],
O.[Username] AS [Primary User]
FROM Computers C
OUTER APPLY (SELECT TOP 1 [Username]
FROM (SELECT TOP (5) *
FROM Logons L
WHERE L.[SN] = C.[SN]
ORDER BY [Timestamp] DESC) Last5Users
GROUP BY [Username]
ORDER BY Count(*) DESC,
Max([Timestamp]) DESC) O

Looks like you want to define a computed column. Check out this question: Creating a computed column in SQL Server 2008

Related

Get account information based on last login time

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.

Looking to display records from Table A that have more than one relationship to Table B

This sounds like a very simple query but I have never needed this calculation before. I'm using SQL Management Studio and SQL Server 2008.
I have a table ct_workers which contains individual employees and a second table cs_facilities which shows the sites that they work at.
The table ct_workers has a field person which is the primary ID for each employee and has a field facility which links the employees to cs_facilities via a field guid
I'm looking to display all workers that have 2 or more facilities.
I've though about using Excel or rownumber but surely that must be a simple efficient way of doing this?
Can anyone assist please?
Thanks,
You can use a GROUP BY with HAVING
SELECT cw.person
FROM ct_workers cw
GROUP BY cw.person
HAVING COUNT(DISTINCT cw.facility) >= 2
Your question suggests that you can use aggregation:
select w.person
from ct_workers w
group by w.person
having min(w.facility) <> max(w.facility); -- at least 2 values
However, if the person is the unique key in ct_workers, then a person can only be in one facility. So, your question would not make sense. You should actually have a junction table with one row per person and per facility.

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 Join Statement based on date range

New SQL dev here. I'm writing a call log application for our Asterisk server. In one table (CDRLogs), I have the call logs from the phone system (src, dst, calldate, duration). In another table I have (Employees) I have empName, empExt, extStartDate extEndDate). I want to join the two together on src and empExt based on who was using a particular ext on the date of the call. One user per extension in a given time frame.
For example, we have had 3 different users sitting at x100 during the month of July. In the Employees table, I have recorded the dates each of these people started and ended their use of that ext. How do I get the join to reflect that?
Thanks in advance
Perhaps something like:
SELECT A.*, B.*
FROM CDRLOGS A
INNER JOIN Employees B
ON A.SRC = B.EmpExt
AND A.CallDate between B.extStartDate and coalesce(B.extEndDate,getdate())
Please replace the * with relevant fields needed
and there may be a better way as a join on a between seems like it would possibly cause some overhead, but I can't think of a better way presently.

SQL Distinct Query

My SQL seems to be letting me down this morning. I have a table with the columns
Id, Guid,AttributeId,AttributeValue,CreationDate,Status
This stores data from a qustonnaire which has around 15 pages to it. Each time you move on to the next question (next page) in the questionnaire the entire questionnaire is persisted to the table i.e after completing the 1st question, that questions data is stored in the table, after completing the 2nd question, the 1st and 2nd question is persisted to the table meaning that know, we have two lots of the 1st qestion and one lot of the second question saved in the table.
I need to write a query that will return the latest lot of saved data for a given questionnaire (and all questionnaires). i.e. if the user got to question 13 i would want only that set of data returned.
Something like...
SELECT Q.*
FROM Questionnaire Q
INNER JOIN (
SELECT TOP 1 Guid, CreationDate
FROM Questionnaire
ORDER BY CreationDate DESC
) Q2
ON Q2.Guid = Q.Guid AND Q2.CreationDate = Q.CreationDate
...ought to do it. The join to Guid is possibly redundant - and you'll presumably need a WHERE somewhere to ensure you get the questionnaire for the particular user / session.
Maybe this does the trick...
SELECT TOP 1 * FROM Questionaire ORDER BY CreationDate DESC