How to add dynamic interval from the column - hive

In Hive I need to add interval, taken from column:
SELECT CAST('2017-09-22 17:22:38' as timestamp) +
INTERVAL T.a minute
FROM ( SELECT 1 as a) as T;
I got this error:
cannot recognize input near 'interval' 'T' '.' in
expression specification.
All examples of using INTERVAL which I found are using the constant value after INTERVAL, but in my case this is dynamic value from the table.

You just need put the dynamic var inside brackets. Below code will work.
SELECT CAST('2017-09-22 17:22:38' as timestamp) +
INTERVAL (T.a) minute
FROM ( SELECT 1 as a) as T;

Related

SQL syntax error on select between two dates

I'm trying to get records which between two dates. Below is my query
select * from my_data
where name = 'customer' AND
(time between (('2021-03-24'::date - '1 month'::interval) AND '2021-03-24'::date))
However I'm getting a syntax error
ERROR: syntax error at or near ")"
LINE 1: ...03-24'::date - '1 month'::interval) AND '2021-03-24'::date))
^
What is the correct way of writing the query to return rows 1 month older than a given date?
You can drop the parentheses:
select *
from my_data
where name = 'customer' AND
time between '2021-03-24'::date - '1 month'::interval AND '2021-03-24'::date;
The specific issue is that the range for between does not accept parens.

Rename Column name in Pivot query and format its time value in format HH:MM:SS

