Re-Calculating number of Years, Months, and Days Oracle SQL - sql

I have a query returns this result :
EmpNo
EmpName
Years
Months
Days
111
Ahmed
0
14
39
In this case, I have 14 months, so it should add one year in the years field and remains 2
months in months field, and I have 39 days, so it should add one month in the months field and remains 9 days in days field
how I could re-calculate the years, months, and days to get query result like this :
EmpNo
EmpName
Years
Months
Days
111
Ahmed
1
2
9

Try this, but it is more correct to use the date field:
UPDATE your_table
SET
days = mod(days,30),
months = mod(months,12) + trunc(days/30),
years = years + trunc(months/12);
COMMIT;

It seems strange to say that all months have 30 days. But if you are assuming that you need to recalculate all columns. In this case, revert to days and recalculate everything:
select t.*,
mod(x.total_days, 30) as days,
floor(mod(x.total_days, 360) / 30) as months,
floor(mod(x.total_days / 360)) as years
from t cross join lateral
(select t.days + t.months * 30 + t.years * 360 as total_days
from dual
) x;
Note that this handles the case where you have 0/11/39.
If you want this in an update, you should be able to use a subquery:
update (select t.*, t.days + t.months * 30 + t.years * 360 as total_days
from t
)
set days = total_days, 30),
months = floor(mod(total_days, 360) / 30),
years = floor(mod(x.total_days / 360));
Assuming that a month has 30 days and (hence) that a year has 360 days seems problematic, but that is another issue entirely.

Try this. However, I think it should be 1 year, 3 months and 9 days though, Kindly let me know otherwise.
UPDATE your_table
SET
days = days - 30,
months = months + 1
WHERE
days > 30;
COMMIT;
UPDATE your_table
SET
months = months - 12,
years = years + 1
WHERE
months > 12;
COMMIT;
Output:
Empno Empname Years Months Days
-------------------------------
111 Ahmed 1 3 9

Related

how to get year between two months along with month and dates in sql query oracle

I need to extract no of years, months between two months, for example my output looks like 1year 9months. I don't know how to display output like this, below is the query which I am using now.
select round((MONTHS_BETWEEN(lease_end_date,lease_start_date)/12),1) Duration_In_Years
from lease_header
How about something like this? Read comments within code:
SQL> with test (date_1, date_2) as
2 -- sample dates; to test the query, modify these values
3 (select date '2021-10-20', date '2020-09-01' from dual),
4 temp as
5 -- split result of MONTHS_BETWEEN to number of years and number of months
6 (select
7 trunc(months_between(date_1, date_2) / 12) yrs,
8 round((months_between(date_1, date_2) / 12 - trunc(months_between(date_1, date_2) / 12)) * 12, 1) mon
9 from test
10 )
11 -- final result
12 select yrs || ' year(s) ' || mon || ' month(s)' result
13 from temp;
RESULT
----------------------
1 year(s) 1,6 month(s)
SQL>

How to get correct year, month and day in firebird function datediff including leap years

I need a solution extension that I received and it is visible at the link How to get correct year, month and day in firebird function datediff. I thought I had the right solution, but it turned out that the results I get differ from those counted by hand for a few days. The analysis showed that the reason of this differ was a leap years. Does anyone have an idea how to update this query to include leap years in counting dates?
I have got sql query forom Livius like this:
SELECT
KP3.id_contact
, (KP3.D2-KP3.D1) / (12*31) AS Y
, ((KP3.D2-KP3.D1) - ((KP3.D2-KP3.D1) / (12*31)) * 12 * 31) / 31 AS M
, CAST(MOD((KP3.D2-KP3.D1) - (((KP3.D2-KP3.D1) / (12*31)) * 12 * 31), 31) AS INTEGER) AS D
FROM
(SELECT
KP2.id_contact, SUM(KP2.D1) AS D1, SUM(KP2.D2) AS D2
FROM
(
SELECT
KP.id_contact, DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO) / 12 AS Y, CAST(MOD(DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO), 12) AS INTEGER) AS M
, EXTRACT(YEAR FROM KP.DATE_FROM)*12*31+EXTRACT(MONTH FROM KP.DATE_FROM)*31+EXTRACT(DAY FROM KP.DATE_FROM) D1
, EXTRACT(YEAR FROM KP.DATE_TO)*12*31+EXTRACT(MONTH FROM KP.DATE_TO)*31+EXTRACT(DAY FROM KP.DATE_TO) D2
FROM
KP
) AS KP2
GROUP BY KP2.id_contact
) AS KP3
For example I have got interval from 2011-11-02 to 2014-08-31. When I use this query I get result 2Y 9M 29D. But when I calculate this on hand I get result 2Y 9M 30D. It is one day differ because year 2012 have 366 days not 365 because 2012 is leap year.

How to Return records between two values in SQL

