Using decode with to_date - sql

If anyone could help me with the following, I'd be grateful:
I'm trying to write a code (create an alert in PowerSchool) that will indicate if a student is younger or older than average for their current grade level. (For example, as student born before 6/30/2002 is older than average for 9th grade) I can't seem to make DECODE work in conjunction with >= TO_DATE. Here's my statement:
select lastfirst, decode (dob >= to_date ('2002-06-30', 'yyyy-mm-dd'), 'old') DOB
from students
where grade_level = 9
order by lastfirst

You probably could get away with using a PowerSchool decode in your sql, but I find code easier to write when fewer languages/systems are included, so I would leave it out. I would also let SQL do the average age calculation so you don't have to supply or calculate average dates yourself (see Averaging dates in oracle sql for an explanation of the TO_DATE line).
SELECT
LastFirst AS "Student Name"
,CASE WHEN dob >= (
SELECT
TO_DATE(ROUND(AVG(TO_NUMBER(TO_CHAR(dob, 'J')))),'J')
FROM Students
WHERE Grade_Level = 9
AND Enroll_Status = 0
) THEN 'Younger' ELSE 'Older' END AS "Older or Younger?"
FROM Students
WHERE Grade_Level = 9
ORDER BY LastFirst
The subquery calculates the average birthday, and the CASE statement compares each of your records against that, reporting if it's older or younger.
In the subquery that calculates the average, I've taken the liberty of assuming you only want to compare against currently enrolled students, since withdrawn students retain the same grade level. You don't really want those students who left 10 years ago and are still listed as a 9th grader to mess with your average numbers.

Related

SQL Query to get the Average age from multiple 'date' values

I'm needing to get a SQL Query which returns the average age of multiple data inputs in my table
Households
User
Dates
1
2002-01-01
2
2004-06-10
I want to grab both User 1 and 2 date of births and return the average age of them.
Managed to get the age from the date of births using
SELECT *, DATE_FORMAT(FROM_DAYS(DATEDIFF(NOW(), Date)), '%Y') + 0 AS age
FROM Households;
I just can't get the rest of it working to then average the ages out.
Assuming that you are running MySQL, as the syntax of your SQL code suggests.
For starts, I would recommend simplifying the age computation. MySQL provides timestampdiff(), which we can use like so:
select user_id, user_date,
timestampdiff(year, user_date, current_date) age
from houshold
user_id
user_date
age
1
2002-01-01
20
2
2004-06-10
18
3
2004-11-10
17
To compute the average age over all rows of the table, we can use aggregate function avg():
select avg(timestampdiff(year, user_date, current_date)) avg_age
from houshold
avg_age
18.3333
Here is a small demo based on your sample data. Note that I renamed the columns so they do not clash with meaningful SQL names.

How to use order by with modified column

There is a Table with a age-column. The Value of this column is a varchar because the age of persons under the age of 1 is saved in months with an additional 'm' (9 Month old -> '9m')
I know that this is generally a bad idea and one should rather persist the date of birth, but in this case the age refers to the age on a specific day in history - and additionally this is part of a lesson and the whole point is learning how to treat "weird" data.
My first idea was to put a leading zero on all ages which are not purely numeric:
SELECT *
FROM db
ORDER BY REPLACE(age, (IF ISNUMERIC(age) age ELSE CONCAT('0', age))) DESC;
However this is not a valid SQL-statement and neither are my other attempts.
The question is: How can I adjust the value used for ORDER BY without altering the db?
Another approach would be to select only the rows with a purely numeric age value and a separate select for the remaining rows order both of them separately and combine them afterwards.
My take on this was the following:
(SELECT name, age
FROM titanic
WHERE ISNUMERIC(age)
ORDER BY age DESC)
UNION
(SELECT name, age
FROM titanic
WHERE NOT ISNUMERIC(age)
ORDER BY age);
This is in fact valid or at least it gives me a result. But in the result I can't really see what happened to the order, it looks like the UNION undos everything.
Thanks in advance, will take any tip or even just the name of the function/method I should look into!
Would this work?
SELECT name, age
FROM titanic
ORDER BY isnumeric(age), age
I would use "Case When" structure with some transformations in the "Order by" to get the total number of months for both types of ages.
Select name, age
From tbl
Where age SIMILAR TO '[1-9][0-9]*' Or
age SIMILAR TO '[1-9][0-2]?m'
Order by Case When age SIMILAR TO '[1-9][0-2]?m' Then Substring(age,1,CHAR_LENGTH(age)-1)::int
When age SIMILAR TO '[1-9][0-9]*' Then age::int * 12 End
First off storing age is a poor idea, you must update every row regularly, in this case at least monthly. Storing it as string turns a poor idea into a terrible idea. Not only do you have the maintenance, it is not straight forward nor is it straight forward to insert it. Instead store date-of-birth as a timestamp or date. You can then quickly get age (via the age) you can then use the extract function on the resulting interval at whatever level is desired. If you absolutely must present age with text indicator for either years/months (or even days) you create a view that derives the appropriate value. (see demo)
create or replace view titanic as
select name "Name"
, case when extract( year from age(dob))::integer > 0 then to_char (extract( year from age(dob)), '999') || ' years'
when extract( month from age(dob))::integer> 0 then to_char (extract( month from age(dob)), '99') || ' months'
else to_char (extract( day from age(dob)),'99') || ' days'
end "Age"
from titanic_tbl;

