I know there are a lot a ways to calculate the difference between to dates in different databases. My problem is that I need a way to do that that will work in both SQL Server and DB2 using the same SQL query.
On a yearly basis I can use
CURRENT_TIMESTAMP - [BIRTHDATE] AS AGETHISYEAR
But I also want to know a persons age in decimal form i.e. 34,4 depending on the persons birthday and current date.
In SQL Server the columntype for [BIRTHDATE] is DATETIME and in DB2 the column type is DATE.
The format is YYYY-MM-DD
Is there a way to do this?
Regards,
Alfred
I think the only way you can write a function that would work in both databases would be to use year(), month(), and day(), or to write functions yourself. There is not that much overlap in the date functions between the two databases.
For instance, to get the full years between two dates, you could use:
select (year(CURRENT_TIMESTAMP) - year(birthdate) +
(case when month(CURRENT_TIMESTAMP) * 100 + day(CURRENT_TIMESTAMP) <
month(birthdate) * 100 + day(birthdate)
then -1 else 0
end)
) as AgeInYears
Fractional years would be much more complicated. Of course, each database has its own more reasonable methods for getting what you want. The methods are different.
Related
i'm new here and it's all a bit confusing, so i'm gonna excuse myself in the beginning, if i do something wrong here.
I usually used MySQL or sometimes Oracle but now I have to switch to Teradata.
Simply i need to convert this:
SELECT FLOOR(DATEDIFF(NOW(),`startdate`)/365.25) AS `years`,
COUNT(FLOOR(DATEDIFF(NOW(),`startdate`)/365.25)) AS `numberofemployees`
FROM `employees`
WHERE 1
GROUP BY `years`
ORDER BY `years`;
into teradata.
Would be great if someone could help :)
Equivalent of your query in Teradata would be :
SELECT FLOOR((CURRENT_DATE - startdate)/365.2500) AS years,
COUNT(FLOOR((CURRENT_DATE - startdate )/365.2500)) AS numberofemployees
FROM employees
--WHERE 1
GROUP BY years
ORDER BY years;
CURRENT_DATE is equivalent to NOW() (without the time part, part DATEDIFF would have ignored it, anyway).
In Teradata you can simply subtract dates to get days in between.
Also, I added two zeroes at the end of 365.25 to force Teradata to evaluate the division to 4 decimal places, because MySQL seems to perform it that way (https://dev.mysql.com/doc/refman/8.0/en/arithmetic-functions.html#:~:text=In%20division%20performed%20with%20/%2C%20the%20scale%20of%20the%20result%20when%20using%20two%20exact-value%20operands%20is%20the%20scale%20of%20the%20first%20operand%20plus%20the%20value%20of%20the%20div_precision_increment%20system%20variable%20(which%20is%204%20by%20default).
But, I am not sure if Understood your original query thoroughly:
What does WHERE 1 do?
Why do you count the years column and call it numberofemployees (why not simply do count(*))
what command should I use to make an output based on this problem:
Display the all values of customers who have joined as members for more than 700 days until today
This is the table that I have created:
table Customers
I've tried other references using DATEDIFF(), but it's always invalid :
SELECT * FROM Customers where DATEDIFF(DAY,customer_join,GETDATE())>700;
In MySQL/MariaDB, as opposed to SQL Server, DATEDIFF() takes just two arguments, and returns an integer number of days between them. We have timestampdiff(), which takes three arguments.
Also, getdate() is not a thing in MySQL (this is a bespoke SQL Server function).
You don't really need date functions here. I would phrase this logic using simple data arithmetics:
select *
from customers
where customer_join < current_date - interval 700 day
This expression can take advantage of an index on customer_join.
Depending on whether you want to take in account the time portion of customer_join (if it has one), you might want to use now() instead of current_date.
suppose I have a table MyTable with a column some_date (date type of course) and I want to select the newest 3 months data (or x days).
What is the best way to achieve this?
Please notice that the date should not be measured from today but rather from the date range in the table (which might be older then today)
I need to find the maximum date and compare it to each row - if the difference is less than x days, return it.
All of this should be done with sqlalchemy and without loading the entire table.
What is the best way of doing it? must I have a subquery to find the maximum date? How do I select last X days?
Any help is appreciated.
EDIT:
The following query works in Oracle but seems inefficient (is max calculated for each row?) and I don't think that it'll work for all dialects:
select * from my_table where (select max(some_date) from my_table) - some_date < 10
You can do this in a single query and without resorting to creating datediff.
Here is an example I used for getting everything in the past day:
one_day = timedelta(hours=24)
one_day_ago = datetime.now() - one_day
Message.query.filter(Message.created > one_day_ago).all()
You can adapt the timedelta to whatever time range you are interested in.
UPDATE
Upon re-reading your question it looks like I failed to take into account the fact that you want to compare two dates which are in the database rather than today's day. I'm pretty sure that this sort of behavior is going to be database specific. In Postgres, you can use straightforward arithmetic.
Operations with DATEs
1. The difference between two DATES is always an INTEGER, representing the number of DAYS difference
DATE '1999-12-30' - DATE '1999-12-11' = INTEGER 19
You may add or subtract an INTEGER to a DATE to produce another DATE
DATE '1999-12-11' + INTEGER 19 = DATE '1999-12-30'
You're probably using timestamps if you are storing dates in postgres. Doing math with timestamps produces an interval object. Sqlalachemy works with timedeltas as a representation of intervals. So you could do something like:
one_day = timedelta(hours=24)
Model.query.join(ModelB, Model.created - ModelB.created < interval)
I haven't tested this exactly, but I've done things like this and they have worked.
I ended up doing two selects - one to get the max date and another to get the data
using the datediff recipe from this thread I added a datediff function and using the query q = session.query(MyTable).filter(datediff(max_date, some_date) < 10)
I still don't think this is the best way, but untill someone proves me wrong, it will have to do...
I have two columns that contains datetimes and i need two add them together somehow. I've tried using sum but that didnt work. Im using sqlserver 2008.
Columns
loanPeriod = the loanperiod of the item
checkOutDate= when the item was borrowed
And Im trying to achieve this
lastreturndate = (checkoutDate + loanperiod)
select dateadd(month, loanperiod, checkoutdate) as lastreturndate
Most databases have a DATEADD() or DATEDIFF() function or similar.
Presumably, these are measured in days. So, you can do something like this:
select dateadd(day, datediff(day, 0, loanPeriod), checkoutDate)
It is odd to store the loan period as a datetime. If so, the date is going to look like some date early in the 1900s (unless the period is very long). The above converts it to days and then adds it to the check out date.
I'm trying to optimize up some horrendously complicated SQL queries because it takes too long to finish.
In my queries, I have dynamically created SQL statements with lots of the same functions, so I created a temporary table where each function is only called once instead of many, many times - this cut my execution time by 3/4.
So my question is, can I expect to see much of a difference if say, 1,000 datediff computations are narrowed to 100?
EDIT:
The query looks like this :
SELECT DISTINCT M.MID, M.RE FROM #TEMP INNER JOIN M ON #TEMP.MID=M.MID
WHERE ( #TEMP.Property1=1 ) AND
DATEDIFF( year, M.DOB, #date2 ) >= 15 AND DATEDIFF( year, M.DOB, #date2 ) <= 17
where these are being generated dynamically as strings (put together in bits and pieces) and then executed so that various parameters can be changed along each iteration - mainly the last lines, containing all sorts of DATEDIFF queries.
There are about 420 queries like this where these datediffs are being calculated like so. I know that I can pull them all into a temp table easily (1,000 datediffs becomes 50) - but is it worth it, will it make any difference in seconds? I'm hoping for an improvement better than in the tenths of seconds.
It depends on exactly what you are doing to be honest as to the extent of the performance hit.
For example, if you are using DATEDIFF (or indeed any other function) within a WHERE clause, then this will be a cause of poorer performance as it will prevent an index being used on that column.
e.g. basic example, finding all records in 2009
WHERE DATEDIFF(yyyy, DateColumn, '2009-01-01') = 0
would not make good use of an index on DateColumn. Whereas a better solution, providing optimal index usage would be:
WHERE DateColumn >= '2009-01-01' AND DateColumn < '2010-01-01'
I recently blogged about the difference this makes (with performance stats/execution plan comparisons), if you're interested.
That would be costlier than say returning DATEDIFF as a column in the resultset.
I would start by identifying the individual queries that are taking the most time. Check the execution plans to see where the problem lies and tune from there.
Edit:
Based on the example query you've given, here's an approach you could try out to remove the use of DATEDIFF within the WHERE clause. Basic example to find everyone who was 10 years old on a given date - I think the maths is right, but you get the idea anyway! Gave it a quick test, and seems fine. Should be easy enough to adapt to your scenario. If you want to find people between (e.g.) 15 and 17 years old on a given date, then that's also possible with this approach.
-- Assuming #Date2 is set to the date at which you want to calculate someone's age
DECLARE #AgeAtDate INTEGER
SET #AgeAtDate = 10
DECLARE #BornFrom DATETIME
DECLARE #BornUntil DATETIME
SELECT #BornFrom = DATEADD(yyyy, -(#AgeAtDate + 1), #Date2)
SELECT #BornUntil = DATEADD(yyyy, -#AgeAtDate , #Date2)
SELECT DOB
FROM YourTable
WHERE DOB > #BornFrom AND DOB <= #BornUntil
An important note to add, is for age caculates from DOB, this approach is more accurate. Your current implementation only takes the year of birth into account, not the actual day (e.g. someone born on 1st Dec 2009 would show as being 1 year old on 1st Jan 2010 when they are not 1 until 1st Dec 2010).
Hope this helps.
DATEDIFF is quite efficient compared to other methods of handling of datetime values, like strings. (see this SO answer).
In this case, it sounds like you going over and over the same data, which is likely more expensive than using a temp table. For example, statistics will be generated.
One thing you might be able do to improve performance might be to put an index on the temp table on MID.
Check your execution plan to see if it helps (may depend on the number of rows in the temp table).