Where clause with sum aggregate in sql query - mysql

I have a table and I want to display only those departments that have at least one registered user in them. My query is below:
SELECT departments.id as DepartmentID,
departments.depName as DepartmentName,
SUM(IF(users.isDelete=0, 1, 0)) AS NumberOfUsers
FROM (myDB.departments)
LEFT JOIN myDB.users ON departmentID=departments.id
AND `departments`.`isDelete` = 0
HAVING SUM(NumberOfUsers) >=0
The HAVING SUM(NumberOfUsers) >=0 is not working at all. I would like to check if the NumberOfUsers is more than one then display it if not more than one then do not display it. Any suggestions?

Try this:
SELECT departments.id as DepartmentID,
departments.depName as DepartmentName,
(SELECT COUNT(u.id)
FROM users u
WHERE u.departmentID = d.id) as NumberOfUsers
FROM departments d
WHERE d.isdelete = 0
AND EXISTS
(SELECT 'user'
FROM users u
WHERE u.departmentID = d.id)
In this way, you don't use a SUM in main query (where you must use GROUP BY to show other scalar fields like departments.id and departments.depName. In My Sql is not mandatory GROUP BY)
EXISTS clause garantee the presence at least one user. If you want to show all department (indipendently number of users, remove EXISTS clause)

I think you can simplify your query as you are checking condition in user table that is_delete should be 0, so there is no need of left join you can just use normal join. After this you are removing all rows those does not have record by having clause, so you can simply put this condition in where clause as per below-
SELECT dpt.id AS DepartmentID, dpt.depName AS DepartmentName,
COUNT(usr.id) AS NumberOfUsers
FROM myDB.departments AS dpt
JOIN myDB.users AS usr ON usr.departmentID=dpt.id
WHERE dpt.`isDelete` = 0 AND usr.isDelete=0
Note: Assuming users table have primary key as id, if not then you can use any other column in count function.

In this case you need to use the group by clause too.
SELECT departments.id as DepartmentID,
departments.depName as DepartmentName,
SUM(IF(users.isDelete=0, 1, 0)) AS NumberOfUsers
FROM (myDB.departments)
LEFT JOIN myDB.users ON departmentID=departments.id
AND `departments`.`isDelete` = 0
GROUP BY departments.id, departments.depName
HAVING SUM(IF(users.isDelete=0, 1, 0)) >=0
But if you want a shorter answer, you can use JOIN instead of LEFT JOIN and removing HAVING clause:
SELECT departments.id as DepartmentID,
departments.depName as DepartmentName,
SUM(IF(users.isDelete=0, 1, 0)) AS NumberOfUsers
FROM (myDB.departments)
JOIN myDB.users ON departmentID=departments.id
AND `departments`.`isDelete` = 0
GROUP BY departments.id, departments.depName

Related

Getting the top sales

How to i get the top vendor for each country? I have this code and it shows the connection between the two tables, now I have to get the largest gmv per country.
Here is my working code:
SELECT DISTINCT a.country_name, b.vendor_name,
SUM(a.gmv_local) as total_gmw
from `my-project-67287.order1.order2`a
join `my-project-67287.vendor1.vendor2` b on a.vendor_id = b.id
group by a.country_name, b.vendor_name;
The top 3 should show this:
Assuming you can save that SELECT into a table called vendors, you need to use it as the subquery in the FROM clause.
You could use this:
SELECT vendors.country_name, vendors.vendor_name, MAX(vendors.total_gmw)
FROM
(
SELECT DISTINCT a.country_name, b.vendor_name,
SUM(a.gmv_local) as total_gmw
from `my-project-67287.order1.order2`a
join `my-project-67287.vendor1.vendor2` b on a.vendor_id = b.id
group by a.country_name, b.vendor_name
) AS vendors
GROUP BY vendors.country_name;
I must mention I have not tested your query, since I do not have your tables, so I assumed it's correct.
I only created the vendors table with the required fields and values from your picture. This should print:
SELECT odr.c_name,vdr.v_name,odr.gmv
FROM(
SELECT *
FROM(
SELECT c_name,v_id,gmv
FROM `order`
ORDER BY gmv DESC
)
GROUP BY c_name
)AS odr
LEFT JOIN vender AS vdr ON vdr.id = odr.v_id
GROUP BY odr.c_name
c_name short for country_name

Creating a join where I pull a count from another table

