Average age using months_between() - sql

So I have a table with the birth dates and I need to average the people's age. How do I do that? I know I have to use months_between(). Thank you in advance!

Why do you think you need months_between? You don't (unless you have a very specific and unusual definition of "average age").
Over a long enough period (like 40+ years, say), a person's age in years can be calculated (within a narrow approximation window) as the age in days, divided by 365.25. The age in days is simply a difference between two dates, SYSDATE and DATE_OF_BIRTH or BORN. The first one is provided by the system and the second is in your table. Assuming, that is, that you want age as of today; otherwise change SYSDATE to whatever "as-of" (fixed) date you want to use.
So, something like
select [some columns here], AVG(SYSDATE - BORN)/365.25 as avg_age
from your_table
Not clear why you would select max(born) from dual; surely you didn't call your table dual? Nor did you change the standard dual table to add your own data to it?
When people ask you what datatype you use for born in your tables, what you see on the screen when you query for it is not sufficient; the screen will show a string (it's the only thing a screen shows) and doesn't necessarily reflect what's in the database. To get the proper answer, run DESCRIBE table_name; that will show all the columns in table_name and their datatype. Note that DESCRIBE table_name is a SQL*Plus command (understood by Toad and SQL Developer - whatever you use to communicate with the database), so it doesn't need a ; or a / at the end. Just type it at the prompt and hit ENTER.
Good luck!

Related

Selecting Between Hours with Timestamp in SQL

I need to figure out how I can select the AVG from another column in a table, between two hour time intervals. I am using PL/SQL/Serverpages or PSP, so the user would select their interval of choice from a drop down menu (ex "2PM-4PM, 4PM-6PM",etc.) and then on the second page, using their choice I will provide information from another column in the table. The issue I have is that the format of my timestamp column is:
30-OCT-16 02.52.00.000000000 PM
30-OCT-16 02.54.00.000000000 PM
The way I have been trying to solve this problem is by using the following methodology:
IF number_text = 1 THEN
SELECT AVG(column) INTO avg_power
FROM table
WHERE date_column BETWEEN TO_DATE('12','HH') AND TO_DATE('2','HH')
AND LIKE '%PM';
I am going to use various IF statements in order to activate each select statement with the IF contingent on which interval the user selects from a drop down list.
As I said, the variable time depends on what the user selects on a prior page. My biggest issues in this situation are figuring out how I am supposed to code the WHERE clause as well as finding a way to work with the data, in terms of hours, as it exists in the database, while also taking AM and PM into account. I greatly appreciate any and all help to solve this issue.

There's duplicated query result in Microsoft Access while checking for time overlapping

I got a table with a huge list of equipment booking details. I wrote a SQL Query to display the desired result that I wanted: A type of the equipment with time overlapping of booking.
So I check for the time overlapping by duplicating my table in order for it to check against each other.
The result I gotten are kind of repetitive?
For instance,
May CLASHES Claire
May CLASHES Sherene
Claire CLASHES May
Claire CLASHES Sherene
Sherene CLASHES May
Those in bold are repetitive.
How can I modify my SQL query in order to resolve the issue?
Please kindly advise. Thank you!
SELECT DISTINCT *
FROM 2015, 2015 AS 2015_1
WHERE ([2015].Equipment Like '*Video cam*' Or [2015].Equipment Like '*video recorder*' Or [2015].Equipment Like '*camcorder*')
AND ([2015_1].Equipment Like '*Video cam*' Or [2015_1].Equipment Like '*video recorder*' Or [2015_1].Equipment Like '*camcorder*')
AND ([2015].[Loaned By]<>[2015_1].[Loaned By])
AND ([2015_1].[Start Time]<=[2015].[End Time])
AND ([2015_1].[End Time] Is Null Or [2015_1].[End Time]>=[2015].[Start Time]);
EDIT
My table is called 2015.
The variables are (Field Name - Data Type):
ID - Number
Loaned By - Text
Equipment - Text
Start Date - Date/Time
Start Time - Date/Time
End Date - Date/Time
End Time - Date/Time
Durations (hours) - Number
You can add the following condition:
[2015].EquipmentType < [2015_1].EquipmentType
This will order them alphabetically.
Your question doesn't have enough information to clearly specify the column.

applying knowledge of SQL for everyday workplace activities

My question is how to properly write a SQL query for the below highlighted/bold question.
There is a table in HMO database which stores doctor's working
hours.Table has following fields
"FirstName","LastName","Date","HoursWorked". write a sql statement
which retrieves average working hours for period January-March for a
doctor with name Joe Doe.
so far i have
SELECT HoursWorked
FROM Table
WHERE DATE = (January - March) AND
SELECT AVG(HoursWorked) FROM Table WHERE FirstName="Joe",LastName="Doe"*
A few pointers as this sounds like a homework question (which we don't answer for you here, but we can try to give you some guidance).
You want to put all the things you want to return from your select first and you want to have all your search conditions at the end.
So the general format would be :
SELECT Column1,
Column2,
Column3,
FROM YourTable
WHERE Column4 = Restriction1
AND Column5 = Restriction2
The next thing you need to think about is how the dates are formatted in your database table. Hopefully they're kept in a column of type datetime or date (options will depend on the database engine you're using, eg, Microsoft SQL Server, Oracle or MySql). In reality some older databases people use can store dates in all sorts of formats which makes this much harder, but since I'm assuming it's a homework type question, lets assume it's a datetime format.
You specify restrictions by comparing columns to a value, so if you wanted all rows where the date was after midnight on the 2nd of March 2012, you would have the WHERE clause :
WHERE MyDateColumn >= '2012-03-02 00:00:00'
Note that to avoid confusion, we usually try to format dates as "Year-Month-Day Hour:Minute:Second". This is because in different countries, dates are often written in different formats and this is considered a Universal format which is understood (by computers at least) everywhere.
So you would want to combine a couple of these comparisons in your WHERE, one for dates AFTER a certain date in time AND one for dates before another point in time.
If you give this a go and see where you get to, update your question with your progress and someone will be able to help get it finished if you have problems.
If you don't have access to an actual database and need to experiment with syntax, try this site : http://sqlfiddle.com/
you already have the answer written
SELECT AVG(HoursWorked) FROM Table WHERE FirstName="Joe",LastName="Doe"*
you only need to fix the query
SELECT AVG(HoursWorked) as AVGWORKED FROM Table WHERE FirstName='Joe' AND LastName='Doe'
That query will give you the average hours worked for Joe Doe, however you only need to get between some time you add the next "AND", if you are using SQL server you can use the built in function DateFromParts(year,month,day) to create a new Date, or if you are using another Database Engine you can convert a string to a DateColumn Convert(Date,'MM/dd/yyyy')
Example
SELECT AVG(HoursWorked) as AVGWORKED FROM Table WHERE FirstName='Joe' AND LastName='Doe' AND DateColumn between DateFromParts(year,month,day) and Convert(Date,'MM/dd/yyyy')
In the example i showed both approaches (datefromparts for the initial date, and convert(date) for the ending date).

How can I get the average of a date field?

I want to get the average of days between some dates, for example, I have a table called Patient that has the id of the registration, patient's id, entry date and final date:
(1,1,'07-04-2014','08-04-2014'),
(2,2,'07-04-2014','07-04-2014'),
(3,3,'08-04-2014','10-04-2014'),
(4,4,'09-04-2014','10-04-2014')
I want to get the average of days of the entry fields, I have tried a lot of thing but I only get random results. I tried with dtiff but it needs two arguments and I only need one.
You could get the average DURATION between a fixed date and the date field. But averaging a date doesn't really make sense.
SELECT AVG(DATEDIFF(DD,'19700101',dateField)) AS avgDays
You could say the "average" date would then be: DATEADD(DD,avgDays,'19700101')
But I'm not sure if that makes sense in the context of what you're trying to do.
thanks for answering, maybe I couldn't express what I wanted to do but I found a solution and it was actually vey simple:
select Patient.Name, avg(day(Patient.FinalDate) - day(Patient.EntryDate)) as [Average] from Patient,DetailPatient where Patient.IdPatient=DetailPatient.IdPatiene group by DetailPatient.Name
I know it looks very simple haha, but is the first time I use avg function this way.
Thank you guys.

How to design SQL tables when column data arrives in multiple types/margins of error?

I've been given a stack of data where a particular value has been collected sometimes as a date (YYYY-MM-DD) and sometimes as just a year.
Depending on how you look at it, this is either a variance in type or margin of error.
This is a subprime situation, but I can't afford to recover or discard any data.
What's the optimal (eg. least worst :) ) SQL table design that will accept either form while avoiding monstrous queries and allowing maximum use of database features like constraints and keys*?
*i.e. Entity-Attribute-Value is out.
You could store the year, month and day components in separate columns. That way, you only need to populate the columns for which you have data.
if it comes in as just a year make it default to 01 for month and date, YYYY-01-01
This way you can still use a date/datetime datatype and don't have to worry about invalid dates
Either bring it in as a string unmolested, and modify it so it's consistent in another step, or modify the year-only values during the import like SQLMenace recommends.
I'd store the value in a DATETIME type and another value (just an integer will do, or some kind of enumerated type) that signifies its precision.
It would be easier to give more information if you mentioned what kind of queries you will be doing on the data.
Either fix it, then store it (OK, not an option)
Or store it broken with a fixed computed columns
Something like this
CREATE TABLE ...
...
Broken varchar(20),
Fixed AS CAST(CASE WHEN Broken LIKE '[12][0-9][0-9][0-9]' THEN Broken + '0101' ELSE Broken END AS datetime)
This also allows you to detect good from bad source data
If you don't always have a full date, what sort of keys and constraints would you need? Perhaps store two columns of data; a full date, and a year. For data that has only year, the year is stored and date is null. For items with full info, both are populated.
I'd put three columns in the table:
The provided value (YYYY-MM-DD or YYYY)
A date column, Date or DateTime data type, which is nullable
A year column, as an integer or char(4) depending upon your needs.
I'd always populate the year column, populate the date column only when the provided value is a date.
And, because you've kept the provided value, you can always re-process down the road if needs change.
An alternative solution would be to that of a date mask (like in IP). Store the date in a regular datetime field, and insert an additional field of type smallint or something, where you could indicate which is present (could go even binary here):
If you have YYYY-MM-DD, you would have 3 bits of data, which will have the values 1 if data is present and 0 if not.
Example:
Date Mask
2009-12-05 7 (111)
2009-12-01 6 (110, only year and month are know, and day is set to default 1)
2009-01-20 5 (101, for some strange reason, only the year and the date is known. January has 31 days, so it will never generate an error)
Which solution is better depends on what you will do with it.
This is better when you want to select those with full dates, which are between a certain period (less to write). Also this way it's easier to compare any dates which have masks like 7,6,4. It may also take up less memory (date + smallint may be smaller than int+int+int, and only if datetime uses 64 bit, and smallint uses up as much as int, it will be the same).
I was going to suggest the same solution as #ninesided did above. Additionally, you could have a date field and a field that quantitatively represents your uncertainty. This offers the advantage of being able to represent things like "on or about Sept 23, 2010". The problem is that to represent the case where you only know the year, you'd have to set your date to be the middle of the year, with 182.5 days' uncertainty (assuming non-leap year), which seems ugly.
You could use a similar but distinct approach with a mask that represents what date parts you're confident about - that's what SQLMenace offered in his answer above.
+1 each to recommendations from ninesided, Nikki9696 and Jeff Siver - I support all those answers though none was exactly what I decided upon.
My solution:
a date column used only for complete dates
an int column used for years
a constraint to ensure integrity between the two
a trigger to populate the year if only date is supplied
Advantages:
can run simple (one-column) queries on the date column with missing data ignored (by using NULL for what it was designed for)
can run simple (one-column) queries on the year column for any row with a date (because year is automatically populated)
insert either year or date or both (provided they agree)
no fear of disagreement between columns
self explanatory, intuitive
I would argue that methods using YYYY-01-01 to signify missing data (when flagged as such with a second explanatory column) fail seriously on points 1 and 5.
Example code for Sqlite 3:
create table events
(
rowid integer primary key,
event_year integer,
event_date date,
check (event_year = cast(strftime("%Y", event_date) as integer))
);
create trigger year_trigger after insert on events
begin
update events set event_year = cast(strftime("%Y", event_date) as integer)
where rowid = new.rowid and event_date is not null;
end;
-- various methods to insert
insert into events (event_year, event_date) values (2008, "2008-02-23");
insert into events (event_year) values (2009);
insert into events (event_date) values ("2010-01-19");
-- select events in January without expressions on supplementary columns
select rowid, event_date from events where strftime("%m", event_date) = "01";