Openedge syntax for TIME minus 4 hours - syntax

I am trying to figure out how to write a Openedge query where i can look back 4 hours. i have struggled with the TIME syntax before. If i understand correctly, the TIME representation in Openedge is in seconds starting from midnight. The query i am trying to write would run 4 times a day, looking back 4 hours.
Is there any way to do this using TIME? Maybe i have to write 4 different queries that only pull records starting at a specific time?
Thanks very much for any help i can get, it is greatly appreciated!
Martin

You don't describe the contents or layout of the table very well.
Yes, TIME, in Progress ABL contains the number of seconds since midnight. So 16:20 for instance is 58800 (16 * 3600 + 20 * 60).
Assuming the field in your table contains an integer representing the time you can do like this to select the records that was created up to four hours ago:
DEFINE VARIABLE iTime AS INTEGER NO-UNDO.
/* I find it easier to write like this but you can very well do = TIME - 14400 instead */
iTime = TIME - 4 * 3600.
FOR EACH tablename NO-LOCK WHERE tablename.createtime >= iTime:
/* Do something */
END.
Note: perhaps you need to check create date as well? And handle midnight?
Another option might be to look at the DATETIME type. There you can do operations like adding and distracting an amount of time.
DEFINE VARIABLE datnow AS DATETIME NO-UNDO.
DEFINE VARIABLE datthen AS DATETIME NO-UNDO.
datnow = NOW.
DISPLAY datnow.
datthen = ADD-INTERVAL(datnow, -4, "hours").
DISPLAY datthen.

Related

Want to make the output human readable

Hello, I am trying to run some queries but my output is not right. Could anyone please help me understand what I'm doing wrong?
I am trying to find the difference between these two DATETIME values as minutes.
SELECT TO_CHAR(booking_StartTime - booking_EndTime) AS Diff FROM Booking;
Assuming that booking_StartTime and booking_EndTime are DATE fields - when doing arithmetic using DATE values in Oracle the result is a number of DAYS. Thus, to get minutes you have to multiply by the number of minutes in a day, i.e. by 24 * 60, or 1440. Also - you probably want to subtract the start time from the end time, in order to get a positive value as the result.
SELECT TO_CHAR((booking_EndTime - booking_StartTime) * 1440) AS Diff FROM Booking;
should get you what you want.

Using Power BI Desktop, how can I present Time Duration in a matrix that converts it to decimal?

I have Begin Date and End Date in my data file (Excel), then in PowerQuery I add a column where I simply subtract the Begin Date from End Date to create a new column "Import Time", change the result's data type to Duration and in PowerQuery, the column correctly shows the difference expressed in Day:Hour:Minute:Seconds. However, in a report, I need to show the average not of an entire column, but of groups of values in a matrix based on the entire table. In other words, I'm looking for a table that shows columns for Category Name, Avg. Duration and Max Duration, with rows showing the results for each unique Category.
The problem is that when I drag a table field in to the Visualizations Value area and change to Average, it expresses the result as a decimal, and I can't figure out how to show the date / time equivalent. I thought I might have to multiply by 3,600 since the result might be shown in milliseconds, but that didn't work. Any thoughts?
So I theorized that perhaps the issue wasn't one with Power BI, but perhaps with how Microsoft expresses date / time computations. I edited my Excel file that contains the source data and computed the "Import Time" by subtracting Begin Time from End Time. By default, it displays in date / time format of "hh:mm:ss.0000". I then asked Google and came across a simple explanation: to express a date / time in numeric format, you need to multiply the date / time by 24 (hours), 60 (minutes) and 60 (seconds) if that's how you wanted to express the result. I then created a Pivot Table summarizing the average of the Import Times and saw the same thing I did in my Power BI report, which is when it clicked it for me.
To solve the issue, I edited my Power Query step to compute the import time and included " * 24 * 60 * 60" in the formula. After updating the report, the results matched what I saw in Excel and I'm good. Hopefully this helps others to deal with this vexing issue.
You wrap your averaging measure in a FORMAT function to convert it to precisely the text format you want to show in your matrix. For example, suppose your raw output is
Group AvgDuration
------------------
A 0.0633
B 0.2733
C 0.0600
These numbers are in the unit of days, so you can convert to hours, minutes, or seconds like this e.g.:
FORMAT ( [AvgDuration] * 24, "0.00h" )
FORMAT ( [AvgDuration] * 24 * 60, "#,0m" )
FORMAT ( [AvgDuration] * 24,* 60 * 60, "#,0s" )
FORMAT ( [AvgDuration], "hh:mm:ss" )
(where [AvgDuration] is your measure you use to calculate the average)
Those last two should look like this:
Group AvgDuration
------------------
A 5,472s
B 23,616s
C 5,184s
and
Group AvgDuration
------------------
A 01:31:12
B 06:33:36
C 01:26:24

