Timestamp query to hours - sql

I need some help with timestamps with postgresql. I have a column for the timestamp with timezone named download_at for when a user downloaded an app and a column user_id which is an integer. I am trying to extract user IDs of users that have downloaded within the last 168 hours from the last 60 days of information. I am a bit confused on how I can approach this and felt stuck because of the two different times. I believe I might have to play around with the trunc function but felt a bit stuck.

A basic example:
SELECT *
FROM table1
WHERE download_at > now() - '186 hours'::interval
Postgres is phenomenal at handling dates and times. A breakdown of what this does:
now() --function that returns the current time as a datetime object
'186 hours'::interval --a string cast to an interval
In postgres :: does casting. When casting to an interval Postgres will turn formatted English to an interval object. Since you can subtract datetime and interval objects it'll do the rest for you.

Related

SQL - how to change the format of a current_timestamp to have 'mm ss' as zeros?

I want to check if a metric is still missing 4 hours later and return a single record if it exists. I wrote a query that checks if there were metrics in the last 4 hours. But I need to check if there is a metric for a certain hour that was expected to load 4 hours before.
-- Returns records that appeared within the last 4 hours
select * from main.basic_metrics
where metric_name = 'common_metric'
and transaction_time > current_timestamp - interval 4 hours
The problem is that transaction_timeis in the following format 2019-10-30T12:00:00.000+0000 where mm ss are always zeros. So when I check it like transaction_time = current_timestamp - interval 4 hours it returns nothing since current_timestamp contains mm ss data.
How should I format timestamp to the format similar to transaction_time - 2019-10-30T12:00:00.000+0000 ?
UPD: There was a typo, mentioned in the comments below. fixed it
That should be very simple: cast the string to timestamp with time zone:
WHERE CAST(transaction_time AS timestamp with time zone)
> current_timestamp - INTERVAL '4 hours'
Try the following:
select * from main.basic_metrics
where metric_name = 'common_metric'
and transaction_time = date_trunc('hour',current_timestamp) - interval 4 hours
This is not necessarily the best query for what you're doing, but it does solve the problem you're having. My guess is that some version of "between" or > and < would solve it, however without knowing exactly how the "transaction time" is populated, I'm could only venture guesses.
The trick in my example is to "truncate" everything after the "hours" off of the current_timestamp using date_trunc()
Note: It helps a lot to realize that timestamps are NOT formatted. Timestamps are a single long integer field that happens to get formatted on your screen so you can make sense of it. Text comparisons are nearly always the wrong way to do things, and datetime aware functions are the preferred method of doing any comparison.

time difference in sql Oracle

I need to know a difference between start time and end time. Both are DATETIME fields, I tried to use "-" and DATADIFF.
I already tried using DATADIFF and simple subtraction converting the field to just time.
(to_date(Fim_Hora,'HH24:MI') - to_date(Inicio_Hora,'HH24:MI')) AS Diferenca
DATADIFF(MIN,Fim_Hora,Inicio_Hora)
I need to know the time in minutes for use as parameters.
Oracle does not have a time data type. Usually, subtraction works well enough:
select (end_time - start_time) as diff
You may need to convert to a string if you want it formatted in a particular way.
In Oracle, you can directly substract dates, it returns the difference between the dates in days. To get the difference in minutes, you can multiply the result by 24 (hours per days) and 60 (minutes per hour):
(Fim_Hora - Inicio_Hora) * 24 * 60 diff_minutes
This assumes that both Fim_Hora and Inicio_Hora are of datatype DATE.

google bigquery select from a timestamp column between now and n days ago

