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.
Related
I want the count even if the count is 0. My current query is
SELECT `id`,count(0) as `fetchpc` FROM `user` WHERE pid in('4,6,7,8') GROUP BY `id`
But it returns only those id where count is greater than 0
Edit:
the values used for in('4,6,7,8') are first fetched from database in another query. And then using a script rows are converted to 4,6,7,8.
So all the values are present in the database.
Also it is possible that the values returned can go upto 100+ values.
You could left join this query on a "fictive" query that queries these IDs as literals:
SELECT ids.id, COALESCE(cnt, 0)
FROM (SELECT 4 AS id
UNION ALL
SELECT 6 AS id
UNION ALL
SELECT 7 AS id
UNION ALL
SELECT 8 AS id) ids
LEFT JOIN (SELECT id, COUNT(*) AS cnt
FROM fetchpc
GROUP BY id) t ON t.id = ids.id
You can use a derived table. I would recommend:
SELECT i.id, COUNT(u.id) as fetchpc
FROM (SELECT 4 as id UNION ALL
SELECT 6 as id UNION ALL
SELECT 7 as id UNION ALL
SELECT 8 as id
) i LEFT JOIN
`user` u
ON u.id = i.id
GROUP BY i.id;
From a performance perspective, this is much better than aggregating first (in a subquery) and then joining. Basically, the aggregation (in that case) has to aggregate all the data and afterwards filter out the unnecessary rows.
This formulation filters the rows first, which should speed the aggregation.
I have a problem with selecting something from my database. Here is the sql sentence:
SELECT name
FROM table1
JOIN table2
ON table1.id=table2.advid
GROUP BY advid
ORDER BY COUNT(table2.likes) ASC
This will output name with the least table2.likes to the highest value of table2.likes
The problem is that table2.likes contain both likes and dislikes. Likes are marked with 1, and dislikes are marked with 2 in the table.
Currently, if there is...
...written in the table, the syntax will count both likes and dislikes so the result would be 6. I would need this result to be zero, which means when counting, dislikes have to be deduced from the number of likes. Which also means this part of the sentence: ORDER BY COUNT(table2.likes) ASC would have to be changed, but I don't know how.
Use conditional aggregation with SUM():
SELECT name
FROM table1 t1 JOIN
table2 t2
ON t2.id = t2.advid
GROUP BY name
ORDER BY SUM(CASE WHEN t2.likes = 1 THEN 1 ELSE -1 END) ASC;
Note: I changed the GROUP BY to be by name. The GROUP BY columns should match the columns you are selecting.
Use a case expression to count 1 for likes and -1 for dislikes. It is considered good style and less error-prone not to join and then aggregate, but to join the already aggregated data instead.
select t1.name, t2.sumlikes
from table1 t1
join
(
select advid, sum(case when likes = 1 then 1 else -1 end) as sumlikes
from table2
group by advid
) t2 on t2.advid = t1.id
order by sumlikes;
If you want to list names without like entries, too, then turn the join into a left outer join and select coalesce(t2.sumlikes, 0) instead.
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);
Is it possible to pull 2 results from a sub query in a sql statement?
I have:
"SELECT
(SELECT bid FROM auction_bids WHERE itemID=a.id ORDER BY bid DESC LIMIT 1) as topbid,
a.* FROM auction_items a ORDER BY a.date DESC LIMIT 15"
The part where it returns the topbid, i'd also like it to pull not only bid (as topbid) but also date (as topdate) as well. How can I do that? Do I need another sub query or can it pull both in one?
Dependent subquery (depending on some values outside, like a.id in your case) is not a very efficient way to find maximum values in subsets.
Instead use a subquery with GROUP BY:
SELECT b.topbid, b.topdate, a.*
FROM auction_items a
LEFT JOIN
( SELECT itemID, MAX(bid) as topbid, MAX(date) as topdate
FROM auction_bids
GROUP BY itemID ) b
ON a.id = b.itemID
ORDER BY a.date DESC
LIMIT 15
I can't figure out how to count results from my query because I limit the output:
(SELECT "new" as type, name FROM newUsers WHERE name LIKE '%John%')
UNION
(SELECT "old" as type, name FROM oldUsers WHERE name LIKE '%John%')
ORDER BY 1 ASC LIMIT 1, 10
The farthest I got was to do SELECT COUNT(*) ( my query ) as userCount but then I don't get all other fields that were outputted by my query.
( select SQL_CALC_FOUND_ROWS ...)
union
( select ...) // not using SQL_CALC_FOUND_ROWS here
order by ... limit ...;
After getting result from the first query,
you can query again
select found_rows(); // to get all the rows count
The info from documentation
This would probably answer the letter of what you seem to be asking for, but isn't a very sensible way to formulate the query:
SELECT c.numusers, n.type, n.name
FROM (SELECT "new" AS type, name FROM newUsers WHERE name LIKE '%John%') AS n
JOIN (SELECT COUNT(*) AS numusers FROM newUsers WHERE name LIKE '%John%') AS c
UNION
SELECT c.numusers, o.type, o.name
FROM (SELECT "old" AS type, name FROM oldUsers WHERE name LIKE '%John%') AS o
JOIN (SELECT COUNT(*) AS numusers FROM oldUsers WHERE name LIKE '%John%') AS c
ORDER BY 1 ASC LIMIT 1, 10
The only oddity here is that there is no join condition (neither an ON nor a USING clause) between the two tables. You might need to use a CROSS JOIN instead of an (INNER) JOIN; alternatively, you can introduce a column "new" AS type to the count query, and join ON n.type = c.type. You might then need to add a GROUP BY clause - in most DBMS you would need it, but MySQL may let you get away without it.
However, I think you would do better with two separate queries - one for the type and name as in your question, and the other as:
SELECT COUNT(*) AS numusers, "new" AS type
FROM newUsers
WHERE name LIKE '%John%'
GROUP BY type
UNION
SELECT COUNT(*) AS numusers, "old" AS type
FROM oldUsers
WHERE name LIKE '%John%'
GROUP BY type;
Given that you are using MySQL, you may be able to get away without the GROUP BY clauses in the second query.