I have two queries which give me different results, can someone explain why this is happening?
The first query uses the unixtime 1533624035000 which represents "07.08.2018 08:40:35" (UTC+2)
select floor((Buchungsdatum - 1533624035000) / (1000*60*60*24)) as Tag,
s.Kurztext as Buchungsstatus,
count(*) as Anzahl
from PfdBuchung b, Schluesselbegriff s
where b.Buchungsdatum >= 1533624035000 and b.SHKennung = 'H' and
b.Buchungsstatus=s.Begriff and s.Oberbegriff='Buchungsstatus' and
b.rzMandant = s.rzMandant
group by floor((Buchungsdatum - 1533624035000) / (1000*60*60*24)), s.Kurztext
order by 1,2`
Result
0 verarbeitet 21800
1 verarbeitet 23380
i have just posted the first two results here
In the 2nd query I convert the unixtimestamp to a datetime with the function POSIX_TO_TIMESTAMP which simple converts my unixts to
l_ora_timestamp := to_timestamp( '1970-01-01 02:00:00', 'yyyy-mm-dd HH24:MI:SS' ) + numtodsinterval( (ptime/1000), 'SECOND' )
select TO_CHAR(POSIX_TO_TIMESTAMP(b.Buchungsdatum), 'YYYY-MM-DD') as Tag,
s.Kurztext as Buchungsstatus, count(*) as Anzahl
from PfdBuchung b, Schluesselbegriff s
where TO_CHAR(POSIX_TO_TIMESTAMP(b.Buchungsdatum), 'YYYY-MM-DD') >= '2018-08-07' and
b.SHKennung = 'H' and
b.Buchungsstatus = s.Begriff and
s.Oberbegriff = 'Buchungsstatus' and
b.rzMandant = s.rzMandant
group by TO_CHAR(POSIX_TO_TIMESTAMP(b.Buchungsdatum), 'YYYY-MM-DD'), s.Kurztext
order by 1,2
Result:
2018-08-07 verarbeitet 15553
2018-08-08 verarbeitet 23315
The reason is pretty obvious.
Both queries count rows where the UNIX timestamp is after 06:40:35 UTC on 7 August 2018.
The first query groups into windows of 24 hours each FROM THIS POINT IN TIME. That is, the first row in the output counts input rows from 06:40:35 on 7 August till same time on 8 August, etc.
The second query counts rows grouped by CALENDAR days (UTC), from midnight to midnight.
There is no reason for the counts to match.
In the second query, you count rows for 7 August, but only input rows with timestamp after 06:40:35 are selected - this is why you only get a count of about 15k, vs. the ~20k for all (full!) 24 hour windows.
And this has nothing to do with time zone. You may be in UTC+2 yourself, but I don't see where in your calculations there is ANY regard paid to timezone.
Your function POSIX_TO_TIMESTAMP will be wrong in winter season due to daylight saving time. Better use
l_ora_timestamp := (timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(ptime/1000, 'SECOND')) AT TIME ZONE 'Europe/Berlin';
Related
I'm working with BigQuery and have a table that looks like:
YEAR
MONTH
DAY
timezone
local time
2015
6
24
America/Los Angeles
1930
Where local time is given by hhmm. I'm wondering if I can format this information into a timestamp column in SQL that yields time in UTC.
I know I can use `TO_TIMESTAMP` but that would involve concatenating all these columns as strings first. Is there any better way to do this? If I were to concatenate, I'm not sure how I would use timezone and then back out UTC.
You might consider below.
WITH sample_table AS (
SELECT 2015 year, 6 month, 24 day, 'America/Los_Angeles' timezone, 1930 local_time UNION ALL
SELECT 2015 year, 6 month, 24 day, 'America/Los_Angeles' timezone, 2400 local_time
)
SELECT TIMESTAMP_SECONDS(
UNIX_SECONDS(TIMESTAMP(DATE(year, month, day), timezone))
+ DIV(local_time, 100) * 3600 + MOD(local_time, 100) * 60
) utc
FROM sample_table;
Since TIME(24, 0, 0) is not a valid time format, the query converts datetime into unix seconds and get back to UTC with the time calculation in seconds.
Input calculates to invalid time: 24:00:00
Query results
I am working out of Oracle SQL. I have some dates that may have been poorly formatted when loading.
I'm doing a basic Max(date)-Min(Date) to get the difference in days. My results are:
+000000156 00:00:00.000000
+000000149 00:00:00.000000
+00 00:00:00.000000
I want to do some basic math with these date differences (average, etc) but I get an error message.
How do I convert these strings into numbers?
My guess is that the columns are timestamps, not dates, as the results are intervals not numbers. As you've found, Oracle have not got around to overloading the standard aggregate functions for intervals (vote for this feature on the Oracle Database Ideas forum) and currently you still have to either write your own or cast the timestamps to dates.
with demo (start_date, end_date) as
( select timestamp '2019-12-31 00:00:00', timestamp '2020-06-04 00:00:00' from dual union all
select timestamp '2020-01-31 00:00:00', timestamp '2020-06-28 00:00:00' from dual
)
select end_date - start_date as elapsed_interval
, cast(end_date as date) - cast(start_date as date) as elapsed_days
from demo;
ELAPSED_INTERVAL ELAPSED_DAYS
----------------------------- ------------
+000000156 00:00:00.000000000 156
+000000149 00:00:00.000000000 149
Basic math with dates:
date + number = date + number of days (also fractions)
SELECT SYSDATE + 1 FROM DUAL; -- tomorrow
date - number = date - number of days
SELECT SYSDATE - 1/24 FROM DUAL; -- one hour ago
date - date = numbers of days between dates (also fraction of days)
date + date = impossible
months_between(date1, date2) = returns months between two dates
add_months(date, number) = adds number (months) to date
if you have a string or number and it can be the n-th day of the year (for instance 156),
you can transform in date with TO_DATE('156', 'DDD')
if you have a string with a particular format, you can transform it in date with
TO_DATE(string, format of the date you imagine)
https://www.techonthenet.com/oracle/functions/to_date.php
if you need the opposite transform, that is transforming date to char (or number), use TO_CHAR(date, format of the date)
I have a table in postgers with schema similar to this.
id start_time end_time
1 2019-10-21 20:00:00 UTC 2019-10-21 23:00:00 UTC
2 2019-10-21 22:00:00 UTC 2019-10-22 02:00:00 UTC
I want to write a query which will give me overlapping duration in database itself.
for example: given two inputs
t1=2019-10-21 21:00:00 UTC
t2=2019-10-22 01:00:00 UTC
the query should calculate all the overlapping time between the input range
the overlapping time between input and row 1 is 2 hrs
the overlapping time between input and row 2 is 3 hrs
the result wold be 2 + 3 = 5
Sounds as if you are looking for the intersection of two tsrange values:
tsrange(start_time, end_time, '[]') * tsrange('2019-10-21 21:00:00', '2019-10-22 01:00:00', '[]')
The '[]' specifies that both edges should be included in the range. This might or might not be what you want. You will need to adjust that to your requirements.
This will return a range type. To calculate the length of the range, subtract the upper value from the lower value:
select sum(upper(diff) - lower(diff))
from (
select tsrange(start_time, end_time, '[]') * tsrange('2019-10-21 21:00:00', '2019-10-22 01:00:00', '[]') as diff
from the_table
) t
This returns an interval representing the sum of all overlap.
If your column is a timestamp with time zone you need to use tstzrange instead.
Online example
You can use date arithmetics and aggregation:
select
sum(
greatest(
least(d.end_time, t.end_time) - greatest(d.start_time, t.start_time),
'0 hour'::interval
)
) total_overlap
from mytable t
cross join (values
('2019-10-21 21:00:00'::timestamp, '2019-10-22 01:00:00'::timestamp)
) d(start_time, end_time)
For each row, the difference between the smaller end time and the greatest start time gives you the duration of the overlap - if it is positive.
Usecase: Query to select the records for a whole day and it should run regularly.
This is my query.
Select to_char(in_date + interval '12' hour, 'DD-MON-YYYY HH24:MI:SS')
from my_table
where incoming_date > sysdate-2 and incoming_date < sysdate
I need to select yesterday's data only. Because of the conversion in the select statement I got today's data also. How do I select only yesterday's data? My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement. And how do I display only yesterday's data?
I'm stuck. Please help me
To get all data from yesterday you should use
SELECT TO_CHAR(IN_DATE + INTERVAL '12' HOUR, 'DD-MON-YYYY HH24:MI:SS')
FROM MY_TABLE
WHERE INCOMING_DATE BETWEEN TRUNC(SYSDATE) - INTERVAL '1' DAY
AND TRUNC(SYSDATE) - INTERVAL '1' SECOND
If, for example, SYSDATE is 05-NOV-2017 18:56:35, the time interval used in the BETWEEN comparison will be from 04-NOV-2017 00:00:00 to 04-NOV-2017 23:59:59. BETWEEN comparisons are inclusive of both endpoints so this will only return data with an INCOMING_DATE of sometime on 04-NOV-2017, in this example.
Best of luck.
only to get the
yesterday's data
make your
WHERE condition as
incoming_date between trunc(sysdate) - interval '1' day and trunc(sysdate) - interval '1' second
My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement.
Using a magic value (INTERVAL '12' HOUR) does not describe what it means or the assumptions you made when chosing that value. Instead you can better describe the process by using FROM_TS( timestampvalue, timezonestring ) to convert the value from a TIMESTAMP to a TIMESTAMP WITH TIME ZONE data type and then use AT LOCAL TIME to convert it to the local time. Then if you have daylight savings time or port the query to another international location then it will still display in the current local time. Like this:
SELECT TO_CHAR(
FROM_TZ( CAST( in_date AS TIMESTAMP ), '+07:00' ) AT LOCAL TIME,
'DD-MON-YYYY HH24:MI:SS'
)
FROM my_table
WHERE incoming_date >= TRUNC( SYSDATE ) - INTERVAL '1' DAY
AND incoming_date < TRUNC( SYSDATE )
And how do I display only yesterday's data?
TRUNC( SYSDATE ) will truncate today's date back to midnight. To get yesterday's data then you can get values that are greater or equal to TRUNC( SYSDATE ) - INTERVAL '1' DAY (one day before midnight today) and also less than TRUNC( SYSDATE ) (midnight today).
I'm not exactly sure I get your question, but I think I can explain some stuff.
I'll be assuming your table is a bit like this:
date_added | some_data | some_more_data
------------|-----------|----------------
date | data1 | data2
As I understand your goal is to fetch all the rows that were added to a table the day before the query is run using a select statement. but your current attempt fails at doing so by also returning today's results.
Here is what's happening (I think):
SYSDATE doesn't just give you the current date, it also gives you the time. You can see that for your self by simply altering your current session and setting the date/time format to one that includes both time and date
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
The reason why you would be getting today's rows is simple, your query is asking for all the rows who's date_added field is between right now and right now - 24 hours. Not today and today - 24 hours.
So what is the solution?
Use the TRUNC function to trim the SYSDATE to the day instead!
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm
SELECT
T.*
FROM
MY_TABLE T
WHERE
T.DATE_ADDED BETWEEN (TRUNC(SYSDATE,'day') - 1) AND TRUNC(SYSDATE,'day');
As you did mention timezones being a thing keep in mind that SYSDATE returns the date on the server itself and not your computer's.
More on that here: https://stackoverflow.com/a/17925834/7655979
Usually I compare the date only using Trunc.
WHERE trunc(incoming_date) = trunc(sysdate-1)
How I can to see last 5 mins record before the current time through sql query how i can do this.
The format of time stamp is
03/25/2014 14:00:00
I used this query for the same
SELECT Time stamp FROM TABLE
WHERE S >1 AND SUBSTRING((Time stamp,15,2)-5)
is this fine of any other way to do the same
If you are using MySQL and your timestamp column is of data type datetime you can do
SELECT Timestamp
FROM your_table
WHERE Timestamp >= now() - interval 5 minute
If your timestamp is a date column, you can simply do:
select t.*
from table t
where t.timestamp >= sysdate - 5/(24*60)
Things are a bit more interesting if timestamp is a character column. Then you need to translate it to a date/time:
select t.*
from table t
where to_date(t.timestamp, 'MM/DD/YYYY HH24:MI:SS') >= sysdate - 5/(24*60)
select *
from the_table
where timestamp_column <= timestamp '2014-03-25 14:00:00' - interval '5' minute;
This assumes that timestamp_column is defined with the data type timestamp.
If it isn't you should stop now and re-define your table to use the correct data type.
The expression timestamp '2014-03-25 14:00:00' is a (ANSI SQL) timestamp literal.
It's equivalent to to_timestamp('2014-03-25 14:00:00', 'yyyy-mm-dd hh24:mi:ss') but I prefer the ANSI literal because it's less typing and works across multiple DBMS.
Here's an example of how to get 5 minutes ago in oracle. subtracting from a timestamp in increments of 1 where 1 is a day. so 5 minutes would be 5/(24hours*60min) of a day.
SELECT sysdate, sysdate-(5/(24*60)) as min_Ago5 from dual