friends, I know that my question is very basic but I am stuck with it as I am naive to SQL,So, apology for that.
I have table named TRANS_MONT and stores data like below
Year month amount
2017 10 500
2017 11 700
2017 12 400
2018 1 600
2018 2 450
2018 3 600
I am interested to return all those transaction from the year 2017 whose month value is greater than 10 and all those record from the year 2018 whose month value is less than 3
I tried below query, but it does not work
Select * from TRANS_MONT where year in (2017, 2018) and month between 10 and 3
It's quite straight forward:
SELECT *
FROM trans_mont
WHERE (year = 2017 AND month > 10)
OR (year = 2018 AND month < 3);
The simplest would be something like this:
select * from Trans_Mont
where (year=2017 and Month>10)
or (year=2018 and Month<3)
or
select * from Trans_Mont
where (year * 100 + Month) BETWEEN 201710 and 201803
SQL doesn't pick up on the modular arithmetic of months if it is only stored as an integer.
Given it's really two logical statements, separate it with an OR to capture both situations in both years. Even if the month range was to work, it could technically also pick up the 12th month in 2018 for example.
SELECT * FROM TRANS_MONT
WHERE (Year = 2017 AND month > 10) OR (Year = 2018 AND month < 3)
Try below
Select * from TRANS_MONT where (year=2017 and month>=10) OR (year=2018 and month<=3)
You didn't state your DBMS, but with standard SQL you can do the following
select *
from trans_mont
where (year, month) between (2017,11) and (2018,2);
The between operator is inclusive of the edges, that's why the month on the lower end is 11 (not 10) and the month on the upper end is 2
Online example: https://rextester.com/VZPQ64850

Query related to month and year [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have a table which contains Year and Month as columns like below:-
Id Year Month Value
1 2012 12 100
2 2013 1 200
3 2013 2 300
4 2013 12 200
5 2012 11 200
I want to create a query which gives me values with (year >= 2012 and month >= 12) and also (year =< 2013 and month =< 12) i.e. It should give me Id 1, 2, 3, 4.
EDIT
This is just an example to demonstrate the behavior.
The months and Year might vary. So please create an answer that suits the condition for any year and any month that are passed.
How can I create a query with the following condition?
Regards
Vishal
This should get you what you want
SELECT id
FROM YourTable
WHERE (Year = '2013' OR (Year = '2012' AND Month = '12'))
I hope I've understood your conditions now ("i want 2012 12 month abd 2013 1 to 12 month data"):
SELECT Id FROM TableName WHERE (Year = 2012 AND Month = 12) OR (Year = 2013) ORDER BY Id
This is assuming there can't be a month > 12 or < 1 ;-)
declare #YearFrom int, #YearTo int, #MonthFrom int, #MonthTo int
set #YearFrom = 2012
set #YearTo = 2013
set #MonthFrom = 12
set #MonthTo = 12
select ID, YEAR, MONTH, Value
from [yourtable]
WHERE (year = #yearfrom AND month >= #monthfrom or year > #yearfrom)
AND (year = #yearto AND month <= #monthto or year < #yearto)
I think the easiest way is to convert the columns to a bigger integer (or string). Assuming the values are integers:
select id
from table
where year*100+month between 201212 and 201312;
edit based on comment
For a given #yearIN
select * from table
where (year = #yearIN and month != 12) or (year = (#yearIN-1) and month = 12)
I think this is what you want
select * from table
where (year = 2013 and month != 12) or (year = 2012 and month = 12)
I think this makes the logic of what you are looking for clearer -- I expect you don't want the last month of 2011

Last three months average for each month in PostgreSQL query

I'm trying to build a query in Postgresql that will be used for a budget.
I currently have a list of data that is grouped by month.
For each month of the year I need to retrieve the average monthly sales from the previous three months. For example, in January I would need the average monthly sales from October through December of the previous year. So the result will be something like:
1 12345.67
2 54321.56
3 242412.45
This is grouped by month number.
Here is a snippet of code from my query that will get me the current month's sales:
LEFT JOIN (SELECT SUM((sti.cost + sti.freight) * sti.case_qty * sti.release_qty)
AS trsf_cost,
DATE_PART('month', st.invoice_dt) as month
FROM stransitem sti,
stocktrans st
WHERE sti.invoice_no = st.invoice_no
AND st.invoice_dt >= date_trunc('year', current_date)
AND st.location_cd = 'SLC'
AND st.order_st != 'DEL'
GROUP BY month) as trsf_cogs ON trsf_cogs.month = totals.month
I need another join that will get me the same thing, only averaged from the previous 3 months, but I'm not sure how.
This will ALWAYS be a January-December (1-12) list, starting with January and ending with December.
This is a classic problem for a window function. Here is how to solve this:
SELECT month_nr
,(COALESCE(m1, 0)
+ COALESCE(m2, 0)
+ COALESCE(m3, 0))
/
NULLIF ( CASE WHEN m1 IS NULL THEN 0 ELSE 1 END
+ CASE WHEN m2 IS NULL THEN 0 ELSE 1 END
+ CASE WHEN m3 IS NULL THEN 0 ELSE 1 END, 0) AS avg_prev_3_months
-- or divide by 3 if 3 previous months are guaranteed or you don't care
FROM (
SELECT date_part('month', month) as month_nr
,lag(trsf_cost, 1) OVER w AS m1
,lag(trsf_cost, 2) OVER w AS m2
,lag(trsf_cost, 3) OVER w AS m3
FROM (
SELECT date_part( 'month', month) as trsf_cost -- some dummy nr. for demo
,month
FROM generate_series('2010-01-01 0:0'::timestamp
,'2012-01-01 0:0'::timestamp, '1 month') month
) x
WINDOW w AS (ORDER BY month)
) y;
This is requires that no month is ever missing! Else, have a look at this related answer:
How to compare the current row with next and previous row in PostgreSQL?
Calculates correct average for every month. If only two previous moths then devide by 2, etc. If no prev. months, result is NULL.
In your subquery, use
date_trunc('month', st.invoice_dt)::date AS month
instead of
DATE_PART('month', st.invoice_dt) as month
so you can sort months over the years easily!
More info
Window function lag()
date_trunc()