PostgreSQL to find midpoint between two timestamps - sql-server

I'm converting something from SQL Server to PostgreSQL. There's a table with a
calculated field between a BeginTime and an EndTime called MidTime. The times are offsets from the beginning of a video clip and will never be more than about 6 minutes long. In SQL Server, BeginTime, EndTime, and MidTime are all TimeSpans. You can use this as the function:
DATEADD(ms, DATEDIFF(ms,BeginTime, EndTime)/2, BeginTime)
Which is taking the difference in the two timespans in millseconds, dividing it by 2, and then adding it to the BeginTime. Super straightforward. Result looks like this:
ID BeginTime EndTime MidTime
10137 00:00:05.0000000 00:00:07.0000000 00:00:06.0000000
10138 00:00:08.5000000 00:00:09.6660000 00:00:09.0830000
10139 00:00:12.1660000 00:00:13.4000000 00:00:12.7830000
10140 00:00:14.6000000 00:00:15.7660000 00:00:15.1830000
10141 00:00:17.1330000 00:00:18.3000000 00:00:17.7160000
10142 00:00:19.3330000 00:00:21.5000000 00:00:20.4160000
10143 00:00:23.4000000 00:00:25.4000000 00:00:24.4000000
10144 00:00:25.4330000 00:00:26.8330000 00:00:26.1330000
I've looked at all of the different things available to me in PostgreSQL and don't see anything like this. I'm storing BeginTime and EndTime as "time without time zone" time(6) values, and they look right in the database. I can subtract these from each other, but I can't get the value in milliseconds to halve (division of times is not allowed) and then there's no obvious way to add the milliseconds back into the BeginTime.
I've looked at EXTRACT which when you ask for milliseconds gives you the value of second and milliseconds, but just that part of the time. I can't seem to get a representation of the time that I can subtract, divide, and then add the result back into another time.
I'm using Postgres 9.4 and I don't see any simple way of doing this without breaking the date into component parts and getting overall milliseconds (seems like it would work but I don't want to do such an ugly thing if I don't need to), or converting everything to a unix datetime and then doing the calculations and then it's not obvious how to get it back into a "time without time zone."
I'm hoping there's something elegant that I'm just missing? Or maybe a better way to store these where this work is easier? I am only interested in the time part so time(6) seemed closest to Sql Server's TimeSpan.

Just subtract one from the other divide it by two and add it to begintime:
begintime + (endtime - begintime)/2
It is correct that you can't divide a time value. But the result of endtime - begintime is not a time but an interval. And you can divide an interval by 2.
The above expression works with time, timestamp or interval columns.

Related

What is the fastest way to get only time part of datetime