I have a table with real estate agent's info and want to pull firstname, fullname, and email from rets_agents.
I want to then get a count of all of their sales from a different table called rets_property_res_mstr.
I created a query that doesn't work yet so I need some help.
SELECT r.firstname, r.fullname, r.email
from rets_agents r
LEFT JOIN rets_property_res_mstr
ON r.email = rets_property_res_mstr.ListAgentEmail
LIMIT 10;

I'm not sure how to get the count in this.
You seem to be looking for aggregation:
SELECT a.firstname, a.fullname, a.email, COUNT(p.ListAgentEmail) cnt
FROM rets_agents a
LEFT JOIN rets_property_res_mstr p ON r.email = p.ListAgentEmail
GROUP BY a.firstname, a.fullname, a.email
ORDER BY ?
LIMIT 10;
Note that, for a LIMIT clause to really make sense, you need a ORDER BY clause so you get a deterministic results (otherwise, it is undefined which records will be shown) - I added that to your query with a question mark that you should replace with the relevant column(s).
I would consider using a CTE for this:
WITH sales as (
SELECT ListAgentEmail, count(*) count_of_sales
FROM rets_property_res_mstr
GROUP BY ListAgentEmail
)
SELECT r.firstname, r.fullname, r.email, count_of_sales
from rets_agents r
LEFT JOIN sales
ON r.email = sales.ListAgentEmail
LIMIT 10;

Select from one table with count from two other tables

