Query NPS Radius SQL log for reject events - sql

I'd like to have a SQL query to find only radius reject events (type=3). The previous row is also required to know the user name that was rejected.
Data looks like this:
id
timestamp
NPS_Svr
Packet_Type
Description
User-Computer
27949
1:25:46 PM
SVR1
2
Access Accept
NULL
27948
1:25:46 PM
SVR1
1
Access Request
user1
27947
1:25:36 PM
SVR1
3
Access REJECT
NULL
27946
1:25:36 PM
SVR1
1
Access Request
user1
27945
1:25:33 PM
SVR3
2
Access Accept
NULL
27944
1:25:33 PM
SVR3
1
Access Request
user2
27943
1:25:21 PM
SVR3
3
Access REJECT
NULL
27942
1:25:21 PM
SVR3
1
Access Request
user2
select *
from accounting_data
where packet_type=3
Returns the reject rows but I also need the previous row from the same NPS Server to know the user name that was rejected.
The server is MS SQL 2014.

As I understand previous row it's
according to sort order of id columns,
So I suggest to self join by id-1
SELECT main.*,past.user_computer FROM (
select m.*,RANK() OVER (PARTITION BY nps_svr ORDER BY id ) as RnKSer
from accounting_data m
) main left join (SELECT nps_svr,RnKSer-1 as PastRnKSer,user_computer
FROM (
select m.*,RANK() OVER (PARTITION BY nps_svr ORDER BY id ) as RnKSer
from
accounting_data m
) prev ) past on main.nps_svr=past.nps_svr and RnKSer=PastRnKSer
where packet_type=3
ORDER BY 1

Related

SQL-Server-2017: Self join a table using timestamp criteria

