Having custom year, not calendar year - sql

I would like the year to begin from August and end in the following July. Is there a simple way of doing this apart from writing the ugly IFELSE statements that I will have to write for each year? Ideally, I'd like to have year like 2009-10, 2010-11 etc. I'm using Postgres.
Here's an example query that I'd like to manipulate in order to get the custom year.
Select extract(year from created) as Year, type, count(*)
from table
group by Year, type
order by Year
Any help would be appreciated, TIA.

Consider setting up a Dates table. With this Dates table, you can associate a variety of data with each date, such as fiscal year, quarter, month #, whether it's a holiday, weekend, etc.

SELECT (CASE WHEN (EXTRACT(month FROM created) > 6) THEN CAST(EXTRACT(year FROM created) AS text) || '-' || CAST(EXTRACT(year FROM created) +1 AS text) ELSE (CAST(EXTRACT(year FROM created) - 1 AS text) || '-' || CAST(EXTRACT(year FROM created) AS text)) END) AS CustomYear
FROM asmt.testscores order by created desc LIMIT 10000
This seems to have done the trick.

select
extract(year from created + interval '6 months') as "Year",
type,
count(*)
from table
group by 1, 2
order by 1

Related

Using Where and group by clause

Can anyone describe how can I suppose to retrieve data using filter conditions such as both where and group by clauses of different fields through SQL ?
For instance ,
Require to take out the No of days in a month does the temperature exceeding 35 degrees celsius ?
SELECT temp, count(*)
FROM weather_data
WHERE day between '01-jun-2022' to '30-jun-2022'
GROUP BY temp > '35';
My requirement is to find out the aggregate details like total count
So I tried using group by clause , Inaddition to that , I must use few conditions to filter further ,
Hence I used conditions in where clause before group by clause
it's correct query :
SELECT temp, count(*) FROM weather_data
WHERE temp > '35' AND day between '01-jun-2022' and '30-jun-2022' GROUP BY temp
You want to aggregate your data, so as to get one result row per month. In SQL this is GROUP BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day). Your DBMS may have additional functions to extract a month (year + month to be precise) from a date, such as TO_CHAR(day, 'YYYY-MM'), but this is vendor specific.
Now you only want to count days with a temperature obove 35 degrees. The first idea to solve this, is a WHERE clause that limits the rows you aggregate to the ones in question:
SELECT
EXTRACT(YEAR FROM day) AS year,
EXTRACT(MONTH FROM day) AS month,
COUNT(*)
FROM mytable
WHERE temp > 35
GROUP BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day)
ORDER BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day);
The problem with this: If a month has no day above that temperature, you won't select that month, because your WHERE clause removed those rows. That may be okay with you, but if you want to show the months with a zero count, then move the condition into the aggregation function. Thus you select all months but only count days with high temperatures:
SELECT
EXTRACT(YEAR FROM day) AS year,
EXTRACT(MONTH FROM day) AS month,
COUNT(CASE WHEN temp > 35 THEN 1 END)
FROM mytable
GROUP BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day)
ORDER BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day);
How does this work? COUNT <expression> ) counts non-null occurrences. CASE WHEN temp > 35 THEN 1 END is short for CASE WHEN temp > 35 THEN 1 ELSE NULL END. And instead of 1 you could use any value that is not null, e.g. 'count me'. Or you could use SUM instead, if you like that better: SUM(CASE WHEN temp > 35 THEN 1 ELSE 0 END).
At last you want to limit the date range. Date literals in SQL look like this: DATE 'YYYY-MM-DD'. And as we sometimes deal with dates and other times with datetimes or timestamps, it has become common, not to use BETWEEN, but >= and <, so as to have the range work for all those data types:
SELECT
EXTRACT(YEAR FROM day) AS year,
EXTRACT(MONTH FROM day) AS month,
COUNT(CASE WHEN temp > 35 THEN 1 END)
FROM mytable
WHERE day >= DATE '2022-06-01'
AND day < DATE '2022-07-01'
GROUP BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day)
ORDER BY EXTRACT(YEAR FROM day), EXTRACT(MONTH FROM day);
Try this:
SELECT temp, count(*)
FROM weather_data
WHERE date >= '01-jun-2022' AND date<='30-jun-2022' AND temp > '35'
GROUP BY temp;

Oracle sql - get months id between two dates

I have date range eg. '2021-01-05' and '2021-02-10'. Two months January and February.
Need resaults:
Months
------
1
2
You want to iterate through the months. This is done with a recursive query in SQL:
with months (month_start_date) as
(
select trunc(:start_date, 'month') from mytable
union all
select month_start_date + interval '1' month
from months
where month_start_date < trunc(:end_date, 'month')
)
select
extract(year from month_start_date) as year,
extract(month from month_start_date) as month
from months
order by month_start_date;
You can use EXTRACT function that Oracle has to achieve this. In your case it should look something like:
SELECT EXTRACT (month FROM date_column) as "Months"
For more information about this function you can check out documentation here.

