Vertica - WITH clause is not recognized in actual query - sql

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.

Related

Postgres - how to displays data for the previous year?

I have sql
select
name,
tanggal,
status
from
tbl_person
where
status = 'PROSES'
and date_part('year', tanggal) = 2021 - INTERVAL '1 YEAR'
tanggal is date 2021-01-01
I want to display previous year's data for example in 2020, how to write the correct query?
Using your method:
where status = 'PROSES' and
date_trunc('year', tanggal) = date_trunc('year', current_date) - interval '1 year'
However, I prefer to avoid functions on the column -- so the query is easier to optimize. So I would recommend:
where status = 'PROSES' and
tanggal < date_trunc('year', now()) and
tanggal >= date_trunc('year', now()) - interval '1 year'
This just uses now() rather than current_date because it is easier to type.

How to find the last 'working' day of last month?

Is there a way to find the last working day of last month? I know I can get last day of last month with SELECT (date_trunc('month', now())::date - 1), but how do I get the last "weekday"?
I believe this does what you want:
select (date_trunc('month', current_date) + interval '1 month' -
(case extract(dow from date_trunc('month', current_date) + interval '1 month')
when 0 then 2
when 1 then 3
else 1
end) * interval '1 day'
) as last_weekday_in_month
Such requests often suggest the need for a calendar table.
Piggy-backing off of Gordon's answer, I think this is what you want:
SELECT (
date_trunc('month', current_date) - interval '1 day' -
(case extract(dow from date_trunc('month', current_date) - interval '1 day')
when 0 then 2
when 6 then 1
else 0
end) * interval '1 day'
)::date as last_weekday_in_last_month;
Assuming your weekends are 0 (Sunday) and 6 (Saturday). It uses OP's original logic to find the last date of the last month, then Gordon's CASE logic to subtract more days if the last date is 0 or 6.

Teradata Interval function

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>>

Converting Recursive Query from Week over Week to Month over Month

I have a recursive query that provides the number of orders placed week over week (week_no, week_start, and week_end). I'd like to create a similar breakdown for a month over month analysis.
WITH recursive weeks (week_start, week_end, time_end, weekno) AS (
VALUES ('2015-12-27'::date, '2016-01-02'::date, '2016-04-02'::date, 1)
UNION ALL
SELECT (week_end + interval '1 day')::date,
(CASE
WHEN (week_end + interval '7 days')::date > time_end THEN time_end
ELSE (week_end + interval '7 days')::date
END)::date,
time_end,
weekno+1
FROM weeks
WHERE time_end > week_end)
Any help would be greatly appreciated.
Why would you use a recursive query for this? Use generate_series():
select g.week_start, g.week_start + interval '6 day' as week_end,
row_number() over (order by g.week_start) as weeknum
from generate_series('2015-12-27'::timestamp,
'2016-01-02'::timestamp,
interval '1 week'
) g(week_start);
The equivalent for months would be like:
select g.month_start, g.month_start + interval '1 month' - interval '1 day' as month_end,
row_number() over (order by g.month_start) as monthnum
from generate_series('2015-12-01'::timestamp,
'2016-01-01'::timestamp,
interval '1 month'
) g(month_start);

postgres query to check for records not falling between two time periods using the ISO WEEK number and year from DB

i do have a query which works fine but I was just wondering if there are other ways or alternate method to bettter this.
I have a table where i am fetching those records exceeding or do not fall between 1 year time interval however there is only the year and ISO week number column in the table (integer values).
basically the logic is to check ISO WEEK - YEAR falls between 'current_date - interval '1 year' AND current_date.
My query is as below :
select * from raj_weekly_records where
(date_dimension_week > extract(week from current_date) and date_dimension_year = extract(year from current_date) )
or (date_dimension_week < extract(week from current_date) and (extract(year from current_date)-date_dimension_year=1) )
or(extract(year from current_date)-date_dimension_year>1);
Here date_dimension_week and date_dimension_year are the only integer parameters by which I need to check is there any other alternate or better way?.This code is working fine no issues here.
Here is an idea. Convert the year/week to a numeric format: YYYYWW. That is, the year times 100 plus the week number. Then you can do the logic with a single comparison:
select *
from raj_weekly_records
where date_dimension_year * 100 + date_dimension_week
not between (extract(year from current_date) - 1) * 100 + extract(week from current_date) and
extract(year from current_date) * 100 + extract(week from current_date)
(There might be an off-by one error, depending on whether the weeks at the ends are included or excluded.)
select *
from raj_weekly_records
where
date_trunc('week',
'0001-01-01 BC'::date + date_dimension_year * interval '1 year'
)
+ (date_dimension_week + 1) * interval '1 week'
- interval '1 day'
not between
current_date - interval '1 year' and current_date