SQL SUBQUERY in Sqlplus Oracle 11g Help please

Im trying to write a query that will list the Consultant_Id, Name and age for all consultants who have a Grade of 'D' in my Consultant table, and were born more than 30 years ago and have a name that begins with the letter 'L'. I need the output ascending age order. so far i have this but i presume there is multiple errors, any help would be greatly appreciated!
I don't want to seem to be attacking you, but since you said you've been trying to figure this out for a long time and you're stuck, let's look at some of the problems with what you have at the moment.
SELECT Consultant_Id, Name, DOB,
This line has a trailing comma.
FROM Consultant;
This line has a semicolon at the end, terminating the statement, so your where clause is a separate invalid command.
WHERE DOB = (SELECT MAX(DOB <= 01-jan-85) FROM CONSULTANT)
You seem to be using 01-jan-85 as a date, but even if it was in single quotes it would be a string not a date and you should explicitly convert it to a date type; without quotes it would get an invalid identifier (trying to treat 'jan' as a column name). Using the <= comparator inside a max() call isn't valid anyway, and I'm not quite sure what it's supposed to achieve. At best you're getting the most recent DOB from the table in the subquery, and then using that to filter the main query so you will only get the row (or maybe rows) that match that exact date. It won't give you all DOBs more than 30 years ago.
WHERE name( SELECT SUBSTR(Name,1,20) LIKE 'L%' AS ShortName)
name() isn't a function, so perhaps you meant to compare it with =; but as with the DOB check that isn't really what you wan. Your subquery doesn't have a from clause, and isn't correlated with the main query so would return multiple rows, which is an error in itself. As this is the second filter you should be using AND rather than a second WHERE. And the substr() isn't really adding anything since you're using like anyway.
WHERE Grade = 'D'
This is almost OK, but should also be AND not `WHERE.
ORDER BY SUBSTR(DOB, 7,9);
This is doing an implicit conversion of DOB to a string, then getting characters 7 to 15 of whatever your session converts it to by default. Based on the date string you used earlier you means substr(dob, 7, 2), which would give you the 2-digit year in that format; but you're supposed to be ordering by the whole DOB, not just the year.
#HepC has given the actual command you need (aside from the trailing comma on the first line).
I believe this is what you're looking for.
SELECT consultant_id, name, DOB
FROM consultant
WHERE DOB <= ADD_MONTHS((SYSDATE), -360)
AND grade = 'D'
AND name LIKE 'L%'
ORDER BY DOB;
SELECT consultant_id, name, DOB
FROM consultant
WHERE DOB <= ADD_MONTHS(TRUNC(SYSDATE), 12 * -30)
AND name LIKE 'L%'
AND grade = 'D'
ORDER BY DOB;
SELECT Consultant_Id, Name AS ShortName, DOB
FROM Consultant
WHERE DOB < dateadd(year, -30, getdate())
AND name LIKE 'L%'
AND Grade = 'D'
ORDER BY DOB

select from database

For a University course I've been given the following task
Suppose that we have an employee table like (first_name, last_name, salary, hire_date, ...). There is regulation which states that every employee each year after he/she is hired, must renew his contract with company. Show how many months remain before the next renewal for each employee.
This is my attempt:
select (abs(months_between(sysdate,hire_date)/12 -
round((months_between(sysdate,e.hire_date))/12)))
from employees e
is it correct?or what will be correct implementation
You are part of the way there, but this isn't it - what you have so far will show the modulus of months since hire date divided by 12, as a fraction.
What you need is to subtract the the modulus of months since hire date divided by 12, as a whole number, from 12.
So to take an example, an employee who was hired 13 months ago will return 0.0833333 in your supplied query - you want to see a result of (12 - (the remainder of 13/12 as a whole number - ie. 1)) = 11 months to go.
Most flavours of SQL have a modulus function, although the name and syntax may vary between SQLs.
Also, I would amend your query to include e.* as well as your calculation in your select statement.
If you start with a table like this:
create table my_table (
first_name varchar(15),
last_name varchar(15),
salary integer,
hire_date date
);
insert into my_table values ('A', 'Beemer', 30000, '2011-01-15');
insert into my_table values ('B', 'Catalog', 31000, '2011-01-27');
insert into my_table values ('C', 'Doir', 45000, '2011-03-11');
you can use a SELECT statement to return a result like this one.
first_name last_name salary hire_date renewal_date days_to_renewal
--
A Beemer 30000 2011-01-15 2012-01-15 57
B Catalog 31000 2011-01-27 2012-01-27 69
C Doir 45000 2011-03-11 2012-03-11 113
You should keep in mind that "month" is a fuzzy word that most database people hate with a white-hot, burning passion. It can mean 28, 29, 30, or 31 days on a real calendar. And you will always get blamed when expectations don't match common sense.
Running your query against my data returns these values. Clearly wrong.
LAST_NAME MONTHS_TO_RENEWAL
Beemer .154442577658303464755077658303464755078
Catalog .186700642174432497013142174432497013143
Doir .310356556152927120669056152927120669056
Oracle has a months_between() function that's documented to return "the number of months between two dates". You need to know exactly what "number of months" means to this function. (Again, given that a calendar month might have 28, 29, 30 or 31 days in it.) I'd be really surprised if you're expected to do the arithmetic any other way.
I'd suggest you start with this, and fill in the three missing pieces.
select first_name, last_name, salary, hire_date,
('date arithmetic to calculate the renewal date') renewal_date,
months_between('one date', 'another date') months_to_renewal
from my_table;

age from dob in sql

In the sql query, I am getting problem in the where clause.
I have a dob and ssn of people in a table. I need to find the youngest snr. customer. The age of youngest senior customer starts from 55. The data of DOB contains all the dob's of children,parent, senior customers. In the line "where" I have to write a condition that checks if the age is > 55 and has to be smaller amongst the senior customers.Please suggest me some ways .I posted a similar question before, but did nt get any reply that can help me in solving it.
I dont have the age parameter in my table.
SSn DOB
22 1950-2-2
21 1987-3-3
54 1954-4-7
I need to find the ssn corresponding to the age whcih has to be greater than 55 and smaller among above values .
In the script below, the sub-select finds the DOB of the youngest person 55 years of age or over; this is then used to find the corresponding SSN record(s). [This uses SQL Server syntax.]
SELECT yt.*
FROM *yourtable* yt
INNER JOIN
(
SELECT MAX(DOB) AS DOB
FROM *yourtable*
WHERE DATEADD(year, 55, DOB) < getdate()
) maxdob
ON maxdob.DOB = yt.DOB
n.b. you may find more than a single record if there is more than 1 person with the same DOB.
If you want to force this single restriction, add a TOP 1 clause in your SELECT statement.
hth
If you have the DOB then you can easily calculate the age based on the current date:
WHERE DATE_ADD(DOB, INTERVAL 55 YEAR) < NOW()
This will add 55 years to the DOB and if it is greater than the current time, it's true. This would indicate they are at least 55 years of age.