Is a nested SELECT statement possible in sql? I'm working on a problem and I can't seem to get the data that I want. This is the sql that Im querying:
SELECT derived.municipality, count(*) as counts, derived.bearing
from (SELECT m.name as municipality, count(*) as totalcount, sum(f.no_of_bearing_trees) as bearing
from farmer_profile f
inner join barangay b on f.barangay_id = b.id
inner join municipality m on b.municipality_id = m.id
inner join province p on m.province_id = p.id
group by b.name) as derived
group by derived.municipality, derived.bearing
Here is the sample data im working with. I want to get the sum of all the bearing and total counts when i put a where clause at the bottom (eg. where derived.bearing < 20). All of those bearings with less than 20 will totaled as well as their counts. I'm not sure if a subquery is needed again or not.
I suspect that you want to filter on municipalities whose bearing sum is less than 20. If so, you can use a having clause for this:
select
m.name as municipality,
count(*) as totalcount,
sum(f.no_of_bearing_trees) as bearing
from farmer_profile f
inner join barangay b on f.barangay_id = b.id
inner join municipality m on b.municipality_id = m.id
inner join province p on m.province_id = p.id
group by b.name
having sum(f.no_of_bearing_trees) < 20
MySQL is lax about column aliases in the having clause, so you can also do:
having bearing < 20
Related
I have two tables, products(id, name) and products_cost(id, sid, cost).
I'm trying to get a list of products whose total cost is less than 1000 including products that has no cost.
I've tried this:
SELECT a.name, SUM(b.cost) AS price
FROM products a
LEFT JOIN products_cost b
ON a.id = b.sid
GROUP BY a.name
HAVING SUM(b.cost)<1000;
The above SQL only gives the list of product name that includes cost and I want the output list to include product name that doesn't include cost as well.
I think you need to check for null values in the having clause:
SELECT p.name, SUM(pc.cost) AS price
FROM products p LEFT JOIN
products_cost pc
ON p.id = b.sid
GROUP BY p.name
HAVING SUM(pc.cost) < 1000 OR SUM(pc.cost) IS NULL;
Note that I also fixed the logic (salary doesn't makes sense in the SUM()). And I introduced meaningful table aliases -- abbreviations for the table names.
You can also add an IFNULL expression in your HAVING clause
SELECT a.name, SUM(b.cost) AS price
FROM products a
LEFT JOIN products_cost b
ON a.id = b.sid
GROUP BY a.name
HAVING SUM(IFNULL,b.cost,0)<1000;
use subquery and join
select p.*,a.s as cost from product p left join (
select pid,sum(cost) as s
from products_cost
group by pid
having s<1000 ) a on p.id=a.pid
So I'm struggling to write a query that returns me all categories regardless of what filter I have applied but the count changes based on how many returned recipes there will be in this filter.
This query works nice if I don't apply any filters to it. The count's seem right, but as soon as I add something like this: where c.parent_id is not null and r.time_cook_minutes > 60 I am filtering out most of the categories instead of just getting a count of zero.
here's an example query that I came up with that does not work the way I want it to:
select t.id, t.name, t.parent_id, a.cntr from categories as t,
(select c.id, count(*) as cntr from categories as c
inner join recipe_categories as rc on rc.category_id = c.id
inner join recipes as r on r.id = rc.recipe_id
where c.parent_id is not null and r.time_cook_minutes > 60
group by c.id) as a
where a.id = t.id
group by t.id
so this currently, as you might imagine, returns only the counts of recipes that exist in this filter subset... what I'd like is to get all of them regardless of the filter with a count of 0 if they don't have any recipes under that filter.
any help with this would be greatly appreciated. If this question is not super clear let me know, and I can elaborate.
No need for nested join if you move the condition into a regular outer join:
select t.id, t.name, t.parent_id, count(r.id)
from categories as t
left join recipe_categories as rc on rc.category_id = c.id
left join recipes as r on r.id = rc.recipe_id
and r.time_cook_minutes > 60
where c.parent_id is not null
group by 1, 2, 3
Notes:
Use left joins so you always get every category
Put r.time_cook_minutes > 60 on the left join condition. Leaving it on the where clause cancels the effect of left
Simply use conditional aggregation, moving the WHERE clause into a CASE (or IF() for MySQL) statement wrapped in a SUM() of 1's and 0's (i.e., counts). Also, be sure to consistently use the explicit join, the current industry practice in SQL. While your derived table uses this form of join, the outer query uses implicit join matching IDs in WHERE clause.
select t.id, t.name, t.parent_id, a.cntr
from categories as t
inner join
(select c.id, sum(case when c.parent_id is not null and r.time_cook_minutes > 60
then 1
else 0
end) as cntr
from categories as c
inner join recipe_categories as rc on rc.category_id = c.id
inner join recipes as r on r.id = rc.recipe_id
group by c.id) as a
on a.id = t.id
group by t.id
I believe you want:
select c.id, c.name, c.parent_id, count(r.id)
from categories c left join
recipe_categories rc
on rc.category_id = c.id left join
recipes r
on r.id = rc.recipe_id and r.time_cook_minutes > 60
where c.parent_id is not null and
group by c.id, c.name, c.parent_id;
Notes:
This uses left joins for all the joins.
It aggregates by all the non-aggregated columns.
It counts matching recipes rather than all rows.
The condition on recipes is moved to the on clause from the where clause.
I am trying to create an SQL query that displays some information from different tables. But I'm getting the error Subquery returns more than 1 row SQL. I want it to display more than one row.
SELECT c.Name,
jn.ID,
jn.ActualWeight as GrossWt,
jn.JobNo,
COUNT(distinct jn.JobNo) as Jobs,
COUNT(distinct jd.JobID) as Dbriefs,
COUNT(distinct jn.OutTurn) as Outturns,
(select Status from jobstat where CompanyID = jn.CompanyID AND Status = "DEL") as Delivery
FROM job_new jn
LEFT JOIN customer c ON jn.CompanyID = c.Company_ID
LEFT JOIN job_debriefs jd ON jn.JobNo = jd.JobID
LEFT JOIN jobstat js ON jn.CompanyID = js.CompanyID
WHERE jn.CompanyID = 36
I've tried adding GROUP BY and ORDER BY but that doesn't work either. If I remove the select State.... line it only displays one row when it should be displaying over a hundred
You need a group by:
SELECT c.Name, jn.ID, jn.ActualWeight as GrossWt, jn.JobNo,
COUNT(distinct jn.JobNo) as Jobs,
COUNT(distinct jd.JobID) as Dbriefs,
COUNT(distinct jn.OutTurn) as Outturns,
jobstat
FROM job_new jn LEFT JOIN
customer c
ON jn.CompanyID = c.Company_ID LEFT JOIN
job_debriefs jd
ON jn.JobNo = jd.JobID LEFT JOIN
jobstat js
ON jn.CompanyID = js.CompanyID
WHERE jn.CompanyID = 36
GROUP BY c.Name, jn.ID, jn.ActualWeight as GrossWt, jn.JobNo, js.status
I'm not sure what the subquery is supposed to be doing, so I'm guessing with regards to js.status.
The problem with your original query is the use of COUNT() in the SELECT. This turns the query into an aggregation query. Without a GROUP BY, exactly one row is returned. In most other databases, you would normally get an error.
I have three tables A,B,C.Their relation is A.id is B's foreign key and B.id is C's foreign key.I need to sum the value when B.id = C.id and A.id = B.id ,I can count the number by query twice. But now I need some way to count the summation just once time !
My inefficient solution
select count(C.id) from C,B where C.id = B.id; //return the value X
select count(A.id) from C,B where A.id = B.id; //return the value Y
select X + Y; // count the summation fo X and Y
How can I optimize ? Thks! :)
PS:
My question is from GalaXQL,which is a SQL interactive tutorial.I have abstract the problem,more detail you can check the section 17.SELECT...GROUP BY... Having...
You can do these things in one query. For instance, something like this:
select (select count(*) from C join B on C.id = B.id) +
(select count(*) from C join A on C.id = A.id)
(Your second query will not parse because A is not a recognized table alias.)
In any case, if you are learning SQL, the first thing you should learn is modern join syntax. The implicit joins that you are using were out of date 15 years ago and have been part of the ANSI standard for over 20 years. Learn proper join syntax.
Try Like This
select sum(cid) (
select count(*) as cid from C join B on C.id = B.id
union all
select count(*) as cid from A join B on A.id = B.id ) as tt
try this one:
select
(select count(*) from C join B on C.id = B.id)
union
(select count(*) from C join A on C.id = A.id)
Having an issue with a JOIN statement.
I'm trying to get a total per name, and not the current 1 with a ton of other same name records
SELECT a.`name`,
(SELECT COUNT(b.`id`)
FROM `host1_hosting` AS b
WHERE b.`id` = c.`host1_servers_host1_hosting_1host1_hosting_idb`) AS HostingCount
FROM `host1_servers` AS a
LEFT JOIN `host1_servers_host1_hosting_1_c` AS c ON c.`host1_servers_host1_hosting_1host1_servers_ida` = a.`id`
ORDER BY a.`name`
Example Returned
Name HostingCount
Name 1
Name 1
Name 1
Where it should be:
Name 3
I'm sure this is simple, but it's early monday, and I'm foggy
Query 2
SELECT a.`name`, COUNT(d.`id`)
FROM `host1_servers` AS a
JOIN `host1_servers_host1_hosting_1_c` AS c ON c.`host1_servers_host1_hosting_1host1_servers_ida` = a.`id`
JOIN `host1_hosting` AS d ON d.`id` = c.`host1_servers_host1_hosting_1host1_hosting_idb`
ORDER BY a.`name`
Gets me 1 name record, but a total of all COUNT
Your second query needs a group by:
SELECT a.`name`, COUNT(d.`id`)
FROM `host1_servers` AS a
JOIN `host1_servers_host1_hosting_1_c` AS c ON c.`host1_servers_host1_hosting_1host1_servers_ida` = a.`id`
JOIN `host1_hosting` AS d ON d.`id` = c.`host1_servers_host1_hosting_1host1_hosting_idb`
GROUP BY a.name
ORDER BY a.`name`;
Without the GROUP BY, MySQL interprets the query as an aggregation query to produce one row. The count() is the overall count. The column name is chosen arbitrarily from one of the rows (using a MySQL extension that wouldn't work in any other database).
EDIT:
If you want to keep all names from the first table and do the count, use left outer join:
SELECT a.`name`, COUNT(d.`id`)
FROM `host1_servers` a LEFT OUTER JOIN
`host1_servers_host1_hosting_1_c` c
ON c.`host1_servers_host1_hosting_1host1_servers_ida` = a.`id` LEFT OUTER JOIN
`host1_hosting` d
ON d.`id` = c.`host1_servers_host1_hosting_1host1_hosting_idb`
GROUP BY a.name
ORDER BY a.`name`;