i have a table named as events and looks like this:
timestamp | intvalue | hostname | attributes
2019-03-13 14:43:05.437| 257 | room04 | Success 000
2019-03-13 14:43:05.317| 257 | room03 | Success 000
2019-03-13 14:43:03.450| 2049 | room05 | Error 108
2019-03-13 14:43:03.393| 0 | room05 | TicketNumber=3
2019-03-13 14:43:02.347| 0 | room04 | TicketNumber=2
2019-03-13 14:43:02.257| 0 | room03 | TicketNumber=1
The above is a sample of a table containing thousands of rows like this.
I'll explain in a few words what you see in this table. The timestamp column gives the date and time of when each event happened. In the intvalue column, 257 means successful entry, 2049 means error and 0 means a ticket made a request. The hostname gives the name of the card/ticket reader that reads each ticket and the attributes column gives some details like the number of the ticket (1, 2, 3 etc) or the type of error (i.e 108 or 109) and if the event is successful.
In this situation there is a pattern that says, if a ticket requests to enter and it is valid and happened at a time like 14:43:02.257, then the message of the successful entry will be written in the database (as a new event) in 6 seconds at most (that means at 14:49:02.257 maximum) after the ticket was read by the ticket reader.
If the ticket fails to enter, then after a time margin of 100 ms the error message will be written in the database.
So in this example what i want to do is create a table like below
timestamp | intvalue | hostname | result | ticketnumber
2019-03-13 14:43:05.437| 257 | room04 | Success 000 | TicketNumber=2
2019-03-13 14:43:05.317| 257 | room03 | Success 000 | TicketNumber=1
2019-03-13 14:43:03.450| 2049 | room05 | Error 108 | TicketNumber=3
As you can see the ticket with TicketNumber=3 is matched with the result Error 108 because if you look at the initial table, they have a time margin of less than 100ms, the other two tickets are matched 1-to-1 with their respective results, because the time margin is less than 6 seconds (and over than 100ms). You can also notice, that the hostnames can help the matching, the row with the attribute of the TicketNumber=3 has a hostname of room05, just like the next row that has the attribute of Error 108.
I've been trying to self join this table or join it with a CTE. I've used cross apply and i also have tried methods using datediff but i've failed miserably and i'm stuck.
Is there anyone that can help me and show me a correct way of achieving the desired outcome?
Thank you very much for your time.
The time lags don't really seem to make a difference, unless somehow a single room could be interleaved with both success and failure messages. Assuming that two requests do not happen in a row with no intervening event, then you can use lag():
select e.*
from (select timestamp, intvalue, hostname, attributes,
lag(attributes) over (partition by hostname order by timestamp) as ticketnumber
from event
) e
where intvalue > 0
order by timestamp
OK...here is the result you asked for based on the data you provided. This is just an example of how to write a self join to get the results in your example. I hope this pushes you in the right direction.
IF OBJECT_ID('tempdb..#t') IS NOT NULL
BEGIN
DROP TABLE #t
END
CREATE TABLE #t
(
[timestamp] DATETIME,
intValue INT,
hostName VARCHAR(50),
attributes VARCHAR(50)
)
INSERT INTO #t([timestamp], intValue, hostName, attributes)
VALUES ('2019-03-13 14:43:05.437', 257, 'room04', 'Success 000'),
('2019-03-13 14:43:05.317',257, 'room03','Success 000'),
('2019-03-13 14:43:03.450',2049, 'room05','Error 108'),
('2019-03-13 14:43:03.393',0, 'room05','TicketNumber=3'),
('2019-03-13 14:43:02.347',0, 'room04','TicketNumber=2'),
('2019-03-13 14:43:02.257',0, 'room03','TicketNumber=1')
SELECT x.[timestamp], x.intValue, x.hostName, x.attributes result, y.attributes
ticketnumber
FROM (SELECT * FROM #t WHERE intValue > 0) AS x
INNER JOIN #t y
ON x.hostName = y.hostName AND y.intValue = 0
GROUP BY x.[timestamp], x.intValue, x.hostName, x.attributes, y.attributes
ORDER BY x.[timestamp] DESC
I would not try to copy this into your project and use it, this is just an example of how to use the join. I would need way more information about what you want to accomplish before posting a full blown solution as there much much better ways to produce reports for large data sets.
- Bill
Since you're using SQL 2017, you can make use of lead/lag.
with evt(timestamp,intvalue,hostname,attributes) as
(
select cast('2019-03-13 14:43:05.437' as datetime), 257 , 'room04','Success 000' union all
select cast('2019-03-13 14:43:05.317' as datetime), 257 , 'room03','Success 000' union all
select cast('2019-03-13 14:43:03.450' as datetime), 2049 , 'room05','Error 108' union all
select cast('2019-03-13 14:43:03.393' as datetime), 0 , 'room05','TicketNumber=3' union all
select cast('2019-03-13 14:43:02.347' as datetime), 0 , 'room04','TicketNumber=2' union all
select cast('2019-03-13 14:43:02.257' as datetime), 0 , 'room03','TicketNumber=1'
)
select [timestamp], intvalue, hostname, attributes, lag(attributes) over (partition by hostname order by timestamp) ticketnumber, datediff(ss,lag([timestamp]) over (partition by hostname order by timestamp), [timestamp]) lapse
from evt
order by timestamp

How do I get Contacts that have not been contacted in the last X days?

Although I have used not exists and other ways, still I'm battling to come up with a solid way to get a list on contacts that have not been contacted in the last XXX days,
Here is my query and a snapshot of the result
SELECT top 100
Todo_tbl.todo_ID,
Contact_tbl.Contact_ID, ---e.i 34
Contact_tbl.Contact_Name, ---e.i John papa
Todo_tbl.Title, ---e.i Sent him an email
Todo_tbl.StartDate ---e.i 2018-10-10 16:50:18.017
FROM
Todo_tbl INNER JOIN
Contact_tbl ON Todo_tbl.Contact_ID = Contact_tbl.Contact_ID
WHERE Todo_tbl.StartDate>60 <-- **wrong**
order by Todo_tbl.StartDate desc
todo_ID Contact_ID Contact_Name Title StartDate
646555 14755 Fox Browne Phone 2018-06-06 16:50:18.017
646553 31791 Weickl Email 2018-06-06 16:47:03.000
646551 26735 Nexp Email 2018-06-06 16:42:19.000
646550 33264 Stooo Email 2018-06-06 16:40:54.000
646548 14769 Heyuu Email 2018-06-06 16:39:19.000
646547 14738 Dakota Email 2018-06-06 16:37:49.000
646560 36720 IHelo Email 2018-06-06 16:00:00.000
Try this with left join and use condition Todo_tbl.Contact_ID is null
SELECT top 100
Todo_tbl.todo_ID,
Contact_tbl.Contact_ID,
Contact_tbl.Contact_Name, -
Todo_tbl.Title,
Todo_tbl.StartDate
FROM Contact_tbl left join
Todo_tbl on
Todo_tbl.Contact_ID = Contact_tbl.Contact_ID
WHERE Todo_tbl.StartDate< cast(GETDATE()-7 as date) and Todo_tbl.Contact_ID is null
order by Todo_tbl.StartDate
I believe you are looking for:
MySQL
...
WHERE Todo_tbl.StartDate <now() - interval 7 day
SQL Server
..
WHERE Todo_tbl.StartDate <GETDATE()-7

Compare a date with a block of dates in SQL

i tried to ready a lot of date comparisons that i found here on stackoverflow and spread into the internet but i wasn't able to find the solution.
I have the following table (Trips):
VehicleID DriverID xID CheckIn CheckOut DateHour
462 257 7 1 0 16/12/2017 20:40:00
462 257 7 0 1 19/12/2017 10:05:00
5032 3746 11 1 0 02/10/2017 07:00:00
5032 3746 11 0 1 06/10/2017 17:00:00
When my company receives a traffic ticket, i want to compare the date from the ticket with the hole block of dates from the table "Trips", each block starts with CheckIn = 1 and finishes with CheckOut = 1, so this way i will know which driver was responsable for the ticket through the DriverID.
For example: the traffic ticket date and time are: 17/12/2017 08:00:00 and the Vehicle is the one with id = 462, i'll insert this date and time in a field in our system to consult automaticaly which driver was driving that car at that moment, we won´t use the ticket table yet. Looking at my example, i know it should return DriverID = 257, but theres a lot of trips with the same vehicle and diferent drivers.....The major problem is how can i compare the Date and Hour from the Ticket with the range of dates from the trips, since i have to consider 1 trip = 2 lines in the table
Unfortunately i can't change the way this table was created, cause we need this 2 lines, CheckIn and CheckOut, separately.
Any thoughts or directions?
Thank you for your attention
select t1.VehicleID
,t1.DriverID
,t1.xID
,t1.DateHour as Checkin
,t2.DateHour as Checkout
from trips as t1 join trips as t2 --self join trips to get both start and end in a single row
on t1.VehicleID = t2.VehicleID -- add all columns
and t1.DriverID = t2.DriverID -- which define
and t1.xID = t2.xID -- a unique trip
and t1.Checkin = 1 -- start
and t2.Checkout = 1 -- end
join tickets -- now join tickets
on tickets.trafficDateHour between t1.DateHour and t2.DateHour
I didn't make sample tables, this will not run as is, but something like this should do it for you:
SELECT *
FROM tickets, trips
WHERE
trips.datehour in (
SELECT trips.datehour
FROM tickets, trips
WHERE
tickets.ticket_date < trips.datehour AND
trips.checkin = 0
) AND
tickets.ticket_date > trips.datehour AND
trips.checkin = 1
If you are running this for a specific date as described in the comment above, it will work. If you are trying to run it for a set of ticket dates all at once, you'll require recursion. Recursion is a different beast depending on your flavor of SQL.

SQL groupby having count distinct

I've got a postgres database that contains a table with IP, User, and time fields. I need a query to give me the complete set of all IPs that have only a single user active on them over a defined time period (i.e. I need to filter out IPs with multiple or no users, and should only have one row per IP). The user field contains some null values, that I can filter out. I'm using Pandas' read_sql() method to get a dataframe directly.
I can get the full dataframe of data from the defined time period easily with:
SELECT ip, user FROM table WHERE user IS NOT NULL AND time >= start AND time <= end
I can then take this data and wrangle the information I need out of it easily using pandas with groupby and filter operations. However, I would like to be able to get what I need using a single SQL query. Unfortunately, my SQL chops ain't too hot. My first attempt below isn't great; the dataframe I end up with isn't the same as when I create the dataframe manually using the original query above and some pandas wrangling.
SELECT DISTINCT ip, user FROM table WHERE user IS NOT NULL AND ip IN (SELECT ip FROM table WHERE user IS NOT NULL AND time >= start AND time <= end GROUP BY ip HAVING COUNT(DISTINCT user) = 1)
Can anyone point me in the right direction here? Thanks.
edit: I neglected to mention that there are multiple entries for each user/ip combination. The source is network authentication traffic, and users authenticate on IPs very frequently.
Sample table head:
---------------------------------
ip | user | time
---------------------------------
172.18.0.0 | jbloggs | 1531987000
172.18.0.0 | jbloggs | 1531987100
172.18.0.1 | jsmith | 1531987200
172.18.0.1 | jbloggs | 1531987300
172.18.0.2 | odin | 1531987400
If I were to query this example table for the time range 1531987000 to 1531987400 I would like the following output:
---------------------
ip | user
--------------------
172.18.0.0 | jbloggs
172.18.0.2 | odin
This should work
SELECT ip
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip
HAVING COUNT(ip) = 1
Explanation:
SELECT ip FROM table WHERE user IS NOT NULL AND time >= start AND time <= end - filtering out the nulls and time periods
...GROUP BY ip HAVING COUNT(ip) = 1 - If an ip has multiple users, the count(no. of rows with that ip) would be greater > 1.
If by "single user" you mean that there could be multiple rows with only one user, then:
SELECT ip
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip
HAVING MIN(user) = MAX(user) AND COUNT(user) = COUNT(*);
I have figured out a query that gets me what I want:
SELECT DISTINCT ip, user
FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end AND ip IN
(SELECT ip FROM table
WHERE user IS NOT NULL AND time >= start AND time <= end
GROUP BY ip HAVING COUNT(DISTINCT user) = 1)
Explanation:
The inner select gets me all IPs that have only one user across the specified time range. I then need to select the distinct ip/user pairs from the main table where the IPs are in the nested select.
It seems messy that I have to do the same filtering (of time range and non-null user fields) twice though, is there a better way to do this?

sql query condition in oracle report IF ELSE

I have The following tables:
DOCUMENT(iddoc,doctype,title,publishingdate,validTillDate)
USERS(iduser,fname,lname)
TRANSACTION(idtrans,iduser,iddoc,transdate,schedulereturndate)
I'm asked to Indicate for a given document whether it is available or not and if it is borrowed by whom, and when it should be returned. So how can i have these conditions in my query.
where my code will be like this:
if(d.validTillDate < SYSDATE){
SELECT u.iduser t.schedulereturndate
FROM USERS u, TRANSACTION t
WHERE u.iduser=t.iduser
}
SO I WANNA KNOW HOW CAN I CODE THIS IF
The query for a borrowed document would be something like this:
SELECT d.iddoc,u.iduser t.schedulereturndate,'Borrowed'
from document d,
,USERS u
,TRANSACTION t
WHERE u.iduser=t.iduser
and t.iddoc=d.iddoc
and d.validitydate<sysdate
union
SELECT d.iddoc,null,null,'Not borrowed'
from document d,
WHERE d.validitydate is null
or d.validitydate>=sysdate
Edit ) added a union for the not borrowed documents.
It's hard to understand your question for me.
If I guessed right, then:
SELECT d.iddoc, u.iduser, t.schedulereturndate
FROM
document d
LEFT JOIN transaction t ON
(d.iddoc=t.iddoc)
-- join by iddoc field
AND (SYSDATE BETWEEN t.transdate AND t.schedulereturndate)
-- I assume we need only current transactions, not past (or future?)
WHERE
(SYSDATE<=d.validTillDate)
-- I assume we need only documents whose validity date not passed yet
Assuming there are no active transactions for iddoc=1, one active transaction for iddoc=2 and two active transactions for iddoc=3, the result will look like:
iddoc | iduser | schedulereturndate
------+--------+-------------------
1 NULL NULL
2 534 2017-09-08
3 54334 2016-03-02
3 2433 2016-07-01