How do I check whether the time has reached the next half hour in SQL? - sql

I know, confusing title. Let me explain:
I have a job that has multiple steps.
The job runs every 15 minutes.
One of the steps in the job is to run a check (stored procedure) to see if there are records in a temp table that is created inside that stored procedure.
If there are records, I want to send an email.
The email can only be sent between 7am and 4pm and it'll repeat every 30 minutes.
Right now, I know how to check whether something exists and it's in the right time frame:
IF (EXISTS ( SELECT 1
FROM #NewItems
WHERE DATEPART(HOUR, GETDATE()) BETWEEN 7 AND 16 ))
BEGIN
-- send email
END
So my question is, how do I do the above check AND it's the next half hour?
For example, I want to send this email at 7am, 7:30am, 8am, 8:30am, etc. until 16:00 (or 4pm).
How would I go about doing this?

You could use an audit table to keep track of the emails that you've sent. Something like:
CREATE TABLE EMAIL_AUDIT_TRAIL
(
EMAIL_SEND_TIME AS DATETIME NOT NULL,
EMAIL_SUMMARY AS VARCHAR(100)
)
A benefit of this is that you get some traceability on the server side to say when emails were sent, and maybe a short summary of what they said (like number of items or whatever).
Each time the stored procedure runs, you could round the current time to the last 30 minute interval using something like CAST(FLOOR(CAST(GETDATE() as FLOAT(53))*48)/(48) AS DATETIME) (adapted from an answer on the question T-SQL: Round to nearest 15 minute interval), and then check to see if that interval has an entry in the audit table.
If it does not, send the email (and add the appropriate entry to the audit table).
You could even use the same approach to determine if the interval was one that should have an email sent by checking whether the current time (rounded to the nearest 30 minutes) is contained within a table containing all of the times during the day that should have emails sent (so in your case, all 30 minute intervals between 7:00 and 16:00).
Obviously you'd have to include some cleanup of the audit table to make sure it doesn't grow forever as well.

Related

How to make the database delete a row after certain time on the row?

I'm doing a project about reporting situations on a map. Each report is marked by a pin on the map. The pin table has an attribute, report_time, that saves the hour in which the pin was inserted (or in which the report was made).
How can I make a function/trigger/procedure (whatever is the best option) to delete that row after 15 minutes since the report? I want something on my database that gets the report_time and deletes the row if 15 minutes have passed.
Instead of constantly deleting rows, how about just using a view?
create view v_pin as
select p.*
from pin p
where p.report_time > now() - interval '15 minute;
Anyone who uses the view will only see the most recent rows.
Then, when the database is quiescent or when you want -- say once an hour or once a day or once a week, just schedule a job to remove old rows:
delete from pin
where report_time < now() - interval '15 minute';
What is elegant about this solution is that users will never see inappropriate rows in the table, even if the job does not run as scheduled or the table is locked for updates for some reason.

Amount of overlaps per minute

I would like to make an SQL-Statement in order to find the amount of users that are using a channel by date and time. Let me give you an example:
Let's call this table Data:
Date Start End
01.01.2020 17:00 17:30
01.01.2020 17:01 17:03
01.01.2020 17:29 18:30
Data is a table that shows when an user started the connection on a channel and the time the connection was closed. A connection can be made any time, which means from 00:00 until the next day.
What I am trying to achieve is to count the maximum number of connections that were made over a big period if time. Let's say 1st February to 1st April.
My idea was to make another table with timestamps in Excel. The table would display a Timestamp for every Minute in a specific date.
Then I tried to make a statement like:
SELECT *
FROM Data,Timestamps
WHERE Timestamps.Time BETWEEN Data.Start AND Data.End.
Now logically this statement does what is supposed to do. The only problem is that it is not really performant and therefore not finishing. With the amount of timestamps and the amount of data I have to check it is not able to finish.
Could anybody help me with this problem? Any other ideas I can try or how to improve my statement?
Regards!
So why dou you create another table in Excel and not directly in MS Access and then why won't you set up the indexes of the timestamps right. That will speed it up by factors.
By the way I think that your statement will print repeat every user that happened to match your Start .. End period, so the amount of rows produced will be enormous. You shall rather try
SELECT Timestamps.Time, COUNT(*)
FROM Data,Timestamps
WHERE Timestamps.Time BETWEEN Data.Start AND Data.End
GROUP BY Timestamps.Time;
But sorry if the syntax in MS Access is different.

monitor the time taken for each entry in a sql table and notify using email if the time taken is more than 5 minutes

I have a table which contains the products details, If it is a new product the status will be 1.
Once it got purchased, the status will change to 2.
My requirement is to send mail to the owner if the product remains in status 1 for more than 5 minutes.
Help me out to proceed further, what are all the ways to do so.
Maybe you can add a field like "LastStatusChangedOn", which is a DateTime (or a DateTimeOffset if you need to keep account with different time zones).
And then just select all Products where the difference between the current time and the LastStatusChangedOn is greater than 5 minutes.
Without the exact database structure, it's impossible to give a complete sample, but something like this?
SELECT * FROM Products WHERE DateDiff(minute, LastStatusChangeOn, getdate()) > 5

