Teradata Interval function - sql

Teradata fails while using in-built function, INTERVAL, when used with MONTH specification for deriving dates on February month
SELECT Cast('2017-12-29' as date) - INTERVAL '10' MONTH;
SELECT Cast('2017-12-30' as date) - INTERVAL '10' MONTH;
SELECT Cast('2017-12-31' as date) - INTERVAL '10' MONTH;
SELECT Cast('2018-12-29' as date) - INTERVAL '10' MONTH;
SELECT Cast('2018-12-30' as date) - INTERVAL '10' MONTH;
SELECT Cast('2018-12-31' as date) - INTERVAL '10' MONTH;
SELECT Cast('2019-12-29' as date) - INTERVAL '10' MONTH;
SELECT Cast('2019-12-30' as date) - INTERVAL '10' MONTH;
SELECT Cast('2019-12-31' as date) - INTERVAL '10' MONTH;
SELECT Cast('2020-12-30' as date) - INTERVAL '10' MONTH;
SELECT Cast('2020-12-31' as date) - INTERVAL '10' MONTH;
or
SELECT CURRENT_DATE - INTERVAL '10' MONTH;-- << If current date is 29,30,31 day of December month Non leap year and 30,31 day of December month leap year>>

Use Add_Months function instead of Interval function..
SELECT ADD_MONTHS(CAST ('2017-12-29' AS DATE),-10);
SELECT ADD_MONTHS(CURRENT_DATE,-10); -- << If current date is 29,30,31 day of December month Non leap year and 30,31 day of December month leap year>>

Related

Selecting record count by month

I have to get a count of transaction by each for a year Oct 2020 to Oct 2021 . The following is the query for the over all year . Is there a way I can do this count by each month with out having to run 12 times this query?
select count(*)
from Transaction_Details
where date_created between TO_DATE('2020-10-01 01:00:00','YYYY-MM-DD hh24:mi:ss')
and TO_DATE('2021-10-01 01:00:00','YYYY-MM-DD hh24:mi:ss');
Truncate the date to the start of the calendar month and GROUP BY that:
select TRUNC(date_created, 'MM') As calendar_month_start,
count(*)
from Transaction_Details
where date_created between DATE '2020-10-01' + INTERVAL '1' HOUR
and DATE '2021-10-01' + INTERVAL '1' HOUR
GROUP BY
TRUNC(date_created, 'MM')
ORDER BY
calendar_month_start;
If you want it starting at 1am on the 1st of each month then:
select TRUNC(date_created - INTERVAL '1' HOUR, 'MM')
+ INTERVAL '1' HOUR AS month_from_1am_on_1st,
count(*)
from Transaction_Details
where date_created between DATE '2020-10-01' + INTERVAL '1' HOUR
and DATE '2021-10-01' + INTERVAL '1' HOUR
GROUP BY
TRUNC(date_created - INTERVAL '1' HOUR, 'MM')
ORDER BY
month_from_1am_on_1st;
db<>fiddle here

previous friday of month

I am trying to write a query that will return the last friday of the previous month This is what I have so far.
SELECT sysdate
FROM DUAL
where (LAST_DAY( SYSDATE ) - INTERVAL '7' DAY,
'Friday' );
Consider:
select next_day(trunc(sysdate, 'month') - interval '8' day, 'Friday') from dual
Rationale:
trunc(sysdate, 'month') gives you the first day of the current month
we offset that value by 8 days so we can the the date 7 days before the end of the previous month
then, next_day() returns the next Friday after this date, that is the last Friday of the month
Try this:
SELECT NEXT_DAY( LAST_DAY( TO_DATE('01-' || TO_CHAR(SYSDATE, 'MON-YYYY')) - 1 ) - INTERVAL '7' DAY, 'FRIDAY' ) FROM DUAL;

SQL Query to get records from last week of every month for 4 years