I'm doing a query where i select all from a table called employee and want to do a count of employee_id from two other tables and represent the count in 2 seperate columns.
The tables:
employee [id, etc.]
report [id, employee_id, etc.]
office_report[id, employee_id, etc.]
What i did so far is:
SELECT emp.*, COUNT(rep.id ) no_of_field_reports, COUNT(of_rep.id) no_of_office_reports
FROM employee emp
LEFT JOIN report rep
ON (emp.id = rep.employee_id)
LEFT JOIN office_report of_rep
ON (emp.id = of_rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
The problem is, as soon as i have reports in BOTH report tables the count messes up. Say i have 16 reports in report table and 2 in office_report table, the count for no_of_field_reports and no_of_office_reports will become 32.
Im missing something obviously but as I'm not a SQL genius I can't figure out what.
Please make sure to explain what is causing the problem so I'm able to learn from my mistakes and get a better understanding of these type of queries as this is not going to be the last time.
I guess the answer will be the same for mariaDB, mySQL, and SQL in general so i added all those tag's for the sake of attention..
Possibly one approach if you're after distinct counts ( though you may need to adjust to the PK field)
SELECT emp.*,
COUNT(distinct rep.id ) no_of_field_reports, --may need to be on Unique key instead
COUNT(distinct of_rep.id) no_of_office_reports --may need to be on Unique key instead)
FROM employee emp
LEFT JOIN report rep
ON (emp.id = rep.employee_id)
LEFT JOIN office_report of_rep
ON (emp.id = of_rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
An approach getting the counts before the joins if you're not after a distinct count then this is likely the right approach and offers flexibility.
SELECT emp.*, rep.cnt, of_Rep.cnt
FROM employee emp
LEFT JOIN (SELECT count(ID) cnt , employee_ID
FROM REPORT
GROUP BY employee_ID) rep
ON (emp.id = rep.employee_id)
LEFT JOIN (SELECT count(ID) cnt, Employee_ID
FROM office_report
GROUP BY employee_ID) of_rep
ON (emp.id = of_Rep.employee_id)
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC
or use of correlated queries (but not supported all the time Such as when creating materialized views from this SQL)
SELECT emp.*,
(SELECT count(ID)
FROM REPORT
WHERE emp.id = rep.employee_id) Report_Cnt,
(SELECT count(ID)
FROM office_report of_REP
WHERE emp.id = of_Rep.employee_id) of_Rep_Cnt
FROM employee emp
WHERE emp.user_id =7 AND emp.active = 1
GROUP BY emp.id, emp.name
ORDER BY emp.name ASC

MySQL subquery referencing a table outside it's scope

In the following query I'm receiving
Error Code: 1054 Unknown column 'PRF.user_id' in 'where clause'
This is due to the fact that the subquery is attempting to reference PRF.user_id which is outside it's own scope. How can I rewrite the query in order to overcome this issue?
SELECT user_id, lastname,
(
SELECT COUNT(*) FROM
(
SELECT *
FROM Demo_Orders_M
WHERE DemoOrderStatus = 253
AND DemoOrderDate BETWEEN '2015-06-19' AND '2015-06-26'
AND `User` = PRF.user_id
GROUP BY CustomerID, `User`
HAVING COUNT(*) > 1
) t1
) recycling
FROM tbl_profiles PRF
JOIN tbl_users U ON PRF.user_id = U.id
WHERE PRF.user_id IN ( SELECT a.user_id FROM tbl_profiles a WHERE a.user_id IN ('1210', '789') )
GROUP BY user_id
The first thing I've noticed is that your subquery has a GROUP BY and HAVING clause without any aggregate functions, which shouldn't be the case. It looks to me that what you are trying to accomplish is getting the COUNT(*) of demo orders for each user/customer combination. You can write that individual query like this:
SELECT customerID, user, COUNT(*) AS numOrders
FROM demo_orders_m
WHERE demoOrderStatus = 253 AND demoOrderDate BETWEEN '2015-06-19' AND '2015-06-26'
GROUP BY customerID, user
HAVING COUNT(*) > 1;
This is a simple aggregation query that will pull the number of orders each user has that meet the given criteria, and as long as they have two or more orders.
Then, you can join these results to your users table to get other info about those users. One thing to note about your query also is that you don't need to write an extra select statement that pulls the user ids like that, what you've written is redundant. The whole condition can be rewritten as:
WHERE PRF.user_id IN(1210, 789)
So, the final query would be as follows. Note that I used a LEFT JOIN and the coalesce function to make sure a zero value is returned for users who didn't meet the order criteria, and as a result were not returned by the subquery:
SELECT user_id, lastname, COALESCE(numOrders, 0) AS numOrders
FROM tbl_profiles PRF
JOIN tbl_users U ON U.id = PRF.user_id
LEFT JOIN(
SELECT customerID, user, COUNT(*) AS numOrders
FROM demo_orders_m
WHERE demoOrderStatus = 253 AND demoOrderDate BETWEEN '2015-06-19' AND '2015-06-26'
GROUP BY customerID, user
HAVING COUNT(*) > 1) TMP ON TMP.user = U.id AND TMP.user IN (1210, 789);

SQL Join returns only one record

I'm writing a query whereby I'm trying to count the total number of records in report and assignment table, whiles at the same time retrieving information from the main table group. Group has a primary key id which is saved in the other tables as gid. This is the query:
SELECT `group`.`id` AS `gid`
, `group`.`name` AS `g_name`
, COUNT(`report`.`id`) AS `reports`
FROM `group`
LEFT OUTER JOIN `report` ON `report`.`gid` = `group`.`id`
LEFT OUTER JOIN `assignment` ON `assignment`.`gid` = `group`.`id`
WHERE `group`.`active` = 0
ORDER BY
`group`.`name`;
My problem is whenever I execute this only one record is returned even if theirs multiple groups.
Thanks in advance.
Well, your query is far from correct :) First of all, you should not have aggregated functions (in this case count) without a group by clause. Now, even if you have that clause the query will summarize information and you want both: the detail and a summary in the same query. I'd recommend 2 separate queries to retrieve this information, but if you want information mixed in only one query (the detail and also the "total number of records in report and assignment table") try the following query:
SELECT
`group`.id AS gid,
`group`.name AS g_name,
(SELECT COUNT(*) from report) as ReportTotalCount,
(SELECT COUNT(*) from assignment) as AssignmentTotalCount,
FROM `group`
WHERE `group`.`active` = 0
LEFT OUTER JOIN report ON report.gid = `group`.id
LEFT OUTER JOIN assignment ON assignment.gid = `group`.id
ORDER BY `group`.name;
I whish I could understand exactly what you're looking for but this might give you an idea on how to get the result you expect.
Can't see anything obvious in your query that would limit it to returning one record.
You are going to have to break it up to see where the problem is against your existing data.
So how many groups where acitive = 0, ahow many with a corresponding assignment record, etc.
maybe it will help:
SELECT
groupid,
groupname,
reports,
assignments,
FROM
(SELECT group.id, group.name, COUNT(*) AS reports from group
INNER JOIN report ON (report.gid = group.id)
WHERE group.active = 0
GROUP BY group.id ) AS ReportForGroup
CROSS JOIN
(SELECT group.id AS groupid, group.name AS groupname, COUNT(*) AS assignments from group
INNER JOIN assignmentON (assignment.gid = group.id)
WHERE group.active = 0
GROUP BY group.id ) AS AssignmentForGroup
ON (ReportForGroup.groupid = AssignmentForGroup.groupid)
ORDER BY groupname;
I'm can't check it so if LEFT JOIN returns to COUNT(*) 0 or 1. if it returns 0 just change the INNERs to LEFTs and use INNER JOIN between the two queries