My problem is that we are using Datetime column in our database but we need to show our date in different calendar like Hijri or Shamsi With the Time.
So with complex query cost of conversion is very high and i need an efficient way to get Time and concatenate it with the converted date part.
Right now i am using these approaches
1-
CONCAT(dbo.getShamsiDate( JI.Job_start_execution_date ),' ',FORMAT(JI.Job_start_execution_date,'HH:mm:s')) AS [JobStart]
JobStart
1399/05/13 19:25:47
2-
SELECT CONVERT(VARCHAR(10), #Job_start_execution_date , 108) JobStart;
JobStart
----------
14:43:35
My question is this:
Which one is faster or be suited and is there any faster way?
Just cast/convert it to a time, as that retain the correct typing (it's still a date and time data type):
SELECT CONVERT(time(0),datetimevalue), CAST(datetimevalue AS time(3))
As the value is a datetime, the value will be accurate to 1/300th of a second, however, choose a precision appropriate for your data.

Limiting datediff by Hours and Days

Long time lurker and now i have my first question:
I'm designing a SQL Report. One Task is to calculate the amount of minutes between two Times. They can be the same day or on different days. In the Database there are 4 Columns given
The Start Date (as Datetime e.g. 24.10.2017 00:00:00)
The Start Time (as Datetime e.g. 01.01.1899 11:25:00)
The End Date (formated as above)
The End Time (formated as above)
I'm calculating three Filds, all in Minutes
Days between: =DateDiff("n", Fields!StartDatum.Value,Fields!QualDatum.Value)
Minutes between: =DateDiff("n",Fields!StartZeit.Value,Fields!QualZeit.Value)
Adding those up: =Fields!QualiZeitTage.Value+Fields!QualiZeitMinuten.Value
All of this is working great and produces the desired output.
My Problem is, that i don't need the full time between those events. I only want to count minutes that are between 7:00 am and 8:00 pm. Also, i want to exclude Saturdays and Sundays. How would i go about limiting the datediff function to my desired times?
Second Problem: The Endtime and Date are only written when the event actually is finished. If it's still ongoing those Fields are empty producing a negative number (-1060764480 for example). Since i'm only using those to produce Boolean output on surpassing a certain length, it's no problem. I would like to handle that more "cleanly" though. Any thoughts?

Tableau – Using Nested Aggregations to Establish a Weekday/Hour Baseline

Background Information: We have an incident time tracker that tracks how long each user spends with a representative before the issue can be closed. We want to determine the average volume of incidents that are being handled for each hour. To say this in another way: We want to get an hourly baseline for each day of the week that will show us the average total call length within the specific time period. Eg: We want to average the total length of every call on Monday from 9AM-10AM for all the weeks in the database, and the same for other hourly intervals.
The simplest way to think of this is that I want AVG(SUM) for the specific time periods, but Tableau does not allow me to do this.
Tableau Output:
This is the desired, target visualization that I am looking for from Tableau.
SQL Query:
I have written a SQL query that returns the answer:
We are looking at two columns: start_time (time stamp) and interval_seconds(float)
In the inner query I use the hour_start function which truncates the date/time value to the hour start, so I can group by the hour and day of the week in the outer query.
SQL Results:
Question:
Is there a way to solve this problem ENTIRELY in Tableau that would get me the result that I am looking for without having to write any SQL code?
Files Stored on Drive
CSV File:
https://drive.google.com/open?id=0B4nMLxIVTDc7NEtqWlpHdVozRXc
Tableau Worksheet:
https://drive.google.com/open?id=0B4nMLxIVTDc7M3A4Q0JxbGdlTE0
You can use Level of Detail expressions to compute the SUM(interval_seconds) at the hour level and then use AVG to calculate the number you are looking for.
I created a couple of calculations:
hour which is defined as: DATETRUNC('hour',[start_time])
this should be equivalent to your hour_start(start_time).
and interval_hours which is defined as {FIXED [hour] : SUM([interval_seconds])/3600 }
This calculates the aggregate for each start_time truncated to the hour.
After this, you simply calculate AVG(interval_hours) and use it in your view.
I put a workbook in dropbox: https://www.dropbox.com/s/3hfvz8w529g9f46/Interval%20Time%20Baseline.twbx?dl=0
Although the chart looks similar to yours, the numbers I came up with are somewhat different from the "SQL Results" you show. Was the data you provided slightly different?

How does NOW/DAY in a Solr query work?

I am trying to figure out why Solr thinks an doc is in the past. My query is set up to use
published:[* TO NOW/DAY]
The doc I am hoping it will find has a published date of
2012-04-30T04:00:00Z
Current Solr server time is Mon Apr 30 18:26:47 EDT 2012. My understanding says that the document should have been found by now, which makes me think the NOW/DAY doesn't work the way I think it does. Does anybody know how the NOW/DAY evaluates dates and why when Solr is not finding my doc when I add that stipulation?
NOW/DAY means take the actual date time and round it to the day (leaving out the time). Of course if the actual date is 2012-04-30, any hour, the result is 2012-04-30T00:00:00Z.
Try just using NOW. I suspect that NOW/DAY is equal to 2012-04-30T00:00:00Z.
NOW/DAY rounds down to midnight last night. If you want the midnight of current day change with NOW+1DAY/DAY.
Date Math Syntax
Date math expressions consist either adding some
quantity of time in a specified unit, or rounding the current time by
a specified unit. expressions can be chained and are evaluated left to
right.
For example: this represents a point in time two months from
now:
NOW+2MONTHS
This is one day ago:
NOW-1DAY
A slash is used to indicate rounding. This represents the beginning of the current hour:
NOW/HOUR
The following example computes (with millisecond precision)
the point in time six months and three days into the future and then
rounds that time to the beginning of that day:
NOW+6MONTHS+3DAYS/DAY
Note that while date math is most commonly used relative to NOW it can
be applied to any fixed moment in time as well:
1972-05-20T17:33:18.772Z+6MONTHS+3DAYS/DAY
Quoted from Apache Solr Reference Guide - Working with Dates

SqlDateTime overflow Exception

I am trying to insert a time only value, but get the following error
ex {"SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM."} System.Exception
From the front end, the time is selected using the "TimeEdit" control, with the up and down arrows. The table in SQL Server has the fields set as smalldatetime. I only need to store the time. I use the following to return data to the app
select id,CONVERT(CHAR(5),timeFrom,8)as timeFrom,CONVERT(CHAR(5),timeTo,8)as timeTo
FROM dbo.Availability
where id = #id
and dayName = #weekday
How do I pass time only to the table?
Edit ~ Solution
As per Euardo and Chris, my solution was to pass a datetime string instead of a time only string. I formatted my result as per Time Format using "g".
Thanks
You can set the date to 1/1/1753 wich is date min value for datetime in MSSQL and then add the hour you want to store. Of course you have to consider this every time you need to get the value, but you can wrap that with some helpers.
Or you can use MSSQL 2008 and use the new TIME datatype.
Pick a date that is in the range(ie, 1/1/1970) and use it for everything you insert.
If you are only keeping track of the time, think about storing it in an int as an offset from midnight in whatever granualarity you need (seconds, minutes, hours, ...). You can then convert it to a TimeSpan in your code using the appropriate TimeSpan.From??() method. To go back the other way, you can use TimeSpan.Total?? and truncate if need be. If you need to do manual queries you can write a SQL function that will convert hours/mins/seconds to the equivalent offset.
I prefer this over using a datetime and picking an arbitrary day as it makes the purpose of the field clearer, which reduces confusion.
there is no such thing as Time in SQL, there is only DateTime.
For your purpose, I would use something like this to only return the time portion.
SELECT (GETDATE() - (CAST(FLOOR(CAST(GETDATE() as FLOAT)) AS DateTime)))
where GETDATE() is the datetime you want to filter.
When setting the time in the database, you will have to add '01/01/1901' or '01/01/1753' to the time.
Dont use CAST and Convert to varchar when working with datetime, its slow. Stick to floating numerical operations.

Resources