PostgreSQL how to get closest birthday date

I have a table called birthdays with 2 columns name and date.
Name is string value, date is date (Looks like this: 1989-07-28 00:00:00)
How can i get closest birthday, according to day i am checking, for example NOW()
Using PostgreSQL
The question is determining if the year is this year or next year:
select (case when to_char(dob, 'MM-DD') >= to_char(now(), 'MM-DD')
then to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(dob, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year'
end)
from (values ('1989-07-28'::date)) v(dob);
Assuming you are searching for forward-looking birthdays, the query below takes the minimum difference in days starting from current date
Select "Date" - Current_Date as diff,
"Date" as Dob,
Name
from birthdays
Where ("Date"- Current_Date) > 0
Order by 1 asc
limit 1;
First off in Postgres if your column is defined as DATE then it does not appear as "1989-07-28 00:00:00". Dates in Postgres do not have time components, so no "00:00:00" (unless you have done something with datestyle. But that is actually immaterial here.
Postgres dates can be directly subtracted to get the days number of between them, with the result either positive or negative depending upon which date occurs first. To
get the "closest" to a specific data just take the absolute value.
with birthdays (name, bday) as
( values ('George', date '2020-10-18')
, ('Gloryann', date '2020-11-02')
, ('Phyllis', date '2020-10-09')
, ('Sam', date '2020-06-18')
)
select name, bday birthday
from birthdays
order by abs(current_date-bday)
limit 1;
Caution: Do not use date as an object name. Date is both a Postres and SQL standard reserved word. While using it may be permitted currently Postges would be within their right to enforce the predefined meaning at anytime, potentially causing major issues for your app. Play it safe Do Not use reserved words as object names.
Thanks guys, it works perfect this way:
select name, date, (case when to_char(date, 'MM-DD') >= to_char(now(), 'MM-DD') then
to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD')
else to_date(to_char(current_date, 'YYYY') || '-' || to_char(date, 'MM-DD'), 'YYYY-MM-DD') + interval '1 year' end)
from birthdays order by 3

Oracle SQL to get first day of month

Requirement is input date should produce first day of the month.
Condtions are:
If the date entered is between 16-nov to 30-nov, then the first day will be 16-nov.
if the date entered is between 1-nov to 15-nov , then the first day will be 01-nov.
for all other month it should return 01st day of corresponding month.
Building on Tim Biegeleisen's solution, simplifying it and avoid the date-to-text-to-date conversions. Note the use of TRUNC to get the first date of the period.
SELECT
CASE
WHEN EXTRACT(MONTH FROM DATE_COL) = 11 AND EXTRACT(DAY FROM DATE_COL) >= 16
THEN TRUNC(DATE_COL, 'MONTH') + 15
ELSE TRUNC(DATE_COL, 'MONTH')
END AS FIRST_OF_MONTH
FROM T1
I used a lengthy CASE expression to handle this, containing the logic for the three cases you mentioned in your question.
SELECT CASE WHEN EXTRACT(month FROM date) = 11 AND
EXTRACT(day FROM date) >= 16
THEN TO_DATE(EXTRACT(year FROM date) || '-11-16', 'yyyy-mm-dd')
ELSE TO_DATE(EXTRACT(year FROM date) || '-' || EXTRACT(month FROM date) ||
'-01', 'yyyy-mm-dd')
END AS newDate
FROM yourTable

How to format a Vertica date column into just the month?

I am trying to format a Vertica date column into only the month.
I would need the final value in some sort of date datatype so in the report I can order the results by date/time, not order by text. So that February sorts after January etc.
select TO_DATE(TO_CHAR(purchase_date), 'Month')
from transactions
order by 1;
I am also tried:
select TO_DATE(TO_CHAR(MONTH(purchase_date)), 'Month')
from transactions
order by 1;
The above statements produce an error "Invalid value for Month"
Any ideas?
How about this?
select to_char(purchase_date, 'Month')
from transactions
order by purchase_date;
You can order by columns that are not in the select list.
EDIT:
If you want to combine months from multiple years, the above will not work quite right. This will:
select to_char(purchase_date, 'Month')
from transactions
order by extract(month from purchase_date);
Select TO_CHAR((NOW() - INTERVALYM '1 MONTH'), 'MON');
Output:
JUN
This will help you get only the name of the previous month.
We can directly use date_part to get a month from the timestamp.
SELECT DATE_PART('MONTH', purchase_date) purchase_date
TO_DATE gives the complete date, if you only provide MM in the parameter then Vertica set default year and day.
Let suppose the month number is 8.
SELECT TO_DATE(purchase_date, 'MM')
Output: (0001-08-01)