1

Perhaps I am making this more complicated that it really is, hopefully someone can point me in the right direction. I get pretty close this this query:

SELECT 
    Action, TimeOccurred, 
    COUNT(Action) 
FROM 
    [].[dbo].[] 
WHERE 
    Action LIKE '%Logon Failed%' 
    AND (DATEDIFF(day, TimeOccurred, GETDATE()) BETWEEN 0 AND 30) 
GROUP BY
    Action, TimeOccurred 
ORDER BY
    TimeOccurred

My problem is TimeOccurred is formatted like this: 2017-05-13 00:02:00 so right now instead of giving me all the "logon failed" events per day, I get it per hour/min/second as well.

I would like to essentially cut the hh:mm:ss off so my results are per day. Hopefully that makes sense.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • https://stackoverflow.com/questions/113045/how-to-return-the-date-part-only-from-a-sql-server-datetime-datatype – fqhv Jun 12 '17 at 18:05

1 Answers1

0

You can convert() to date to truncate the time portion of a datetime data type.

select 
    Action
  , TimeOccurred = convert(date,TimeOccurred )
  , Count(Action)
from [].[dbo].[]
where Action like '%Logon Failed%' 
  and TimeOccured >= dateadd(day,-30,dateadd(day, datediff(day, 0, getdate()), 0))
group by Action
  , convert(date,TimeOccurred)
order by TimeOccurred

For your where, you can calculate the date for 30 days ago instead of getting a datediff() and restricting that range to 0-30.


For conditional aggregation you could do something like this:

select 
    TimeOccurred    = convert(date, TimeOccurred)
  , logon_kerberos  = count (case when Action like ' %logon (kerberos)%' then 1 end)
  , logon_local_wts = count (case when Action like ' %logon (local/wts)%' then 1 end)
  , logon_ntlm      = count (case when Action like ' %logon (ntlm)%' then 1 end)
  , logon_total     = count (case when Action like ' %logon (%' then 1 end)
  , Count(Action)
from [CPTRAX_for_Windows].[dbo].[Logon_Logoff_and_Failed_Logon_Profiles]
where Action like '%Logon (%' 
  and TimeOccurred >= dateadd(day, -30, dateadd(day, datediff(day, 0, getdate()), 0))
group by convert(date, TimeOccurred)
order by TimeOccurred

You can use a Calendar or dates table for this sort of thing.

For only 152kb in memory, you can have 30 years of dates in a table with this:

/* dates table */
declare @fromdate date = '20000101';
declare @years    int  = 30;
/* 30 years, 19 used data pages ~152kb in memory, ~264kb on disk */
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
select top (datediff(day, @fromdate,dateadd(year,@years,@fromdate)))
    [Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
into dbo.Dates
from n as deka cross join n as hecto cross join n as kilo
               cross join n as tenK cross join n as hundredK
order by [Date];
create unique clustered index ix_dbo_Dates_date
  on dbo.Dates([Date]);

Without taking the actual step of creating a table, you can use it inside a common table expression with just this:

declare @fromdate date = dateadd(day  , datediff(day  , 0, getdate() )-30 , 0); 
declare @thrudate date = dateadd(day  , datediff(day  , 0, getdate() ), 0);
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
  select top (datediff(day, @fromdate, @thrudate)+1) 
      [Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
  from n as deka cross join n as hecto cross join n as kilo
                cross join n as tenK cross join n as hundredK
   order by [Date]
)
select [Date]
from dates;

Use either like so:

select 
    TimeOccurred    = d.Date
  , logon_kerberos  = count (case when Action like ' %logon (kerberos)%' then 1 end)
  , logon_local_wts = count (case when Action like ' %logon (local/wts)%' then 1 end)
  , logon_ntlm      = count (case when Action like ' %logon (ntlm)%' then 1 end)
  , logon_total     = count (case when Action like ' %logon (%' then 1 end)
  , Count(Action)
from Dates d
  left join [CPTRAX_for_Windows].[dbo].[Logon_Logoff_and_Failed_Logon_Profiles] l
    on d.Date = convert(date,l.TimeOccured)
   and l.Action like '%Logon (%' 
 where d.Date >= dateadd(day, -30, dateadd(day, datediff(day, 0, getdate()), 0))
group by d.Date
order by d.Date

Number and Calendar table reference:

SqlZim
  • 37,248
  • 6
  • 41
  • 59
  • Thank you so much for the quick easy answer. If I had multiple Actions (like %logon (kerberos)% or %logon (local/wts)% or %logon (ntlm)%) and I wanted to combine their counts into a single row what would that look like? – B.Breckenridge Jun 12 '17 at 19:05
  • Tried this: Select TimeOccurred = convert(date,TimeOccurred ), Count(Action) from [CPTRAX_for_Windows].[dbo].[Logon_Logoff_and_Failed_Logon_Profiles] where Action like '%Logon (%' and TimeOccurred >= dateadd(day,-30,dateadd(day, datediff(day, 0, getdate()), 0)) group by TimeOccurred, convert(date,TimeOccurred) order by TimeOccurred – B.Breckenridge Jun 12 '17 at 19:06
  • @B.Breckenridge Added another option to my answer for your additional question – SqlZim Jun 12 '17 at 19:20
  • I was really just trying to find the logon_total per day, this gives each day multiple rows instead of it all being on 1 row. Shouldn't the group by TimeOccurred make it so that each row was for 1 day? – B.Breckenridge Jun 12 '17 at 20:23
  • @B.Breckenridge Sorry, I meant to remove `TimeOccurred` from the `group by`. Try that. – SqlZim Jun 12 '17 at 20:31
  • I am getting really close to what I am looking for out of this, would it be difficult to force it to display a row for each date the last 30 days and just give a count of 0 for a day that doesn't exist in the DB? – B.Breckenridge Jun 12 '17 at 20:36
  • @B.Breckenridge Updated – SqlZim Jun 12 '17 at 21:03
  • You are ridiculously awesome. I am getting off work now so I will have to look at your new answers in detail, but I greatly appreciate the amount of time/effort you put into this. – B.Breckenridge Jun 12 '17 at 22:43
  • I went ahead and created the Dates table as that seemed like a good solution. I ran the final select statement you sent to work with the dates table and it returns the values I need, but only for dates that exist in the original Table. It doesn't include a row for every day the last 30 days and provide a 0 for that row under the count. – B.Breckenridge Jun 13 '17 at 15:59
  • @B.Breckenridge Move the `where l.action...` to the join statement and it should do what you want. – SqlZim Jun 13 '17 at 16:18
  • I think I made a mistake and modified your code. When I copy and pasted the exact select statement you gave me at the end of your answer it worked for the most part, I had to add 'and d.Date <= dateadd(day, 0, getdate())' to the where d.Date statement to make it stop showing every date going forward out to 2029. After that I was able to get exactly what I was looking for. Thank you so much for your help. – B.Breckenridge Jun 13 '17 at 17:05
  • @B.Breckenridge Whoops, you're right. The code above worked for the `cte` version because of the `@thrudate`, but that wasn't translated to the calendar table version where you could add `and d.Date <= convert(date,getdate())` – SqlZim Jun 13 '17 at 17:22
  • One last time, thank you for all your efforts. They certainly saved me a lot of time and taught me a few things along the way. This issue is fully resolved as I have exactly what I need now. – B.Breckenridge Jun 13 '17 at 21:08