SQLite - Negative value by substracting months of different years - sql

I am trying to retrieve the month value of a calculation :
SELECT strftime('%m', 'now') - strftime('%m', e.date) AS something FROM ...
But here are the results I get and what I really want :
NOW - 2012-02-03 = 0 // want 11
NOW - 2012-11-02 = -9 // want 3
NOW - 2012-02-02 = 0 // want 12
NOW - 2012-01-02 = 1 // want 13
As I can see I can almost get the right values by doing sqlResult + 12 (except for first example) but is there a way to achieve this directly in the SQL statement and to get exact values in every case ?
EDIT : Finally here is the solution
SELECT CAST ((julianday('now') - julianday(e.date_retour)) / 30 AS integer) AS something

You need to take the year into account. You can do this as:
select strftime('%Y', 'now')*12+strftime('%m', 'now') -
(strftime('%Y', e.date)*12+strftime('%m', e.date))
The month returns the month of the year. So, it is no surprise that something like 2 (February) - 9 (September) produces a negative number.
To handle day of month, I think you have to handle the date arithmetic yourself:
select (strftime('%Y', 'now')*12+strftime('%m', 'now') -
(strftime('%Y', e.date)*12+strftime('%m', e.date))
) -
(case when strftime('%d', 'now') < strftime('%d', e.date) then 0 else 1 end)
SQLite has the ability to add months to a date. Unfortunately, it doesn't seem to have the ability to take the difference in months between dates.

You are not really looking at difference between two months but, considering their years as well.
So you need to do like this:
SQLite (SQL.js) Demo
SELECT round((julianday(Date('now')) -
julianday(Dates))/30) as MonthsDiff
from demo;
| MonthsDiff |
--------------
| 11.0 |
| 2.0 |

you are getting the weird numbers because you are asking the strftime function to return only the month and then you are subtracting only the months...
How about you do this?
SELECT strftime('%s', date()) - strftime('%s', '2012-03-03') as blah
this will subtract the unix timestamps and then you can convert it back to readable months or whatever...
or this could give you number of days...
SELECT julianday(date()) - julianday('2012-03-03') as blah

Related

SQL Date Format - Display the time difference as X days X hours X mins

I wanted to display the difference between 2 timestamps in the format like 'X days X hours X mins' (e.g. 2 days 2 hours 3 mins).
The best I can do now is date_trunc('minutes',sysdate) - date_trunc('minutes',createdate::timestamp) as age, which gives me the result like 1 day 06:05:00. And then I do the extract with the following to get the each part. Then I can concat them..
extract(day from age) as days_age,
extract (hour from age) - 24 * extract(day from age) as hours_age,
extract (min from age) - 24 * 60 * days_age - 60 * hours_age,
Is there a better way to do so?
Thanks!
The best solution is to combineto use Redshift function DATEDIFF.
Example to retrieve the number of day between 2 timestamps:
DATEDIFF('day', timestamp1, timestamp2)
DATEDIFF returns a BIGINT, so depending on the expected result you may cast it to string to concatenate it with the 'minute' part and so on, or do something else.
For example, to get
2 days 2 hours 3 mins
:
DATEDIFF('day', timestamp1, timestamp2)::text | ' days ' | DATEDIFF('hour', timestamp1, timestamp2)::text | ' hours ' | DATEDIFF('minute', timestamp1, timestamp2)::text | ' minutes'
https://docs.aws.amazon.com/redshift/latest/dg/r_DATEDIFF_function.html
https://docs.aws.amazon.com/redshift/latest/dg/r_DATE_PART_function.html

Get month,days difference between two date columns

I'm trying to fix some problems in my database and i want to re-calculate column in my db based on other 2 date columns. This col is float and i want to get the difference between 2 dates in months with decimal point for days.
For example if i have 2 dates '2016-01-15', '2015-02-01' the difference should be 12.5 best of 12 months differences and 0.5 for the remaining 15 days
Here is what i tried so far based on my searches but i think there is something i'm missing as it tells me there is an error with my date col as it doesn't exist
Select EXTRACT(year FROM vehicle_delivery(date, vehicle_received_date))*12 + EXTRACT(month FROM vehicle_delivery(date, vehicle_received_date));
Where vehicle_delivery is my table name & date is my end date and vehicle_received_date is my start date
same thing happes with this sql :
select extract('years' from vehicle_delivery) * 12 + extract('months' from vehicle_delivery) + extract('days' from vehicle_delivery) / 30
from (select age(date::timestamp, vehicle_received_date::timestamp)) a;
The SQL should look like this:
select extract(year from diff) * 12 + extract(month from diff) + extract(day from diff) / 30
from (select age(date::timestamp, vehicle_received_date::timestamp) as diff
from vehicle_delivery
) vd;
I don't know what the purpose of the / 30 is, but you appear to want it.
Notes:
The FROM clause references the table.
The first argument in extract() is a keyword, not a string.
You want to reference the age() value in the extract().
extract() returns an interval, so it is rather redundant to take out the parts (only needed if you want them in separate columns).

