Postgresql - Query to multiply time by number - sql

I'm creating a query to multiply a time by a number.
The time is the result of a query of the annual working hours of a person. The purpose is calculate the 25% then I want to multiply the time by 0.25
Example:
Time1: 100:00:00
[format H:M:s]
For this I've tried this query:
SELECT '100:00:00'::time * 0.25
PostgreSQL returns:
ERROR: the time / date value is out of range: «100: 00: 00»
LINE 2: SELECT '100: 00: 00' :: time * 0.25
The error is clear. My conversion of the time is out of range because the time object only is valid to 24 hours. In this case is working fine:
SELECT '24:00:00'::time * 0.25
Result:
"06:00:00"
Someone have any idea?

Time values are limited to 24 hours. You can do the calculation using other units. For instance, the following translates this to seconds:
select 0.25 * ( (string_to_array('100:00:00', ':'))[1]::int*60*60 +
(string_to_array('100:00:00', ':'))[2]::int*60 +
(string_to_array('100:00:00', ':'))[3]::int
) as num_seconds
Note that you also cannot represent the result as a time

You can use an INTERVAL, as in:
select interval '100 hours 0 minutes 0 seconds' * 0.25
or:
select interval '100:00:00' * 0.25
or:
select '100:00:00'::interval * 0.25
The result (for all of them):
?column?
--------
25:00:00

Related

How to take date time difference by milliseconds in Oracle

In my requirement, I need to take the difference between date time by milliseconds. its most of the time receiving correctly, but in sometimes, it shows minus value.
in my table I'm storing EXPIREDDATE as follows, to update EXPIREDDATE time by 2 hours
UPDATE nd_user_encode_keys
SET EXPIREDDATE = SYSDATE + ( 1 / 1440 * 120) -- here 120 means 2 hours
and according to my SP, above query running before the below query.
SELECT (EXPIRYDATETIME - SYSDATE) * 24 * 60 * 60 * 1000 as EXPIRYDATETIMEINMILISECONDS
My problem is most of the time result is 7200000 , but somtimes it shows minus value like this -34932000 . what could be the reason for this issue. can someone please explain.
When you have A - B, then the result can be:
0, if A = B
a positive number, if A > B
a negative number, if A < B --> that is your case
Why is expirydatetime less than sysdate and is that a valid value, I wouldn't know, but you should as it is your database, you're storing values into that table.
According to update statement you posted, and regarding the fact that sysdate won't return the same value "right now" as it did "a few moments ago", then it depends on when you ran that update.
Therefore, I presume it is about time difference between update and select.

Query using group by with steps/range over large data

I have a table that stores a sensor temperature readings every few seconds
Sample data looks like this
nId nOperationId strDeviceIp nIfIndex nValue nTimestamp
97 2 192.168.99.252 1 26502328 1593828551
158 2 192.168.99.252 1 26501704 1593828667
256 2 192.168.99.252 1 26501860 1593828788
354 2 192.168.99.250 1 26501704 1593828908
452 2 192.168.99.250 1 26501692 1593829029
I want to have the average temperature per device so I ran the following query
select strDeviceIp, AVG(CAST(nValue as bigint)) as val1
from myTable
where nOperationId = 2 and nTimestamp >= 1593828600 and nTimestamp <= 1593838600
group by strSwitchIp;
Where I can pass the time range I want.
My issue is that this gives me total average but I want steps or range
I want to achieve that instead of one line I'll get all the values in a range/step of say 5 minutes as a row.
P.S. I'm trying to show a graph.
Running the following query I get
strSwitchIp average
192.168.99.252 26501731
But I would like to get
strSwitchIp average timestamp
192.168.99.252 26201731 1593828600
192.168.99.252 26532731 1593828900
192.168.99.252 24501721 1593829200
192.168.99.252 26506531 1593829500
In this example I would like to get a row every 300 seconds, per device.
Since your nTimestamp is number of seconds, you can simply add it to the GROUP BY. Division by 300 gives you 300 second (5 minute) intervals. In SQL Server / is integer division, which discards the fractional part.
select
strSwitchIp
,AVG(CAST(nValue as bigint)) as val1
,(nTimestamp / 300) * 300 AS Timestamp
from myTable
where
nOperationId = 2 and nTimestamp >= 1593828600 and nTimestamp <= 1593838600
group by
strSwitchIp
,nTimestamp / 300
;
nTimestamp / 300 gives an integer, a number of 5-minute intervals since 1970. / discards here the fractional part.
When this number is multiplied back by 300, it becomes again the number of seconds since 1970, but "rounded" to the nearest 5-minute interval. Just as you showed in the question in the expected result.
For example:
1593828667 / 300 = 5312762.2233333333333333333333333
discard fractional part
1593828667 / 300 = 5312762
5312762 * 300 = 1593828600
So, all timestamps between 1593828600 and 1593828899 become 1593828600 and all values for these timestamps are grouped into one row and averaged.
you ca use partition like this:
select strDeviceIp, AVG(CAST(nValue as bigint)) as val1,
ROW_NUMBER() over(partition by nTimestamp order by nTimestamp desc) as ROW_NO from AmyTable) Q where q.ROW_NO%5=0
....

SQL Subtract Hours