I have below table
ABC Date
200 2019-02-22
-200 2019-02-23
1200 2019-02-24
-500 2019-02-25
'
'
'
'
-889 2015-01-11
I need to get values for from ABC for every day of last week of every month
select ABC
from table 1
where date between '2019-03-26' and '2019-03-30'
this is for month of march 2019. How do i create a loop such that it displays value for everyday of last week of every month for 3 years
You can use date arithmetic to get the last week of each month. In Terdata, I think this is one solution:
select abc
from table1
where (date >= (current_date - extract(day from date) * interval '1 day') - interval '6 day' and
date <= current_date - extract(day from date) * interval '1 day'
) or
(date >= (current_date - extract(day from date) * interval '1 day') - interval '1 month' - interval '6 day' and
date <= current_date - extract(day from date) * interval '1 day' - interval '1 month'
) or
(date >= (current_date - extract(day from date) * interval '1 day') - interval '2 month' - interval '6 day' and
date <= current_date - extract(day from date) * interval '1 day' - interval '12month'
);
SELECT ABC, DATE FROM table_1 WHERE DATEPART(wk, DATE) =
DATEPART(wk, EOMONTH(DATE)) AND DATE <= DATEADD(year,3,GETDATE())
DATEPART(wk, DATE) gives me the week number of that date, DATEPART(wk,EOMONTH(DATE)) gives me the week number of (the last day of the corresponding date's month). So, when I check this, I will only select dates belonging to the last week of every month. The next filter is to select only those dates which are lesser than 3 years from now (GETDATE()).

Vertica - WITH clause is not recognized in actual query

Please take a look at the following Vertica SQLcode:
WITH date_range AS
(SELECT YEAR(now() - interval '1' MONTH) ||MONTH(now() - interval '1' MONTH) ||'#'||DATE(TRUNC(now() - interval '1' MONTH, 'mm')) ||'#'||DATE(TRUNC(now(), 'mm') - interval '1' DAY) AS month1
, YEAR(now() - interval '2' MONTH) ||MONTH(now() - interval '2' MONTH) ||'#'||DATE(TRUNC(now() - interval '2' MONTH, 'mm')) ||'#'||DATE(TRUNC(now() - interval '1' MONTH, 'mm') - interval '1' DAY) AS month2
)
SELECT regexp_substr(
(SELECT month1
FROM date_range), '[^#]*', 1, 1)
I have a 420 rows-long query, and I need to use "month1" and "month2" as variables many time in my code. Unfortunately, Vertica still doesn't support variables, so I tried to use a WITH clause instead.
Unfortunately, it doesn't work, as I keep getting the following error message:
(4566) ERROR: Relation "date_range" does not exist
So help me God (or Stack Overflow)
I think this is the query you want:
WITH date_range AS (
SELECT YEAR(now() - interval '1' MONTH) ||MONTH(now() - interval '1' MONTH) ||'#'||DATE(TRUNC(now() - interval '1' MONTH, 'mm')) ||'#'||DATE(TRUNC(now(), 'mm') - interval '1' DAY) AS month1,
YEAR(now() - interval '2' MONTH) ||MONTH(now() - interval '2' MONTH) ||'#'||DATE(TRUNC(now() - interval '2' MONTH, 'mm')) ||'#'||DATE(TRUNC(now() - interval '1' MONTH, 'mm') - interval '1' DAY) AS month2
)
SELECT regexp_substr(month1, '[^#]*', 1, 1)
FROM date_range;
In an actual query, you would do this as:
SELECT regexp_substr(dr.month1, '[^#]*', 1, 1)
FROM date_range dr CROSS JOIN
. . .;
I often call such CTEs params to highlight that they are providing parameters to the query.

Select data with a rolling date criteria

The below query returns a distinct count of 'members' for a given month and brand (see image below).
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct UNIQUE_MEM_ID) as distinct_count
from source.table
group by to_char(transaction_date, 'YYYY-MM'), brand;
The data is collected with a 15 day lag after the month closes (meaning September 2016 MONTHLY data won't be 100% until October 15). I am only concerned with monthly data.
The query I would like to build: Until the 15th of this month (October), last month's data (September) should reflect August's data. The current partial month (October) should default to the prior month and thus also to the above logic.
After the 15th of this month, last month's data (September) is now 100% and thus September should reflect September (and October will reflect September until November 15th, and so on).
The current partial month will always = the prior month. The complexity of the query is how to calc prior month.
This query will be ran on a rolling basis so needs to be dynamic.
To be clear, I am trying to build a query where distinct_count for the prior month (until end of current month + 15 days) should reflect (current month - 2) value (for each respective brand). After 15 days of the close of the month, prior month = (current month - 1).
Partial current month defaults to prior month's data. The 15 day value should be variable/modifiable.
First, simplify the query to:
select to_char(transaction_date, 'YYYY-MM') as month, brand,
count(distinct members) as distinct_count
from source.table
group by members, to_char(transaction_date, 'YYYY-MM'), brand;
Then, you are going to have a problem. The problem is that one row (say from Aug 20th) needs to go into two groups. A simple group by won't handle this. So, let's use union all. I think the result is something like this:
select date_trunc('month', transaction_date) as month, brand,
count(distinct members) as distinct_count
from source.table
where (date_trunc('month', transaction_date) < date_trunc('month' current_date) - interval '1 month') or
(day(current_date) > 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by date_trunc('month', transaction_date), brand
union all
select date_trunc('month' current_date) - interval '1 month' as month, brand,
count(distinct members) as distinct_count
from source.table
where (day(current_date) < 15 and date_trunc('month', transaction_date) = date_trunc('month' current_date) - interval '1 month')
group by brand;
Since you already have a working query, I concentrate on the subselect. The condition you can use here is CASE, especially "Searched CASE"
case
when extract(day from current_date) < 15 then
extract(month from current_date - interval '2 months')
else
extract(month from current_date - interval '1 month')
end case
This may be used as part of a where clause, for example.
Here is some sudo code to get the begin date and the end date for your interval.
Begin date:
date DATE_TRUNC('month', CURRENT_DATE - integer 15) - interval '1 month'
This will return the current month only after the 15th day, from there you can subtract a full month to get your starting point.
End Date:
To calculate this, grab the begin date, plus a month, minus a day.
If the source table is partitioned by transaction_date, this syntax (not masking transaction_date with expression) enables partitions eliminatation.
select to_char(transaction_date, 'YYYY-MM') as month
,count (distinct members) as distinct_count
,brand as brand
FROM source.table
where transaction_date between date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 1 else 2 end * interval '1' month
and date_trunc('month', current_date) - case when extract (day from current_date) >= 15 then 0 else 1 end * interval '1' month - interval '1' day
group by to_char(transaction_date, 'YYYY-MM')
,brand
;