Oracle correctly getting the month difference

Hi Ive been having an issue with getting the correct difference in a date from the current month not including the day.
ie if the month when the query is run is march 2013
then the following should be the result
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 2
however using the below sql statement im getting
EXECUTION_DATE, EXEC_DIFF
01-FEB-13, 1
31-JAN-13, 2
30-JAN-13, 1
select EXECUTION_DATE,
floor(MONTHS_BETWEEN (trunc(sysdate,'MM')-1, EXECUTION_DATE))+1 "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
Please can someone put me right ive been bashing my head with this for some time now
thanks
select EXECUTION_DATE,
MONTHS_BETWEEN (trunc(sysdate,'MM'), trunc(EXECUTION_DATE,'MM')) "EXEC_DIFF"
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
Not looking for scores but cannot understand what is the problem with months_between? In my understanding it does not matter when in month execution takes place - Jan-31 or Jan 30... The difference is still 2 months between Jan and Mar as in your example. I can add more days in month in the query but mo_betw. will still be the same...:
SELECT to_char(exec_date, 'DD-MON-YYYY') exec_date, MONTHS_BETWEEN(run_date, exec_date) months_btwn
FROM
(
SELECT to_date('01/03/2013', 'DD/MM/YYYY') run_date
, Add_Months(Trunc(sysdate,'YEAR'),Level-1) exec_date -- first day of each month
FROM dual
CONNECT BY LEVEL <= 3
)
/
EXEC_DATE MONTHS_BTWN
------------------------
01-JAN-2013 2
01-FEB-2013 1
01-MAR-2013 0
Months_Between has complex logic that takes the day of the month into account.
Perhaps what you want is this:
select EXECUTION_DATE,
((year(sysdate)*12+month(sysdate)) - (year(execution_date)*12 + month(execution_date))
) as Exec_Diff
from V_CERT_LIST
WHERE EXECUTION_DATE < TO_DATE('02/02/2013','DD/MM/YYYY')
ORDER BY EXECUTION_DATE DESC
This converts the year/month combination into the number of months since 0 time and then subtracts the results.

AS400 SQL query to determine records for who is 70.5 years old for the current year

I am trying to find individuals that will turn 70.5 years old in the current year.
dob7 = DECIMAL(7) YYYYDDD
select acctno, name, address, status, year(curdate()) - year(date(digits(dob7))) as Age
from mydata.cdmast cdmast
left join mydata.cfmast cfmast
on cdmast.cifno = cfmast.cifno
where status <> 'R' and year(curdate()) - year(date(digits(dob7))) >= 70
The code above returns the following error:
[Error Code: -181, SQL State: 22008] [IBM][System i Access ODBC Driver][DB2 for i5/OS]SQL0181 - Value in date, time, or timestamp string not valid.
After seeing the other answers, I'm submitting my own. This should have the benefit of using any indicies on dob7, and should work without too many 'tricks'.
I've modified the WHERE clause in your original query. I'm assuming '.5 years' means '6 months', although this is adjustable. I deliberately wrapped the calculations in CTEs to 'encapsulate' the logic; the operations should be nearly no-cost.
WITH Youngest (dateOfBirth) as (
SELECT CURRENT_DATE - 70 YEARS - 6 MONTHS
FROM sysibm/sysdummy1),
Converted (dateOfBirth, formatted) as (
SELECT dateOfBirth, YEAR(dateOfBirth) * 1000 + DAYOFYEAR(dateOfBirth)
FROM Youngest)
SELECT acctno, name, address, status,
YEAR(CURRENT_DATE) - INT(dob7 / 1000)
- CASE WHEN DAYOFYEAR(CURRENT_DATE) < MOD(dbo7, 1000)
THEN 1
ELSE 0 END as Age
FROM myData.cdMast cdMast
JOIN Converted
ON Converted.formatted >= dob7
LEFT JOIN myData.cfMast cfMast
ON cdMast.cifno = cfMast.cifno
WHERE status <> 'R'
Please note that it will consider people born on a leap day to have had their birthday on March 1st (due to DAYOFYEAR()).
From the DATE scalar function documentation:
A string with an actual length of 7 that represents a valid date in the form yyyynnn, where yyyy are digits denoting a year, and nnn are digits between 001 and 366 denoting a day of that year.
Reformat the date with:
DATE(SUBSTR(DIGITS(DOB7),4,4) || SUBSTR(DIGITS(DOB7),1,3))
To select 70.5 or older by the end of the current year:
YEAR(CURRENT_DATE) - YEAR(DATE(SUBSTR(DIGITS(DOB7),4,4) || SUBSTR(DIGITS(DOB7),1,3))) = 70
AND MONTH(DATE(SUBSTR(DIGITS(DOB7),4,4) || SUBSTR(DIGITS(DOB7),1,3))) >= 6
OR YEAR(CURRENT_DATE) - YEAR(DATE(SUBSTR(DIGITS(DOB7),4,4) || SUBSTR(DIGITS(DOB7),1,3))) > 70
The error message is saying that the contents of DOB7 cannot be converted to a date. Does the value of DOB7 match one of the valid formats? Note that many require quotation marks. http://publib.boulder.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/db2/rbafzscadate.htm
Try this instead:
(year(curdate()) - mod(dob7, 10000)) >= 70
This is using modular arithmetic to extract the year, rather than trying to convert it to a date.
By the way, storing the date this way seems very awkward. Databases have built-in support for dates and times, so it is usually better to store them in the native format.
If you date of birth is really yyyymmm, then the following should work for years:
(year(curdate()) - cast(dob7/1000 as int)) >= 70
For the half year:
(year(curdate()) - cast(dob7/1000 as int))+(1-mod(dob7,1000)/365.0) >= 70.5

