aggregation give result of 0 although no data exists - mysql

Having following sql with a join:
SELECT sum(r) AS amount
FROM rep.stats
JOIN rep.valdata
ON rep.valdata.id = rep.stats.data_id
WHERE rep.valdata.custid = 3657 AND
rep.stats.sdatetime LIKE '2014-09-29%'
Problem, my ResultSet gives me one row as result with the value of 0 although no data available. I expect no resultSet. Whats wrong? Is it, because sum(r) return a 0 as default?
This brings me in trouble cause also a 0 value is a value and will be displayed.

Your query is an aggregation query with no GROUP BY. It is an aggregation query because you have an aggregation function (SUM()) in the select clause.
An aggregation query with no group by treats all the rows as the group -- and all means all, including none. So, such a query always returns exactly one row which summarizes all rows.
That said, the query should not be returning a value of 0. It should be returning a single row with a value of NULL.
If you want no row, then add a group by:
SELECT sum(r) AS amount
FROM rep.stats s JOIN
rep.valdata v
ON v.id = s.data_id
WHERE v.custid = 3657 AND
s.sdatetime >= '2014-09-29' AND
s.sdatetime < '2015-09-30'
GROUP BY v.custid;
Notes:
The aggregation query now has a GROUP BY. This will return one row per group, and if there are no groups, no rows will be returned.
Table aliases make the query easier to write and to read.
Don't use LIKE with date/time values. This requires converting the date/time to a string, which can depend on internationalization settings. Plus, it prevents the use of indexes.

Related

Why does HAVING MAX() return a different value than SELECT MAX()?

I have a table log that contains, among others, a DateTime column called TimeOfLog and a foreign key Logger_ID.
What I was trying to do was get the newest entry per Logger_ID.
SELECT l.TimeOfLog AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
HAVING MAX(l.TimeOfLog)
this however returns more or less a random TimeOfLog belonging to that Logger_ID. If I then run
SELECT MAX(l.TimeOfLog) AS TimeOfLog, l.Logger_ID AS Logger_ID
FROM `log` `l`
GROUP BY l.Logger_ID
I get the expected, newest, result. However, I'm pretty sure the Logger_ID is not the one belonging to that TimeOfLog.
Why is that/What am I misunderstanding here?
To get the maximum row, don't think group by; think filtering. Here is one method:
select l.*
from log l
where l.timeoflog = (select max(t2.timeoflog)
from log l2
where l2.logger_id = l.logger_id
);
If you just want the maximum time, then aggregation is appropriate:
select logger_id, max(timeoflog)
from log l
group by logger_id;
You have the expression:
HAVING MAX(l.TimeOfLog)
This just checks that the maximum is not 0 or NULL.
You are misunderstarding how GROUP BY AND HAVING works.
GROUP BY groups all rows that have same values in columns specified columns together into one group. If you select one column that is not mentioned in GROUP BY without using agregate function, you will randomly get one value from the grouped rows.
If you use agregate function like MAX() then the function is applied on all grouped rows and then result is selected.
HAVING is a filter similar to WHERE but while WHERE is applied before grouping the HAVING filter is applied after grouping.
You can use aggregate functions there. The correct usage of having might be for example
SELECT column,
FROM table
GROUP BY column
HAVING COUNT(*) > 1
This query would only select values of column that are present more than once.
In your example the MAX(c.TimeOfLog) will always be true as long as c.TimeOfLog is not empty for at least one row in group so it won't filter anything.

Why is only one result showing from my query?

Why am I only getting one result from the query below? The suggested "answer" has the first name "Susan" instead of what I got in my results.
SELECT EmpFirstName, EmpLastName, p.ProductName as ProductName,
YEAR(c.OrderDate) AS Year,
SUM(o.QuotedPrice + o.QuantityOrdered) AS TotalValue
FROM Employees
NATURAL JOIN Products p
NATURAL JOIN Order_Details o
NATURAL JOIN Orders c
ORDER BY Year, TotalValue DESC
Image of results
Image of Table Structure
Because there are a Sum in your Query
The result returned by the query does not match your expectations because the query is invalid. And your expectations are incorrect.
The presence of an aggregate (GROUP BY) function in the expression from the SELECT clause requires the presence of a GROUP BY clause. When such a clause does not exists, the SQL standard automatically adds a GROUP BY 1 clause that produces only one group from all the selected rows.
Each expression that appears in the SELECT clause of a GROUP BY query must follow one of these rules, in order to have a valid SQL query:
it also appears in the GROUP BY clause;
it's a call to an aggregate (GROUP BY) function;
is functionally dependent of one column that appears in the GROUP BY clause.
Because your query does not have a GROUP BY clause, the expressions EmpFirstName, EmpLastName, p.ProductName and YEAR(c.OrderDate) are not valid in the SELECT clause.
Before version 5.7.5, MySQL used to allow such invalid SQL queries but it reserved its privilege to return indeterminate values for the invalid expressions.
Since version 5.7.5, MySQL handles such queries correctly and rejects them. Other RDBMS-es handle them correctly since many years ago.
The explanation for the indeterminate values is simple: the JOIN and WHERE clauses extract some rows from the table(s). The (missing) GROUP BY clause produces only one record from all these rows. A GROUP BY query never returns rows from the table, it generates the values it puts in the result set. Since there are multiple different values for EmpFirstName in the group, the SQL standard says the query is invalid. MySQL used to ignore the standard but it had no valid rule about what value to pick from the EmpFirstName expression in the SELECT clause. Any value from the rows in the group is equally valid and that's what it returns: one random value from the group.
In order to get the results you expect you have to group the rows by OrderNumber and ProductNumber (and EmployeeID to get a valid SQL query):

