Basically I want a column to to return 0 if null. I'm using the ifnull inside a nested statement, when I run the nested statement by itself the column returns 0, but when I run the whole query I get NULL again. This is my code:
SELECT Text, Verbo, Objeto, mPosts FROM Posts
LEFT JOIN (SELECT ID, IFNULL(COUNT(*),0) AS mPosts FROM `Posts` WHERE Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) GROUP BY `Verbo`,`Objeto`) AS B ON Posts.ID = B.ID
I could move the IFNULL to the main select statement, but I would rather not:
SELECT Text, Verbo, Objeto, IFNULL(mPosts,0) FROM Posts
LEFT JOIN (SELECT ID, COUNT(*) AS mPosts FROM `Posts` WHERE Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) GROUP BY `Verbo`,`Objeto`) AS B ON Posts.ID = B.ID
Why I can't do it on the nested statement? Can it can be done any other way so that I don't have to use it on the main query?
If you are getting NULL for IFNULL(COUNT(*),0), it is because the LEFT JOIN is not matching with your ON clause of Posts.ID = B.ID, so all values in the right table will be NULL.
So yes, you will need to move IFNULL to the top-level SELECT clause.
You must have the IFNULL on the outer query.
The COUNT(*) in the inner query is not returning a NULL, the NULL is being created by the LEFT JOIN operation, when a row on the left side does not have a matching row from the row source on the right side.
This query is equivalent to yours:
SELECT a.Text
, a.Verbo
, a.Objeto
, c.mPosts
FROM `Posts` a
LEFT
JOIN ( SELECT b.ID
, COUNT(*) AS mPosts
FROM `Posts` b
WHERE b.Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY)
GROUP BY b.`Verbo`, b.`Objeto`
) c
ON c.ID = a.ID
The reformatted query makes it more obvious where the problem is.
Your inline view (the subquery) is performing a GROUP BY on two columns, and then returning the value of ID from some one row that is included in each of the count values.
(Other relational databases would throw a "non-aggregate in select list not in group by" type exception with this statement, where MySQL is more liberal, which is both a convenience and a curse.)
The result set returned by the query is quite odd. It's not clear what result set you want returned here.
The row from the "count" subquery is going to get matched with only one row included in each value of COUNT(). (Any time that COUNT(*) is greater than 1, there's going to be a row in the outer query that doesn't have a matching row from the inline view... that GROUP BY is collapsing all of the ID values of the included rows down to just one ID value of some one row that is included.
I hesitate to make any suggestions, because I'm not clear on what you want returned.
One thing you could do is to remove the predicate from the WHERE clause, and instead check that condition in the aggregate, something like this...
SELECT a.`Text`
, a.`Verbo`
, a.`Objeto`
, c.`mPosts`
FROM `Posts` a
LEFT
JOIN ( SELECT b.ID
, SUM(IF b.`Date` >= DATE_ADD(CURDATE(), INTERVAL -30 DAY)) AS `mPosts`
FROM `Posts` b
GROUP BY b.`Verbo`, b.`Objeto`
) c
ON c.ID = a.ID
That may reduce the number of NULL values, but it doesn't address the more fundamental issue of the LEFT JOIN generating NULL for any row on the left side that don't have a match from the right side.
Related
I have 14000 records in my sql table. They have columns ID, test_subject_id and date_created. I want to fetch all the records that have been created within a time difference of 3 minutes(difference in date_created values) and both records should have the same test_subject_id.
You should use a self join, I assume inner join is what will work for you:
SELECT a.ID, a.date_created, b.ID, b.date_created
FROM accounts a
INNER JOIN accounts b
ON a.test_subject_id = b.test_subject_id
AND TIMESTAMPDIFF(MINUTE,a.date_created,b.date_created) = 3
Note: TIMESTAMPDIFF is used assuming date_created has type datetime, details here.
You can use EXISTS:
SELECT t1.*
FROM tablename t1
WHERE EXISTS (
SELECT 1
FROM tablename t2
WHERE t2.test_subject_id = t1.test_subject_id
AND ABS(TIMESTAMPDIFF(SECOND, t1.date_created, t2.date_created)) <= 180
)
ORDER BY t1.test_subject_id, t1.date_created;
Why is the result of countTypes NULL ?
I need the counts based of the main query (a.id's).
I get the counts only if i put the same on a WHERE clause but i need a solution without double WHERE clause.
Thanks in advance.
items
id type
1 2
2 2
3 1
4 1
5 3
SELECT a.id, countTypes FROM items AS a
INNER JOIN (
SELECT id, JSON_ARRAYAGG(JSON_OBJECT(CONCAT('countType', type), count)) as countTypes
FROM (SELECT id, type, count(id) AS count FROM items GROUP BY type) AS b
) AS c ON c.id = a.id
WHERE a.id >= '100' AND a.id <= '200'
Your innermost subquery query is this.
SELECT id, type, count(id) AS count FROM items GROUP BY type
Here you have run afoul of MySQL's notorious nonstandard extension to GROUP BY. Your query actually means
SELECT ANY_VALUE(id), type, count(id) AS count FROM items GROUP BY type
Where ANY_VALUE() formally means MySQL may return an unpredictable value for that column. Unpredictable can be confusing. That's why MySQL's extension is notorious.
You need
SELECT id, type, count(id) AS count FROM items GROUP BY id, type
for this subquery to be predictable. But I guess you want the count of types in items, so what you want is this.
SELECT type, count(*) AS count FROM items GROUP BY type
Your outer query says
SELECT a.id
FROM items
JOIN (subquery) c ON c.id = a.id
WHERE a.id >= '100'
AND a.id <= '200'
Your outer query returns no items from your subuery so it's not clear what result you need. Inner JOIN operations can serve to filter a resultset. But because of your ANY_VALUE(id) situation, your filter is unpredicatable.
I have 3 tables I need to pull from A,B,C (the data is not organized well)
I have used a JOIN on the first two tables but I an not sure how to proceed with the 3rd table. Is a sub query best or use another join?
any help? can I use 2 WHERE clause?
SELECT DISTINCT `App`,`status`,`New App`,`Sunset`
FROM `Table A`
LEFT JOIN `Table B`
ON `App (table A)`= `New App(Table B)`
WHERE status NOT LIKE '%sunset%'
This is Table C, it has the request date I need
(SELECT `App ID`,`Status`
FROM `requests`
WHERE `Updated` < DATE_SUB(NOW(), INTERVAL 364 DAY))
You can alias the tables when you join.
If they all share common identifiers, joining that's the fastest approach.
SELECT DISTINCT
a.App, b.status, c.NewApp AS c_new_apps
FROM
TableA a
LEFT JOIN
TableB b ON a.App = b.NewApp
LEFT JOIN
TableC c ON c.AppId = b.NewApp
WHERE
b.status NOT LIKE '%sunset%',
c.Updated` < DATE_SUB(NOW(), INTERVAL 364 DAY)
Also, consider if you are looking for INNER JOINs or OUTER JOINs.
I am wondering how to group by a field that has both a select count() and count() statement. I know that we have to put all select fields in group by but it wont let me do so because of the second count() statement in the field.
create table C as(
select a.id, a.date_id,
(select count(b.hits)*1.00 where b.hits >= '9')/count(b.hits) AS percent **<--error here
from A a join B b
on a.id = b.id
group by 1,2,3) with no data primary index(id);
This is my error:
[SQLState HY000] GROUP BY and WITH...BY clauses may not contain
aggregate functions. Error Code: 3625
When i add a select to the second count in the third line only get 1 or 0 which is not right.
`((select count(b.hits)*1.00 where b.hits >= '9')/(select count(b.hits))) AS` percent
Do i need to do a self join instead or is there any way i can just use nested queries?
You need to fix the group by. But, you can probably simplify the query as:
create table C as
select a.id, a.date_id,
avg(b.hits >= 9) as percent
from A a join
B b
on a.id = b.id
group by a.id, a.date_id
with no data primary index(id);
It looks like you only need to group on 2 columns, not 3, plus you shouldn't need a sub-select:
create table C as(
select a.id, a.date_id,
SUM(CASE WHEN b.hits >= '9' THEN 1 ELSE 0 END)/COUNT(b.hits) AS percent
from A a join B b
on a.id = b.id
group by 1,2) with no data primary index(id);
I have 2 queries that are nearly identical, one with a GROUP BY, one without. The results are very different. The GROUP BY query results in over double the non-GROUP BY query result.
Query 1:
SELECT table2.name, COUNT(DISTINCT(op.id))
FROM op INNER JOIN table1 ON table1.EID = op.ID
INNER JOIN table3 ON table3.id = table1.jobid
INNER JOIN table2 ON table2.id = table3.CatID
WHERE op.BID = 1
AND op.ActiveStartDate <= NOW()
AND op.ActiveEndDate >= NOW()
GROUP BY table2.name
ORDER BY COUNT(*) DESC;
Query 2:
SELECT op.Type, COUNT(DISTINCT op.id)
FROM op
WHERE op.BID = 1
AND op.ActiveStartDate <= NOW()
AND op.ActiveEndDate >= NOW()
ORDER BY op.Type ASC;
These should result in the same result. When playing around with them, once I remove the "GROUP BY" from query 1, the result is the same. If I put the "GROUP BY" back into Query 1, the result is more than doubled.
Edit: It seems the additional INNER JOINS are not affecting the results, but rather the GROUP BY in query 1. If I remove the GROUP BY in query 1, the results between the 2 queries are identical. If I add the GROUP BY back into query 1, the results are very different.
I don't know how you think that those are nearly identical queries; they are very different. Anyway, you shouldn't remove the GROUP BY from the first one, but add a GROUP BY on the second query:
SELECT op.Type, COUNT(DISTINCT op.id)
FROM op
WHERE op.BID = 1
AND op.ActiveStartDate <= NOW()
AND op.ActiveEndDate >= NOW()
GROUP BY op.Type
ORDER BY op.Type ASC;
Of course, this doesn't mean that you'll get the same results anyway, since the first query has 3 extra joins.
the queries are not at all "nearly identical..." in my view.
you have INNER JOIN with other tabls that can have duplicates and so the INNER JOIN will increase the number of rows by that number.
you can check the explaination in here
INNER JOIN and GROUP BY