ActiveJDBC MAX() function - activejdbc

I'm new to ActiveJDBC and Java.
How can I do
SELECT MAX(age) FROM persons
with ActiveJDBC on a MySQL database?
I have tried
Pesrsons.find("MAX(age)")
but this one returns an empty list
and
Persons.FindBySql("SELECT MAX(age) FROM persons")
this other one returns null.
Any idea?

You can't use .find() to execute a custom "SELECT" query.
But with .findBySql() this should work Persons.FindBySql("SELECT MAX(age) as age FROM persons")

Related

Keyword ALL in AVG function of PostgreSQL

Suppose I have an employee table with their salaries.
What is the difference between:
SELECT AVG(salary)
FROM employee;
and
SELECT AVG(ALL salary)
FROM employee;
What does ALL do? Both cases give the same result.
According to the documentation they are exactly the same regardless of the aggregation function:
The first form of aggregate expression invokes the aggregate once for each input row. The second form is the same as the first, since ALL is the default.

"You tried to execute a query that does not include the specified aggregate function"

SELECT SUM(orders.quantity) AS num, fName, surname
FROM author
INNER JOIN book ON author.aID = book.authorID;
I keep getting the error message: "you tried to execute a query that does not include the specified expression "fName" as part of an aggregate function. What do I do?
The error is because fName is included in the SELECT list, but is not included in a GROUP BY clause and is not part of an aggregate function (Count(), Min(), Max(), Sum(), etc.)
You can fix that problem by including fName in a GROUP BY. But then you will face the same issue with surname. So put both in the GROUP BY:
SELECT
fName,
surname,
Count(*) AS num_rows
FROM
author
INNER JOIN book
ON author.aID = book.authorID;
GROUP BY
fName,
surname
Note I used Count(*) where you wanted SUM(orders.quantity). However, orders isn't included in the FROM section of your query, so you must include it before you can Sum() one of its fields.
If you have Access available, build the query in the query designer. It can help you understand what features are possible and apply the correct Access SQL syntax.
I had a similar problem in a MS-Access query, and I solved it by changing my equivalent fName to an "Expression" (as opposed to "Group By" or "Sum"). So long as all of my fields were "Expression", the Access query builder did not require any Group By clause at the end.
GROUP BY can be selected from Total row in query design view in MS Access.
If Total row not shown in design view (as in my case). You can go to SQL View and add GROUP By fname etc. Then Total row will automatically show in design view.
You have to select as Expression in this row for calculated fields.

Nested aggregate function in SELECT list

I tried following query:
SELECT
MAX(SUM(e.Empid))
FROM HR.Employees
and got following error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
My question is why isn't this allowed?
Each aggregate works on a group. You can only define one group per query. So multiple aggregates require subqueries. For example, to find the amount of employees in the largest department:
SELECT MAX(EmpCount)
FROM (
SELECT COUNT(*) as EmpCount
FROM HR.Employees
GROUP BY
e.Department
) as SubQueryAlias
since you have not define any columns to be grouped, The value of SUM() is equal to MAX()
UPDATE
An error was thrown because MAX(SUM(e.Empid)) requires the results of two grouped selects, not just one.
SUM(x) evaluates to a single value, so it's not appropriate to MAX the result of it.
This query makes no sense, as even if it worked, it would return only one value : the sum of Empid. The MAX function applied on one value is not really useful.
Try this
SELECT MAX(_ID)
FROM (SELECT SUM(e.Empid) _ID FROM HR.Employees e) t
OK. I got your question now. Here is why:
The value expression simply contained in set function specification
shall not contain a set function specification or a subquery. If the
value expression contains a column reference that is an outer
reference, then that outer reference shall be the only column
reference contained in the value expression.
Further reading : SQL 92 Standards
Raj

Select all columns on a group by throws error

I ran a query against Northwind database Products Table like below
select * from Northwind.dbo.Products GROUP BY CategoryID and i was hit with a error. I am sure you will also be hit by same error. So what is the correct statement that i need to execute to group all products with respect to their category id's.
edit: this like really helped understand a lot
http://weblogs.sqlteam.com/jeffs/archive/2007/07/20/but-why-must-that-column-be-contained-in-an-aggregate.aspx
You need to use an Aggregate function and then group by any non-aggregated columns.
I recommend reading up on GROUP BY.
If you're using GROUP BY in a query, all items in your SELECT statement must either be contained as part of an aggregate function, e.g. Sum() or Count(), else they will also need to be included in the GROUP BY clause.
Because you are using SELECT *, this is equivalent to listing ALL columns in your SELECT.
Therefore, either list them all in the GROUP BY too, use aggregating functions for the rest where possible, or only select the CategoryID.

Can I use non-aggregate columns with group by?

You cannot (should not) put non-aggregates in the SELECT line of a GROUP BY query.
I would however like access the one of the non-aggregates associated with the max. In plain english, I want a table with the oldest id of each kind.
CREATE TABLE stuff (
id int,
kind int,
age int
);
This query gives me the information I'm after:
SELECT kind, MAX(age)
FROM stuff
GROUP BY kind;
But it's not in the most useful form. I really want the id associated with each row so I can use it in later queries.
I'm looking for something like this:
SELECT id, kind, MAX(age)
FROM stuff
GROUP BY kind;
That outputs this:
SELECT stuff.*
FROM
stuff,
( SELECT kind, MAX(age)
FROM stuff
GROUP BY kind) maxes
WHERE
stuff.kind = maxes.kind AND
stuff.age = maxes.age
It really seems like there should be a way to get this information without needing to join. I just need the SQL engine to remember the other columns when it's calculating the max.
You can't get the Id of the row that MAX found, because there might not be only one id with the maximum age.
You cannot (should not) put non-aggregates in the SELECT line of a GROUP BY query.
You can, and have to, define what you are grouping by for the aggregate function to return the correct result.
MySQL (and SQLite) decided in their infinite wisdom that they would go against spec, and allow queries to accept GROUP BY clauses missing columns quoted in the SELECT - it effectively makes these queries not portable.
It really seems like there should be a way to get this information without needing to join.
Without access to the analytic/ranking/windowing functions that MySQL doesn't support, the self join to a derived table/inline view is the most portable means of getting the result you desire.
I think it's tempting indeed to ask the system to solve the problem in one pass rather than having to do the job twice (find the max, and the find the corresponding id). You can do using CONCAT (as suggested in Naktibalda refered article), not sure that would be more effeciant
SELECT MAX( CONCAT( LPAD(age, 10, '0'), '-', id)
FROM STUFF1
GROUP BY kind;
Should work, you have to split the answer to get the age and the id.
(That's really ugly though)
In recent databases you can use sum() over (parition by ...) to solve this problem:
select id, kind, age as max_age from (
select id, kind, age, max(age) over (partition by kind) as mage
from table)
where age = mage
This can then be single pass
PostgesSQL's DISTINCT ON will be useful here.
SELECT DISTINCT ON (kind) kind, id, age
FROM stuff
ORDER BY kind, age DESC;
This groups by kind and returns the first row in the ordered format. As we have ordered by age in descending order, we will get the row with max age for kind.
P.S. columns in DISTINCT ON should appear first in order by
You have to have a join because the aggregate function max retrieves many rows and chooses the max.
So you need a join to choose the one that the agregate function has found.
To put it a different way how would you expect the query to behave if you replaced max with sum?
An inner join might be more efficient than your sub query though.