How To Compare two dates, SQL/SSIS Task - sql

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)

Related

Query another table with results of an another query that include a csv column

Brief Summary:
I am currently trying to get a count of completed parts that fall within a specific time range, machine number, operation number, and matches the tool number.
For example:
SELECT Sequence, Serial, Operation,Machine,DateTime,value as Tool
FROM tbPartProfile
CROSS APPLY STRING_SPLIT(Tool_Used, ',')
ORDER BY DateTime desc
is running a query which pulls all the instances that a tool has been changed, I am splitting the CSV from Tool_Used column. I am doing this because there can be multiple changes during one operation.
Objective:
This is where the production count come into place. For example, record 1 has a to0l change of 36 on 12/12/2022. I will need to go back in to the table and get the amount of part completed that equals the OPERATION/MACHINE/TOOL and fall between the date range.
For example:
SELECT *
FROM tbPartProfile
WHERE Operation = 20 AND Machine = 1 AND Tool_Used LIKE '%36%'
ORDER BY DateTime desc
For example this query will give me the datetimes the tools LIKE 36 was changed. I will need to take this datetime and compare it previous query and get the sum of all parts that were ran in this TimeRange/Operation/Machine/Tool Used

How to find where a total condition exist

I am trying to create a report that will show how long an automated sprinkler system has run for. The system is comprised of several sprinklers, with each one keeping track of only itself, and then sends that information to a database. My problem is that each sprinkler has its own run time (I.E. if 5 sprinklers all ran at the same time for 10 minutes, it would report back a total run time of 50 minutes), and I want to know only the net amount of run time - in this example, it would be 10 minutes.
The database is comprised of a time stamp and a boolean, where it records the time stamp every time a sprinkler is shut on or off (its on/off state is indicated by the 1/0 of the boolean).
So, to figure out the total net time the system was on each day - whether it was 1 sprinkler running or all of them - I need to check the database for time frames where no sprinklers were turned at all (or where ANY sprinkler at all was turned on). I would think the beginning of the query would look something like
SELECT * FROM MyTable
WHERE MyBoolean = 0
AND [ ... ]
But I'm not sure what the conditional statements that would follow the AND would be like to check the time stamps.
Is there a query I can send to the database that will report back this format of information?
EDIT:
Here's the table the data is recorded to - it's literally just a name, a boolean, and a datetime of when the boolean was changed, and that's the entire database
Every time a sprinkler turns on the number of running sprinklers increments by 1, and every time one turns off the number decrements by 1. If you transform the data so you get this:
timestamp on/off
07:00:05 1
07:03:10 1
07:05:45 -1
then you have a sequence of events in order; which sprinklers they refer to is irrelevant. (I've changed the zeros to -1 for reasons that will become evident in a moment. You can do this with "(2 * value) - 1")
Now put a running total together:
select a.timestamp, (SELECT SUM(a.on_off)
FROM sprinkler_events b
WHERE b.timestamp <= a.timestamp) as run_total
from sprinkler_events a
order by a.timestamp;
where sprinkler_events is the transformed data I listed above. This will give you:
timestamp run_total
07:00:05 1
07:03:10 2
07:05:45 1
and so on. Every row in this which has a run total of zeros is a time at which all sprinklers were turned off, which I think is what you're looking for. If you need to sum the time they were on or off, you'll need to do additional processing: search for "date difference between consecutive rows" and you'll see solutions for that.
You might consider looking for whether all the sprinklers are currently off. For example:
SELECT COUNT (DISTINCT s._NAME) AS sprinkers_currently_off
FROM (
SELECT
_NAME,
_VALUE,
_TIMESTAMP,
ROW_NUMBER() OVER (PARTITION BY _NAME ORDER BY _TIMESTAMP DESC, _VALUE) AS latest_rec
FROM sprinklers
) s
WHERE
_VALUE = 0
AND latest_rec = 1
The inner query orders the records so that you can get the latest status of all the sprinklers, and the outer query counts how many are currently off. If you have 10 sprinklers you would report them all off when this query returns 10.
You could modify this by applying a date range to the inner query if you wanted to look into the past, but this should get you on the right track.

SQL Like function Broken? or Limited?

I am trying to use the LIKE function to get data with similar names. Everything looks fine but the data I get in return is missing some values when I get back more than ~20 rows of data.
I have a very basic query. I just want data that starts with Lab, ideally for the whole day, or at least 12 hours. The code below misses some data and I cannot discern a pattern for what it picks to skip.
SELECT History.TagName, DateTime, Value FROM History
WHERE History.TagName like ('Lab%')
AND Quality = 0
AND wwRetrievalMode = 'Full'
AND DateTime >= '20150811 6:00'
AND DateTime <= '20150811 18:00'
To give you an idea of the data I am pulling, I have Lab.Raw.NTU, Lab.Raw.Alk, Lab.Sett.NTU, etc. Most of the data should have values at 6am/pm, 10am/pm, and 2am/pm. Some have more, few have less, not important. When I change the query to be more specific (i.e. only 1 hour window or LIKE "Lab.Raw.NTU") I get all of my data. Currently, this will spit out data for all tags and I get both 6am data and 6pm data, but certain values will be missing such as Lab.Raw.NTU at 6pm. There seem to be other data that is missing if I change the window for the previous day or the night shift, so I don't think it has to be with the data itself. Something weird is going on with the LIKE function but I have no idea what.
Is there another way to get the tagnames that I want besides like? Such as Tagname > Lab and Tagname <= Labz? (that gives me an error, so I am thinking not)
Please help.
It appears that you are using the Like operator correctly; that could be a red herring. Check the data type of the DateTime field. If it is character based such as varchar you are doing string comparisons instead of date comparisons, which could cause unexpected results. Try doing an explicit cast to ensure they are compared as dates:
DateTime >= convert(datetime, '20150811 6:00')

How do I check whether the time has reached the next half hour in 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.

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;