I have a dataset in bigquery with a TIMESTAMP column "register_date" (sample value "2017-11-19 22:45:05.000 UTC" ).
I need to filter records based on x days or weeks before today criteria.
Example query
select all records which are 2 weeks old.
Currently I have this query (which I feel like a kind of hack) that works and returns the correct results
SELECT * FROM `my-pj.my_dataset.sample_table`
WHERE
(SELECT
CAST(DATE(register_date) AS DATE)) BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -150 DAY)
AND CURRENT_DATE()
LIMIT 10
My question is do I have to use all that CASTing stuff on a TIMESTAMP column (which seems like over complicating the otherwise simple query)?
If I remove the CASting part, my query doesn't run and returns error.
Here is my simplified query
SELECT
*
FROM
`my-pj.my_dataset.sample_table`
WHERE
register_date BETWEEN DATE_ADD(CURRENT_DATE(), INTERVAL -150 DAY)
AND CURRENT_DATE()
LIMIT
10
that results into an error
Query Failed
Error: No matching signature for operator BETWEEN for argument types: TIMESTAMP, DATE, DATE. Supported signature: (ANY) BETWEEN (ANY) AND (ANY) at [6:17]
any insight is highly appreciated.
Use timestamp functions:
SELECT t.*
FROM `my-pj.my_dataset.sample_table` t
WHERE register_date BETWEEN TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -150 DAY) AND CURRENT_TIMESTAMP()
LIMIT 10;
BigQuery has three data types for date/time values: date, datetime, and timestamp. These are not mutually interchangeable. The basic idea is:
Dates have no time component and no timezone.
Datetimes have a time component and no timezone.
Timestamp has both a time component and a timezone. In fact, it represents the value in UTC.
INTERVAL values are defined in gcp documentation
Conversion between the different values is not automatic. Your error message suggests that register_date is really stored as a Timestamp.
One caveat (from personal experience): the definition of day is based on UTC. This is not much of an issue if you are in London. It can be a bigger issue if you are in another time zone and you want the definition of "day" to be based on the local time zone. If that is an issue for you, ask another question.

Convert milliseconds to Date/Time

I'm trying to generate a report in PostgreSQL.
It's working -- except one column stored in the database represents a date/time value, but it is stored as an integer representing the number of milliseconds since 1970.
Needless to say, the millisecond value has not much meaning to people reading the report.
Is there a way in SQL to convert milliseconds into some sort of readable date/time value?
I'm not easily able to have the report generated in some other program or language. I'd like the report to be run as a SQL script.
This recipe is from the docs:
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + (millisecond_column/1000) * INTERVAL '1 second'
FROM mytable;
Recent versions of PostgreSQL provide a to_timestamp function to achieve the same.

Timestamp Difference In Hours for PostgreSQL

