How to calculate ages in Oracle SQL - sql

I have two databases in the same server(dbA and dbB). The both have a table called CUSTOMERS. I want to calculate the age of my customers and instert it on a column AGE, on the dbB.CUSTOMERS, based on the current date and the DateOfBirth column on the dbA.CUSTOMERS table.
To calculate the age I tried to use
SELECT floor(months_between(SYSDATE, (SELECT BIRTH_DATE FROM dbA.CUSTOMERS)) /12) from dual;
but this returns an ORA-01427:single-row subquery returns more than one row
I am guessing this is because the subquery returns every row of the BIRTH_DATE column. Is there someway to do this for all the rows and then insert the result to my dbB.CUSTOMERS table?
I am using OracleSQL

There is no need for the subquery here
select floor(months_between(sysdate,BIRTH_DATE)/12) as Age
from CUSTOMERS
Using the subquery returns all the rows for the table and cannot apply the functions against all of them. This method applies the function against each row, so it works

Related

In SQL, how to select rows with matching values in one column, based on earliest date in another column

I think this should be a simple SQL exercise, but I am not sure how it is done as I am new to querying dbs with SQL. I have a table that looks like this:
select * from myschema.mytable
customer_name date
nick 2017-06-19 19:26:40
tom 2017-06-21 19:24:40
peter 2017-06-23 21:25:10
nick 2017-06-24 13:43:39
I'd like for this query to return only one row for each unique name. Specifically, I'd like the query to return the rows for each customer_name with the earliest date. In this case, the first row for nick should be returned (with date 2017-06-19), but not the other row with date 2017-06-24.
Is this a simple exercise in SQL?
Thanks!
A simple MIN will do:
SELECT
customer_name,
MIN(date) AS earliest_date
FROM myschema.mytable
GROUP BY customer_name;
For this kind of problems you can use aggregate functions. what has to be done basically is grouping the rows by name and choosing the minimum date:
select cutomer_name, MIN(date)
FROM myschema.mytable
GROUP BY customer_name

sql functions and WHERE clause

Is the function in the SELECT clause takes the WHERE clause in account?
For example:
SELECT COUNT(id)
FROM Person
WHERE age > 18
will print the count of all persons, or only persons that have an age older than 18 years?
This query will return the count of rows where age > 18
Where clause specifies a condition that tells which rows to retrieve from the table. Since the condition is age>18 it will return the rows whose age column has a value greater than 18. Ṭhe function uses only those rows. Read more about select statement and different parts in it here:
http://en.wikipedia.org/wiki/Select_%28SQL%29

SQL Server Sum multiple rows into one - no temp table

I would like to see a most concise way to do what is outlined in this SO question: Sum values from multiple rows into one row
that is, combine multiple rows while summing a column.
But how to then delete the duplicates. In other words I have data like this:
Person Value
--------------
1 10
1 20
2 15
And I want to sum the values for any duplicates (on the Person col) into a single row and get rid of the other duplicates on the Person value. So my output would be:
Person Value
-------------
1 30
2 15
And I would like to do this without using a temp table. I think that I'll need to use OVER PARTITION BY but just not sure. Just trying to challenge myself in not doing it the temp table way. Working with SQL Server 2008 R2
Simply put, give me a concise stmt getting from my input to my output in the same table. So if my table name is People if I do a select * from People on it before the operation that I am asking in this question I get the first set above and then when I do a select * from People after the operation, I get the second set of data above.
Not sure why not using Temp table but here's one way to avoid it (tho imho this is an overkill):
UPDATE MyTable SET VALUE = (SELECT SUM(Value) FROM MyTable MT WHERE MT.Person = MyTable.Person);
WITH DUP_TABLE AS
(SELECT ROW_NUMBER()
OVER (PARTITION BY Person ORDER BY Person) As ROW_NO
FROM MyTable)
DELETE FROM DUP_TABLE WHERE ROW_NO > 1;
First query updates every duplicate person to the summary value. Second query removes duplicate persons.
Demo: http://sqlfiddle.com/#!3/db7aa/11
All you're asking for is a simple SUM() aggregate function and a GROUP BY
SELECT Person, SUM(Value)
FROM myTable
GROUP BY Person
The SUM() by itself would sum up the values in a column, but when you add a secondary column and GROUP BY it, SQL will show distinct values from the secondary column and perform the aggregate function by those distinct categories.

SQL - Insert using Column based on SELECT result

I currently have a table called tempHouses that looks like:
avgprice | dates | city
dates are stored as yyyy-mm-dd
However I need to move the records from that table into a table called houses that looks like:
city | year2002 | year2003 | year2004 | year2005 | year2006
The information in tempHouses contains average house prices from 1995 - 2014.
I know I can use SUBSTRING to get the year from the dates:
SUBSTRING(dates, 0, 4)
So basically for each city in tempHouses.city I need to get the the average house price from the above years into one record.
Any ideas on how I would go about doing this?
This is an SQL Server approach, and a PIVOT may be a better, but here's one way:
SELECT City,
AVG(year2002) AS year2002,
AVG(year2003) AS year2003,
AVG(year2004) AS year2004
FROM (
SELECT City,
CASE WHEN Dates BETWEEN '2002-01-01T00:00:00' AND '2002-12-31T23:59:59' THEN avgprice
ELSE 0
END AS year2002,
CASE WHEN Dates BETWEEN '2003-01-01T00:00:00' AND '2003-12-31T23:59:59' THEN avgprice
ELSE 0
END AS year2003
CASE WHEN Dates BETWEEN '2004-01-01T00:00:00' AND '2004-12-31T23:59:59' THEN avgprice
ELSE 0
END AS year2004
-- Repeat for each year
)
GROUP BY City
The inner query gets the data into the correct format for each record (City, year2002, year2003, year2004), whilst the outer query gets the average for each City.
There many be many ways to do this, and performance may be the deciding factor on which one to choose.
The best way would be to use a script to perform the query execution for you because you will need to run it multiple times and you extract the data based on year. Make sure that the only required columns are city & row id:
http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
INSERT INTO <table> (city) VALUES SELECT DISTINCT `city` from <old_table>;
Then for each city extract the average values, insert them into a temporary table and then insert into the main table.
SELECT avg(price), substring(dates, 0, 4) dates from <old_table> GROUP BY dates;
Otherwise you're looking at a combination query using joins and potentially unions to extrapolate the data. Because you're flattening the table into a single row per city it's going to be a little tough to do. You should create indexes first on the date column if you don't want the database query to fail with memory limits or just take a very long time to execute.

rows with max value

I'm wanting to retrieve all rows and columns which contain the MAX value in one column.
For example: 3 columns - ID (not unique), name, age
I'm wanting all rows and columns which contain the max value in age.
Thanks
SELECT * FROM table WHERE age = (SELECT MAX(age) FROM table)
Select * from table where value=max(value)
Maybe you need to exchange where with having