LEFT JOIN returns everything with NULL

I have two tables whome I am joining through left join. Both the tables are empty. But when I run the query, mysql returns a row with all NULLS.
I have tried several queries like
SELECT products.*,SUM(pq_quantity) as quantity
FROM `products` LEFT JOIN `products_quantities` ON `pq_product_idFk` = `p_id`
WHERE `p_volusion_id` = '37808'
OR
SELECT products.*,SUM(pq_quantity) as quantity
FROM `products` LEFT JOIN `products_quantities` ON `pq_product_idFk` = `p_id`
WHERE `p_volusion_id` = '37808' AND p_id IS NOT NULL
OR
SELECT products.*,SUM(pq_quantity) as quantity
FROM `products` LEFT JOIN `products_quantities` ON `pq_product_idFk` = `p_id` AND `p_volusion_id` = '37808' AND p_id IS NOT NULL
NONE of the above queries seem to work as I just want the result that is not NULL.
Thanks
Both the tables are empty. But when I run the query, mysql returns a row with all NULLS.
The presence of GROUP BY aggregate functions in the SELECT clause asks the GROUP BY clause to be present too. However, if it is not present, the SQL standard specifies that a single group is to be created using all the rows filtered by the WHERE clause.
Because of the * used in the SELECT clause, all the queries you posted are invalid SQL.
A query that contains a GROUP BY clause does not return rows from tables. It creates rows using the values extracted from the tables. First it creates groups (and sub-groups) using the expressions from the GROUP BY clause. All the rows from a group have the same value for the first expression specified in the GROUP BY clause.
If there are two or more expressions in the GROUP BY clause, each group is split into sub-groups using the second expression then each sub-group is further split into sub-sub-groups using the third expression (if exists) and so on.
From each such group of rows (after the last split), the database engine generates one new row and puts it into the result set. If the query contains in the SELECT clause expressions that are not either arguments of a GRUP BY aggregate function or also present in the GROUP BY clause then, most probably, these expressions will have more than one value in a subgroup. This is why the query is invalid SQL. Up to version 5.7.5, MySQL accepts such invalid queries but reserves itself the right to return any value it wants (from the group) for the offending expressions.
Back to your question, as explained above, even without having a GROUP BY clause, your query is processed as it had one and one group is created from all the rows filtered by the WHERE clause.
It is an empty group but this doesn't prevent the database engine to generate a row from it. Since there are no values to use to compute SUM(pG_quantity), NULL is the logical value it returns in the columns of the result set.
NULL is a special value that means the absence of any value or an unknown value. It make perfect sense in your case. You don't have any value in the tables, there is no way one could compute SUM(pq_quantity). Its value is not available (i.e. NULL).

Using Max and Sum for the same column without subquery -Mysql

I am new to Mysql,I wanted to use both sum(Max(column)) ?
I don't know why its impossible to use?
whereas count(Distinct(column)) is possible i.e using two aggregate functions together
The reason is SUM() and MAX() both are aggregate functions and these functions returning results by grouping their inputs across the table . While applying one aggregate function over another, it is something like grouping data over the result set of another grouping function and that is not allowed in SQL.
But in SQL Server, from 2008 version onwards introduced a new clause OVER() so that we can specify the grouping criteria in that over clause for that particular column.
In the case of DISTINCT which does not need any grouping and it pull the distinct record set over which we are applying the aggregate function. So that will work.
You can perform in the following way but if you are not using orther grouping columns then it always return 1 column so SUM(MAX(tot)) = MAX(tot) though we are not allow to do it in same place:
SELECT SUM(total) tot FROM (
SELECT
MAX(quantity) total
FROM deliveries) t;
DISTINCT is not an aggregate function. It's a keyword, a basic command.
In your case, when you're getting the MAX from a group you're getting a single value. SUM a single value makes no sense.
If you want so SUM the MAX values from all existing groups, you could try like this:
SELECT SUM(<column>)
FROM <table> t
WHERE NOT EXISTS
(
-- filter all max values from each group
SELECT 1
FROM <table> d
WHERE 1=1
AND d.<group_column1> = t.<group_column1>
AND d.<group_column2> = t.<group_column2>
...
AND d.<column> > t.<column>
)

MySQL joins: why is this returning a row?

I have the below query. The email and pass specified do NOT correspond to any row in the table, so it should return no rows, which is what happens.
SELECT *
FROM _users
LEFT JOIN _assocs ON
item_id = _users.id AND
item_type = "_users.user_group" AND
foreign_item_type = "_user_groups"
WHERE
email = 'some#email.com' AND
password = 'somepass' AND
activation_key IS NULL
LIMIT 1
However, when I modify the SELECT part to
SELECT GROUP_CONCAT(foreign_item_id) AS user_groups
...it always returns a row, regardless, with the columns all having null values. Why?
I'm using a left join specifically because it's possible nothing will be returned from table 2 (_assocs).
The function group_concat() is an aggregation function (such as MIN(), MAX(), SUM() and AVG()).
This turns the query into an aggregation query, with no group by clause. For such a query, all the rows are considered as a single set and one row is returned to summarize them. These is even true when the result set has no rows. As you have found, the result is one row with NULLs in the columns.
According to mysql docs, when no non-null value is provided for GROUP_CONCAT function, the return value is null,