Is there a TIMESTAMPDIFF() equivalent for PostgreSQL?
I know I can subtract two timestamps to get a postgresql INTERVAL. I just want the difference between the two timestamps in in hours represented by an INT.
I can do this in MySQL like this:
TIMESTAMPDIFF(HOUR, links.created, NOW())
I just need the difference between two timestamps in hours represented as an integer.
Solution works for me:
SELECT "links_link"."created",
"links_link"."title",
(EXTRACT(EPOCH FROM current_timestamp - "links_link"."created")/3600)::Integer AS "age"
FROM "links_link"
The first things popping up
EXTRACT(EPOCH FROM current_timestamp-somedate)/3600
May not be pretty, but unblocks the road. Could be prettier if division of interval by interval was defined.
Edit: if you want it greater than zero either use abs or greatest(...,0). Whichever suits your intention.
Edit++: the reason why I didn't use age is that age with a single argument, to quote the documentation: Subtract from current_date (at midnight). Meaning you don't get an accurate "age" unless running at midnight. Right now it's almost 1am here:
select age(current_timestamp);
age
------------------
-00:52:40.826309
(1 row)
Get fields where a timestamp is greater than date in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > to_date('05 Dec 2000', 'DD Mon YYYY');
Subtract minutes from timestamp in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > current_timestamp - interval '5 minutes'
Subtract hours from timestamp in postgresql:
SELECT * from yourtable
WHERE your_timestamp_field > current_timestamp - interval '5 hours'
Michael Krelin's answer is close is not entirely safe, since it can be wrong in rare situations. The problem is that intervals in PostgreSQL do not have context with regards to things like daylight savings. Intervals store things internally as months, days, and seconds. Months aren't an issue in this case since subtracting two timestamps just use days and seconds but 'days' can be a problem.
If your subtraction involves daylight savings change-overs, a particular day might be considered 23 or 25 hours respectively. The interval will take that into account, which is useful for knowing the amount of days that passed in the symbolic sense but it would give an incorrect number of the actual hours that passed. Epoch on the interval will just multiply all days by 24 hours.
For example, if a full 'short' day passes and an additional hour of the next day, the interval will be recorded as one day and one hour. Which converted to epoch/3600 is 25 hours. But in reality 23 hours + 1 hour should be a total of 24 hours.
So the safer method is:
(EXTRACT(EPOCH FROM current_timestamp) - EXTRACT(EPOCH FROM somedate))/3600
As Michael mentioned in his follow-up comment, you'll also probably want to use floor() or round() to get the result as an integer value.
You can use the "extract" or "date_part" functions on intervals as well as timestamps, but I don't think that does what you want. For example, it gives 3 for an interval of '2 days, 3 hours'. However, you can convert an interval to a number of seconds by specifying 'epoch' as the time element you want: extract(epoch from '2 days, 3 hours'::interval) returns 183600 (which you then divide by 3600 to convert seconds to hours).
So, putting this all together, you get basically Michael's answer: extract(epoch from timestamp1 - timestamp2)/3600. Since you don't seem to care about which timestamp precedes which, you probably want to wrap that in abs:
SELECT abs(extract(epoch from timestamp1 - timestamp2)/3600)
postgresql get seconds difference between timestamps
SELECT (
(extract (epoch from (
'2012-01-01 18:25:00'::timestamp - '2012-01-01 18:25:02'::timestamp
)
)
)
)::integer
which prints:
-2
Because the timestamps are two seconds apart. Take the number and divide by 60 to get minutes, divide by 60 again to get hours.
extract(hour from age(now(),links.created)) gives you a floor-rounded count of the hour difference.
To avoid the epoch conversion you could extract the days multiply them by 24 and add the extraction of hours to it.
select current_timestamp, (current_timestamp - interval '500' hour), (extract(day from (current_timestamp - (current_timestamp - interval '500' hour)) * 24) + extract(hour from (current_timestamp - (current_timestamp - interval '500' hour))));
For MySQL timestampdiff I don't know, but for MSSQL datediff(hour, start, end) the best equivalent in PostgreSQL is floor(extract(epoch from end - start)/3600), because in MSSQL select datediff(hour,'2021-10-31 18:00:00.000', '2021-10-31 18:59:59.999') return 0
This might sound crazy to a lot of developers who like to take advantage of database functions,
But after exhaustive problems thinking, creating and bugfixing applications for mysql and postgrsql with php comparing date functions, I've come to the conclusion (for myself), that the easiest way, that is the simplest with less SQL headaches is not to take advantage of any of them.
Why? because if you are developing in a middleware language like PHP, PHP has all of these functions, and they are easier to implement in the application ode as comparing integers. PostgreSQL timestamp is NOT == UNIX TIMESTAMP and MySQL's UNIX TIMESTAMP is NOT PostgresQL's or Oracles timestamp.. it gets harder to port if you use database timestamps..
so just use an integer, not a timestamp,
as the number of seconds since january 1st 1970 midnight. and never mind database timestamps.
, and use gmdate() and store everything as gmt time to avoid timezone issues.
if you need to search, sort or compare the day from other data, or the month or the year or the day of the week, or anything, in your application,
and INTEGER datatype for time_day, time_hour, time_seconds.. or whatever you wnat to index to be searched will make for smoother and more portable databases.
you can just use one field, in most instances: INTEGER time_created NOT NULL
(more fields in your database row is the only drawback to this solution that i have found, and that doesnt cause as many headaches, or cups of coffee :)
php's date functions are outstanding to compare dates,
but in mysql or postgresql, comparing dates ? nah.. use integer sql comparisons
i realize it may SEEM easier to use CURRENT_TIMESTAMP on an insert function. HA!
don't be fooled.
You cant do DELETE FROM SESSION_TABLE WHERE time-initialized < '2 days'
if time-intitialized is a postgresql timestamp.
but you CAN do:
DELETE FROM SESSION_TABLE WHERE time_initialized < '$yesterday'
As long as you set $yesterday in php as the integer of seconds since 1970 that yesterday was.
This is easier housekeeping of session records than comparing timestamps in postgresql select statements.
SELECT age(), SELECT extract(), and asbtime are headaches in an of themselves. this is just my opinion.
you can do addition, substraction, <, >, all with php date objects
_peter_sysko
U4EA Networks, Inc.