How To Compare two dates, SQL/SSIS Task

So I've got a task that takes a random 20% of a table's results from the previous day to use as a control group. These results are put into a table, and then shoved into a .CSV file for use by the employer.
That works perfectly well. The only problem is, it's in a group of tasks that are often tested, which means that when the task gets repeated, more random data gets dumped into the file - meaning manual deletion of rows. I'm looking for a fix.
Because the process is run once a day, a unique key is the TransactionDateID, formatted INT (20150603). I need to check against that column to make sure that nothing has been run on that same day. The problem is exacerbated because it involves yesterday's records.
For example. In order to check todays date to see if it has been run, getDate() would be used to get today's date, then converted to INT (20150604). But I can't simply check to see if there is a numerical difference of 1, because once the month switches, a simple +1 will throw the entire thing out of whack:
(20150631) + 1 =/= (20150701)
I'm just wondering if this is going to be casting/converting back and forth because of the difference in variable types, or if there's something I can do with a BIT to add a column if the task has been completed for the day, something along those lines.
A colleague suggested using MAX(TransactionDateID) and then checking getDate() against that column.
Unfortunately, I run into a problem the following day:
Initial task run at 2015-06-04-09:30:ss:mm
2015-06-04-11:45:ss:mm etc.. > 2015-06-04-09:30:ss:mm, DO NOT RUN
2015-06-05-09:30:ss:mm etc.. > 2015-06-04-09:30:ss:mm, I want it to run ...
To convert your day to a formatted int, try this:
DECLARE #today date = getdate()
select year(#today) * 10000 + month(#today) * 100 + day(#today)

Simultaneous calls from CDR

I need to come up with an analysis of simultaneus events, when having only starttime and duration of each event.
Details
I've a standard CDR call detail record, that contains among others:
calldate (timedate of each call start
duration (int, seconds of call duration)
channel (a string)
What I need to come up with is some sort of analysys of simultaneus calls on each second, for a given timedate period. For example, a graph of simultaneous calls we had yesterday.
(The problem is the same if we have visitors logs with duration on a website and wish to obtain simultaneous clients for a group of web-pages)
What would your algoritm be?
I can iterate over records in the given period, and fill an array, where each bucket of the array corresponds to 1 second in the overall period. This works and seems to be fast, but if the timeperiod is big (say..1 year), I would need lots of memory (3600x24x365x4 bytes ~ 120MB aprox).
This is for a web-based, interactive app, so my memory footprint should be small enough.
Edit
By simultaneous, I mean all calls on a given second. Second would be my minimum unit. I cannot use something bigger (hour for example) becuse all calls during an hour do not need to be held at the same time.
I would implement this on the database. Using a GROUP BY clause with DATEPART, you could get a list of simultaneous calls for whatever time period you wanted, by second, minute, hour, whatever.
On the web side, you would only have to display the histogram that is returned by the query.
#eric-z-beard: I would really like to be able to implement this on the database. I like your proposal, and while it seems to lead to something, I dont quite fully understand it. Could you elaborate? Please recall that each call will span over several seconds, and each second need to count. If using DATEPART (or something like it on MySQL), what second should be used for the GROUP BY. See note on simultaneus.
Elaborating over this, I found a way to solve it using a temporary table. Assuming temp holds all seconds from tStart to tEnd, I could do
SELECT temp.second, count(call.id)
FROM call, temp
WHERE temp.second between (call.start and call.start + call.duration)
GROUP BY temp.second
Then, as suggested, the web app should use this as a histogram.
You can use a static Numbers table for lots of SQL tricks like this. The Numbers table simply contains integers from 0 to n for n like 10000.
Then your temp table never needs to be created, and instead is a subquery like:
SELECT StartTime + Numbers.Number AS Second
FROM Numbers
You can create table 'simultaneous_calls' with 3 fields: yyyymmdd Char(8),
day_second Number, -- second of the day,
count Number -- count of simultaneous calls
Your web service can take 'count' value from this table and make some statistics.
Simultaneous_calls table will be filled by some batch program which will be started every day after end of the day.
Assuming that you use Oracle, the batch may start a PL/SQL procedure which does the following:
Appends table with 24 * 3600 = 86400 records for each second of the day, with default 'count' value = 0.
Defines the 'day_cdrs' cursor for the query:
Select to_char(calldate, 'yyyymmdd') yyyymmdd,
(calldate - trunc(calldate)) * 24 * 3600 starting_second,
duration duration
From cdrs
Where cdrs.calldate >= Trunc(Sysdate -1)
And cdrs.calldate
Iterates the cursor to increment 'count' field for the seconds of the call:
For cdr in day_cdrs
Loop
Update simultaneos_calls
Set count = count + 1
Where yyyymmdd = cdr.yyyymmdd
And day_second Between cdr.starting_second And cdr.starting_second + cdr.duration;
End Loop;