In SQL I have one column A (float) which contains 2173.03 value. You can read this as 2173 Hours and 3 minutes.
I have another column-(B) in float which contains 2171.33 value. Same way you can read this as 2171 Hours and 33 Minutes.
In SQL I want to subtract Column B From A.
So what I need is to convert Column A's 2173 in Minutes and then want to add 3 minutes to the result.
Column A: 2173 * 60 + 03 = 1,30,383 Minutes
Column B: 2171 * 60 + 33 = 1,30,293 Minutes
Column A-B = 90 Minutes
I want the result as 1.30. How can I achieve this?
Why are you using such an arcane format? Why not just decimal minutes, where the decimals mean what decimals mean?
You can convert to decimal minutes by doing:
select (floor(cola) - (cola - floor(cola)) * 100.0 / 60)
Then do the subtraction:
select ( (floor(cola) - (cola - floor(cola)) * 100.0 / 60) -
(floor(colb) - (colb - floor(colb)) * 100.0 / 60)
)
And then to convert back, I would use a subquery:
select (floor(decimal_minutes) +
(decimal_minutes - floor(decimal_minutes) * 60.0 / 100)
)
from (select ( (floor(cola) - (cola - floor(cola)) * 100.0 / 60) -
(floor(colb) - (colb - floor(colb)) * 100.0 / 60)
) as decimal_minutes
) x
However, I would strongly advise you to change the meaning of the column to either decimal minutes or just seconds.

SQL Server DATEDIFF keeps ignoring seconds part of date

I am getting 0 on executing the following statement:
SELECT DATEDIFF(mi,'1970-01-01 00:00:00','1970-01-01 00:00:01') * CONVERT(BIGINT,60)*1000 as BidTicks
Whereas I get 6000 on executing this:
SELECT DATEDIFF(mi,'1970-01-01 00:00:00','1970-01-01 00:01:01') * CONVERT(BIGINT,60)*1000 as BidTicks
What are my options?
You need to use s or ss for your expected output .
select DATEDIFF(s,'1970-01-01 00:00:00','1970-01-01 00:00:01') * CONVERT(BIGINT,60)*1000 as BidTicks
it will prodece :
60000
To return the difference in seconds as the first argument in your query, you'll want to use seconds as the argument, which is an s:
select DATEDIFF(s,'1970-01-01 00:00:00','1970-01-01 00:01:01')
Basically, your query is asking for the number of minutes between the two. Your first query returns 0, the second returns 1.
Therefore 0 * 60 * 1000 = 0 and 1 * 60 * 1000 = 60000
Try the following:
select DATEDIFF(s,'1970-01-01 00:00:00','1970-01-01 00:01:01')
-- * convert(BIGINT,60) wasn't sure if this was necessary still
* 1000 as BidTicks
Use s or ss instead of mi
select DATEDIFF(s,'1970-01-01 00:00:00','1970-01-01 00:00:01') * CONVERT(BIGINT,60)*1000 as BidTicks
datepart | Abbreviations
------------+---------------
hour | hh
minute | mi, n
second | ss, s
millisecond | ms
microsecond | mcs
nanosecond | ns

Access query to partition data and sum each partition?

I have a query with the fields date hour and value.
It looks something like this
date hour value
xx/xx/xx 15 100
xx/xx/xx 30 122
xx/xx/xx 45 50
... 100 100
... 115 23
... ... ...
... ... ...
... 2400 400
... 15 23
Basically, date is the date, hour is the hour, and value is the value for that particular 15 minute interval. What I have been trying to figure out is a way to take each hour (so 15, 30, 45, and 100) or (1015, 1030, 1045, 1100) [As you can see hours are military-esque 1:00pm is 1300 and midnight 2400], and sum their values together. So i am looking to return something like this:
xx/xx/xx 100 372
xx/xx/xx 200 23 + (130 data) + (145 data) + (200 data)
And so on...
The table has on average around 100 days and they all start from 15 to 2400 incrementing by 15 with varying numbers for the value column.
I have thought about using a partition, group by, etc. with no real ideas how to tackle it. Essentially I have to take 4 rows (an hour), sum their values, spit out the date, hour, and summed value then repeat for every day. I am not asking for code, just some help with what i should be using since this seems like a simple problem minus the key to solving it.
Any help is greatly appreciated, Thank you!
Grouping by Hour/100 will almost get you there - subtract 1 from the hour will make 1 AM fall to 99, and get included in the grouping. This will give a query that looks like this:
SELECT Table1.Dte, Int(([tme]-1)/100) AS Hr, Sum(Table1.Val) AS TotVal
FROM Table1
GROUP BY Table1.Dte, Int(([tme]-1)/100);
I may have misremembered how you cast to int in Access, but this might work:
Select
[date],
100 * (1 + Cint(([Hour] - 1) / 100)),
Sum(Value)
From
Query
Group By
[date],
100 * (1 + Cint(([Hour] - 1) / 100))
Order By
1, 2
SELECT
DateCol,
Int(HourCol \ -100) * -100 AS Hr,
Sum(Value) AS Value
FROM
YourTable
GROUP BY
DateCol,
Int(HourCol \ -100) * -100
Or you can use ((Hr + 99) \ 100) * 100.