Oracle week calculation issue

I am using Oracle's to_char() function to convert a date to a week number (1-53):
select pat_id,
pat_enc_csn_id,
contact_date,
to_char(contact_date,'ww') week,
...
the 'ww' switch gives me these values for dates in January of this year:
Date Week
1-Jan-10 1
2-Jan-10 1
3-Jan-10 1
4-Jan-10 1
5-Jan-10 1
6-Jan-10 1
7-Jan-10 1
8-Jan-10 2
9-Jan-10 2
10-Jan-10 2
11-Jan-10 2
12-Jan-10 2
a quick look at the calendar indicates that these values should be:
Date Week
1-Jan-10 1
2-Jan-10 1
3-Jan-10 2
4-Jan-10 2
5-Jan-10 2
6-Jan-10 2
7-Jan-10 2
8-Jan-10 2
9-Jan-10 2
10-Jan-10 3
11-Jan-10 3
12-Jan-10 3
if I use the 'iw' switch instead of 'ww', the outcome is less desirable:
Date Week
1-Jan-10 53
2-Jan-10 53
3-Jan-10 53
4-Jan-10 1
5-Jan-10 1
6-Jan-10 1
7-Jan-10 1
8-Jan-10 1
9-Jan-10 1
10-Jan-10 1
11-Jan-10 2
12-Jan-10 2
Is there another Oracle function that will calculate weeks as I would expect or do I need to write my own?
EDIT
I'm trying to match the logic used by Crystal Reports. Each full week starts on a Sunday; the first week of the year starts on whichever day is represented by January 1st (e.g. in 2010, January 1st is a Friday).
When using IW, Oracle follows the ISO 8601 standard regarding week numbers (see http://en.wikipedia.org/wiki/ISO_8601). That is the same standard than the one we generally use in Europe here.
Your problem is also mentioned on the Oracle forum: http://forums.oracle.com/forums/thread.jspa?threadID=947291 and http://forums.oracle.com/forums/message.jspa?messageID=3318715#3318715. Maybe you can find a solution there.
I know this is old, but still a common question.
This should give you the correct results in the smallest amount of effort:
select pat_id,
pat_enc_csn_id,
contact_date,
to_char(contact_date + 1,'IW') week,
...
Since it looks like you are using your own special definition of the week number you'll need to write your own function.
It might be helpful that NLS_TERRITORY affects the day with which a week starts as used by the D Format Model
see also:
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#SQLRF00210
and
http://www.adp-gmbh.ch/ora/sql/to_char.html
Based on this question, How do I calculate the week number given a date?, I wrote the following Oracle logic:
CASE
--if [date field]'s day-of-week (e.g. Monday) is earlier than 1/1/YYYY's day-of-week
WHEN to_char(to_date('01/01/' || to_char([date field],'YYYY'),'mm/dd/yyyy'), 'D') - to_char([date field], 'D') > 1 THEN
--adjust the week
trunc(to_char([date field], 'DDD') / 7) + 1 + 1 --'+ 1 + 1' used for clarity
ELSE trunc(to_char([date field], 'DDD') / 7) + 1
END calendar_week