I am preparing one report for which I need to have sum of time taken by various processes in column 2.
I am sharing small snippet in which I am not able to figure out. Below is the query.
SELECT DISTINCT *
FROM CTE_NAME
PIVOT ( SUM(TIME) FOR ACTIVITY IN ( NULL
,Process 1
,Process 2
)
) order by 2 desc
Things to be noted:-
hours_diff is the value calculated in a CTE expression above this shared snippet
hours_diff is of date type.
Things to be done:-
It is required to change the Column name NULL to TOTAL_TIME
It is required to convert the value of TIME to HH:MM:SS
Things I have tried:-
I tried using SUM(TIME) AS TOTAL_TIME ... it didn't seem to work. Also after that I tried replacing NULL with TOTAL_TIME but it changed in a way that TIME values of Process 1 shifted towards column 2.
In order to convert the time value (which is in seconds). I have this previously used TO_CHAR(TRUNC(sec_diff/3600),'FM9900') || ':' || TO_CHAR(TRUNC(MOD(sec_diff,3600)/60),'FM00') || ':' || TO_CHAR(MOD(sec_diff,60),'FM00') as time_diff. But as I am unable to fetch the column from above snippet I am not able to convert the values to HH:MM:SS
If I convert the value of TIME inside CTE then SUM function in SELECT query throws error Invalid Number as the value being passed to SUM function is in format HH:MM:SS
For giving name to the column, you can provide name in IN list of PIVOT as follows:
SELECT DISTINCT *
FROM CTE_NAME
PIVOT ( SUM(TIME) FOR ACTIVITY
IN ( NULL as TOTAL_TIME, -- THIS
,Process 1
,Process 2
)
) order by 2 desc;
To calculate HH:MI:SS from seconds, use this in select.(works for seconds in diff is less than 86400(1 day)
TO_CHAR(TRUNC(SYSDATE) + INTERVAL '1' SECOND * YOUR_COLUMN_SECONDS, 'HH24:MI:SS')
Or following will work for any bigger values
Lpad(Trunc(your_column_seconds/86400),2,'0')
|| ':' ||
Lpad(Trunc(your_column_seconds/1440),2,'0')
|| ':' ||
Lpad(Trunc(your_column_seconds/60),2,'0')
Note: column name of seconds difference generated by pivot should be used in above expression.

Convert an integer column to Month type MM

I'm trying to use PRECEDING and FOLLOWING on ranged month with following code
WITH tmp1 AS (
SELECT location.city, date.date, COUNT(*) OVER W
FROM fact, crime, date, location
WHERE fact.location_key = location.location_key and crime.crime_key =
fact.crime_key and fact.date_key = date.date_key
WINDOW W AS (
PARTITION BY location.city, date.year
ORDER BY date.month
RANGE BETWEEN INTERVAL '1 month' PRECEDING
AND INTERVAL '1 month' FOLLOWING
))
I got the error says
RANGE with offset PRECEDING/FOLLOWING is not supported for column type integer and offset type interval
I assume this is because my date.month is of type integer
So I tried to convert my date.month column to date type of format MM
I tried following
ALTER TABLE date ALTER COLUMN month TYPE text
using to_date(month, 'MM');
and gives error
No function matches the given name and argument types. You might need to add explicit type casts.
My question is
How to convert date.month to a type that can be used with PROCEDING and FOLLOWING command ?
I assume this type is date with format MM. That's why I tried the above code
Thank you!
You don't need to convert month column to any other datatype. The windowing clause i.e rows between... in your case works on a given partition which is PARTITION BY location.city, date.year. You need to add month to partition clause first in order for it to work in the window clause. Also don't use old style of joining.
WITH tmp1 AS (
SELECT location.city, date.date, COUNT(*) OVER W
FROM fact
join crime
on crime.crime_key = fact.crime_key
join date
on fact.date_key = date.date_key
join location
on fact.location_key = location.location_key and
WINDOW W AS (
PARTITION BY location.city, date.year, date.month
ORDER BY date.month
RANGE BETWEEN 1 PRECEDING
AND 1 FOLLOWING
))
Why would you use an interval range when you can use an integer range?
WINDOW W AS (
PARTITION BY location.city, date.year
ORDER BY date.month
RANGE BETWEEN INTERVAL 1 PRECEDING AND
INTERVAL 1 FOLLOWING
)

query to subtract date from systimestamp in oracle 11g

I want to perform a subtraction operation on the date returned from another query and the system time in oracle SQL. So far I have been able to use the result of another query but when I try to subtract from systimestamp it gives me the following error
ORA-01722: invalid number
'01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
Below is my query
select round(to_number(systimestamp - e.last_time) * 24) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I have also tried this
select to_char(sys_extract_utc(systimestamp)-e.last_time,'YYYY-MM-DD HH24:MI:SS') as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I want the difference between the time intervals to be in hours.
Thank you for any help in advance.
P.S. The datatype of ATTR_VALUE is VARCHAR2(150). A sample result of e.last_time is 2016-09-05 22:43:81796
"its VARCHAR2(150). That means I need to convert that to date"
ATTR_VALUE is a string so yes you need to convert it to the correct type before attempting to compare it with another datatype. Given your sample data the correct type would be timestamp, in which case your subquery should be:
(
select to_timestamp(ATTR_VALUE, 'yyyy-mm-dd hh24:mi:ss.ff5') as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
)
The assumption is that your sample is representative of all the values in your CONFIG table for the given keys. If you have values in different formats your query will break on some other way: that's the danger of using this approach.
So finally after lots of trial and errors I got this one
1. Turns out initially the error was because the data_type of e.last_time was VARCHAR(150).
To find out the datatype of a given column in the table I used
desc <table_name>
which in my case was desc CONFIG
2. To convert VARCHAR to system time I have two options to_timestamp and to_date. If I use to_timestamp like
select round((systimestamp - to_timestamp(e.last_time,'YYYY-MM-DD HH24:MI:SSSSS')) * 24, 2) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
I get an error that round expects NUMBER and got INTERVAL DAY TO SECONDS since the difference in date comes out to be like +41 13:55:20.663990. To convert that into hour would require a complex logic.
An alternative is to use to_data which I preferred and used it as
select round((sysdate - to_date(e.last_time,'YYYY-MM-DD HH24:MI:SSSSS')) * 24, 2) as lag
from (
select ATTR_VALUE as last_time
from CONFIG
where ATTR_NAME='last_time'
and PROCESS_TYPE='new'
) e;
This returns me the desired result i.e. the difference in hours rounded off to 2 floating digits

JPQL & Postgresql - How to perform arithmetic on timestamp field for comparison with CURRENT_TIMESTAMP?

I have a table "User" in two environments. One is using an Oracle DB and the other Postgresql. What I would like to do is retrieve all the records created in the last 4 hours. The "User" table has a field "beCreatime" which stores the timestamp of when the record was created.
I've implemented this successfully on the Oracle-based environment using the following:
SELECT u.id, u.userName, u.beCreatime FROM User u WHERE u.beCreatime + 4/24 > CURRENT_DATE
However, when using the same query on the Postgres environment, I receive the following error:
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: timestamp without time zone + integer
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Position: 100
Error Code: 0
Call: SELECT Id AS a1, UserName AS a2, be_creatime AS a3 FROM BeamUser WHERE ((be_creatime + (? / ?)) > CURRENT_TIMESTAMP) LIMIT ? OFFSET ? bind => [4 parameters bound] Query: ReportQuery(referenceClass=UserEntity sql="SELECT Id AS a1, UserName AS a2, be_creatime AS a3 FROM BeamUser WHERE ((be_creatime + (? / ?))
CURRENT_TIMESTAMP) LIMIT ? OFFSET ?")
It seems like Postgres just doesn't like the addition of the timestamp (u.beCreatime) and 4/24. Is there a way to do something similar to this in a Postgres environment?
You need to use an interval:
WHERE u.beCreatime + interval '4' hour > CURRENT_DATE
But you cannot pass the '4' as a paramter, you need to do something like this in a PreparedStatement:
WHERE u.beCreatime + (interval '1' hour) * ? > CURRENT_DATE
Are you sure you want to compare that value with current_date? Becaues current_date does not contain any time information in Postgres (as it does in Oracle due to the lack of a "real" DATE data type)
If you want to get the Oracle behaviour you have to use current_timestamp because unlike Oracle, a DATE in Postgres does not contain a time part (that includes current_date)