Is there a data type for time format hh:mm:ss in Hive

I am processing the files that contains the call details of different users. In the data file, there is a field call_duration which contains the value in the format hh:mm:ss. eg: 00:49:39, 00:20:00 etc
I would like to calculate the the total call duration of each user per month.
I do not see a data type in hive which can stock the time format in hh:mm:ss. ( Currently I have this data as string in my staging table).
I am thinking of writing a UDF which converts the time into seconds, so that i can do a sum(call_duration) grouping by user.
Did any one face a similar situation? Should I go with writing a UDF for is there a better approach?
Thanks a lot in advance
Storing duration as an Integer number of seconds seems like the best option for efficiency and for being able to do calcuations. I don't think you need a custom UDF to convert from your String to an Int. It can be done by combining existing UDFS:
Select 3600 * hours + 60 * minutes + seconds as duration_seconds
FROM (
Select
cast(substr(duration,1,2) as Int) as hours,
cast(substr(duration,4,2) as Int) as minutes,
cast(substr(duration,7,2) as Int) as seconds
From(
Select "01:02:03" as duration) a
) b;
Hive provides built-in date functions to extract hour, minutes and seconds.
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF#LanguageManualUDF-DateFunctions
But if these functions doesn't help you directly and you use many combination of builtin function then i would suggest you to write your own UDF (in case this is very frequent utility and you run over large number of rows). You will see query performance difference.
Hope this helps

Storing recurring time periods in Oracle database

I'm writing monitoring software, where most of the logic will be in Oracle databasen & pl/sql.
When my monitoring is called it should alert about problems. For example, it should alert about problem if
1. There are less than 2 operation, in every minute, on Friday from 22:00 till 23:00
2. There are less than 5 operation, in every minute, on 31 of January from 22:00-23:00
3. There are less than 3 operation, in every minute, every day from 10:00 till 12:00
If my monitoring is called on 22:30, 31 of January I should compare my operation number to 5.
4. If there are less than 5 operation, in every minute, from Friday 22:00 till Monday 15:00
I was thinking about saving data periods with cron expression format in database. In this case I have to compare SYSDATE (current call date of monitoring function) to cron expression saved in the database.
My questions:
1. How can I find out if SYSDATE falls under cron expression?
2. Is it correct to use cron expressions in this case, at all? Can you suggest any other way of saving periods of time.
Don't do it
I am completely with SpaceTrucker: Don't do it in SQL or PL/SQL, do it in Java with either Java 8 date API or JodaTime.
How to do it nevertheless
But even when you should't do it, there might still be some good reason to do it. So here is how:
Table for each instant you want to check
First let's create a table for each second or minute in the interval you want to check. The granularity and the length of your interval depends on the cron expressions you want to allow. Usually one second for a whole week should be sufficient (about 100'000 rows). If you want to check a whole year, use minutes as granularity (about 500'000 rows). Both amount or rows are nothing for a modern database. On my notebook, according queries return instantly.
CREATE TABLE week AS
SELECT
running_second,
ts,
EXTRACT(SECOND FROM ts) as sec,
EXTRACT(MINUTE FROM ts) as min,
EXTRACT(HOUR FROM ts) as h,
to_char(ts, 'Day') as dow
FROM (
SELECT
level as running_second,
TO_TIMESTAMP_TZ('2015-09-05 00:00:00 0:00',
'YYYY-MM-DD HH24:MI:SS TZH:TZM') +
NUMTODSINTERVAL(level-1, 'SECOND') AS ts
FROM dual CONNECT BY level<=60*60*24*7
)
;
Query for each filter expression
Next, you convert each cron expression to a query. You can either use PL/SQL to transform each cron expression to a where clause, or you can use a generic where clause.
You should get something like this:
SELECT
*
FROM
week
WHERE
h =5
AND min=0
AND sec=0;
or in a generic version:
SELECT
filter_expression.name, week.ts
FROM
week, filter_expressions
WHERE
(fiter_hour is null or h = filter_hour)
AND (filter_min is null or min = filer_min)
AND (filter_sec is null or sec = filter_sec);
(given your filters are stored in a table filter_expressions, that has a column for each constraint type, and each row has either a parameter for the constraint or NULL if the constraint is not applicable).
Store the result in a global temporary table cron_startpoints.
Check for violations
Group the table cron_startpoints to check for constraint violations. You can count, how many matches are there for Friday or midnight or whatever and can check, whether that number is OK for you or not.
It depends on how much flexibility you want. For the examples you provided such structure would be enough:
CREATE TABLE monitoring_periods (
id INTEGER NOT NULL PRIMARY KEY,
monit_month VARCHAR2(2),
monit_day VARCHAR(2),
monit_day_of_week VARCHAR(3),
monit_time_from INTERVAL DAY TO SECOND,
monit_time_to INTERVAL DAY TO SECOND,
required_ops INTEGER
);
Here are some examples to store the periods and checking against sysdate. I would avoid storing the cron expression literally as a string, as it would require parsing it at query time. However, the more complex your expressions are (kind of '5 4,15,22 */2 * 1-5') the more complicated the structure to store it - you need to think carefully of your requirements.
I once had the task to write difficult date calculations with recurring periods and time windoes for 10g. Among those were things like "Tuesday of the second week of the month every 2 months between 8 AM and 2 PM". We decided to use java stored procedures for this (also because they were already in use for other purposes).
Depending on your oracle version, you can choose a joda-time version, which can be run within the oracle database jvm. Also note that joda-time 1.6 can be compiled with java 1.3 (which we had to use).
If you are looking for cron expressions explicitly, than you might also do well with using another java library within the oracle database jvm. For example here is one:
CronExpression expression = CronExpression.parser()
.withSecondsField(true)
.withOneBasedDayOfWeek(true)
.allowBothDayFields(false)
.parse("0 15 10 L * ?");
assert expression.matches(dateTime);
However i think cron is not suited for your task at hand. Cron is a way to specify when to run jobs. However you need to observe what happend. So for your requirement There are less than 2 operation, in every minute you could have operations at the 1st and 2nd second or at the 1st 31st second and both are valid, but their cron expressions are very different.
When it's about saving the time periods, you could also look at ISO 8601 recurinng intervals stored as varchars:
P1Y2M10DT2H30M
In any case you will need to apply calculations on every row you would like to match. Depending on how many lines that are, you might need to use some heuristics to sort out results which are far away from meeting your criteria.
Thinking a bit more outside the box:
you should question your architecture. The requirements you listed ca be represented by state machines. You can feed them with the events that occured in chronological order. If a state machine reaches some unwanted state you can just report that. However I doubt that this can be easily done in pure pl/sql.

Google SpreadSheet - handling MM:SS.sss time formats

I'd like to process the following columns in a google-spreadsheet. The Time column represents the minutes, second and milliseconds take to run 1km and I'd like to be able to sum the four values.
Split Time
1 3:13:4
2 3:20:5
3 3:16:1
4 3:26:3
I suspect that I need to convert and split the time column into a specific minute and second columns to achieve this goal but would appreciate any advise that the developer may have.
I updated the format of the time column and used the SPLIT / CONTINUE functions
Minutes=SPLIT(B2,":")
Seconds=CONTINUE(C2,1,2)
Total Seconds=(C2*60)+D2
The table now looks like
Split Time minutes Seconds Total Seconds
1 03:13:00 3 13 193
2 03:15:00 3 15 195
3 03:16:00 3 16 196
Still wondering about the most efficient way to convert the Total Seconds value to time.
You can use the LEFT(text, number), MID(text, start, number), and RIGHT(text, number).
In detail:
Minutes = LEFT(B2, 1)
Seconds = MID(B2, 3, 2)
Milliseconds = RIGHT(B2, 2)
You can just use SUM for those values, a la:
=SUM(A1:A4)
Alternatively, you can use functions such as HOUR, MINUTE and SECOND to extract appropriate values if you want more fine-grained control.
Where the source data is a specified (ie The Time column represents the minutes,second and milli seconds) then to be able to add to a sensible result (795.013 seconds for the first sample of four) conversion similar to:
=60*index(split(B2,":"),0,1)+index(split(B2,":"),0,2)+index(split(B2,":"),0,3)/1000
is required.
To convert the total (assumed to be in C6) to the same absurd format as for input (13:15:13):
=int(C6/60)&":"&int(mod(C6,60))&":"&value(mid(C6,find(".",C6)+1,3))
`
In your original sheet, in a new column:
=TO_DATE("00:0" & left($B2,4))
Then copy the formula down the column.
This will convert your M:SS (the left 4 characters of your data) to the sheet's system date/time format, for each entry in column B.
You can then sum and format the results as you like.
This assumes there are no leading zeroes on your data. You can add code to check for this, but if your times all have single digits for the minutes value, it won't matter.

Resources