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
Related
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
I'm stuck with a query not returning unique records.
I have following tables:
clinics (id => PK)
patients (id => PK, clinic_id => FK)
patient_visits(id => PK, patient_id => FK, clinic_id => FK)
A patient is registered to a clinic. A patient can visit to any clinic any number of times.
What I want is to return all unique patients who visited in a clinic.
I tried following query which is not returning unique records for a clinic
SELECT v.id
, v.patient_id
, v.clinic_id
, c.name clinic_name
, p.name
, p.mobile
, p.email
, p.gender
, p.created_at
, last_visit_date
, visit_count
FROM
( SELECT DISTINCT patient_id
, clinic_id
FROM patient_visits
) pat
JOIN patient_visits v
ON pat.patient_id = v.patient_id
JOIN clinics c
ON c.id = v.clinic_id
JOIN patients p
ON p.id = v.clinic_id
JOIN
( SELECT patient_id
, MAX(patient_visits.created_at) last_visit_date
, COUNT(patient_visits.created_at) visit_count
FROM patient_visits
GROUP
BY patient_id
) visits_aggregate
ON visits_aggregate.patient_id = p.id
WHERE v.clinic_id = ?
ORDER
BY visit_date
One problem I understand is if I join with patient_visits, it will pick matching duplicate patient_id, clinic_id combination.
You should refrain from JOINing to all the rows in patients_visits as it will cause the notorious combinatorial explosion leading to duplicate rows. You need an aggregate.
But, your example showed patient_visits.id. If you don't want duplicates in your result set for each visit, you cannot show that column; it has a different value for each visit.
You need an aggregate from the patient_visits table, like this:
SELECT patient_id, clinic_id,
MAX(created_at) last_visit_date,
COUNT(*) visit_count
FROM patient_visits
GROUP BY patient_id, clinic_id
That query contains one row per combination of patient and clinic, so you can JOIN it to your other tables without generating duplicate rows. Before you do that, run it separately to convince yourself it works correctly.
Then... use it in your query like this
select patients.id patient_id, clinics.id clinic_id,
clinics.name as clinic_name,
patients.name, patients.mobile, patients.email, patients.gender,
patients.created_at,
pv.last_visit_date, pv.visit_count
from patients
join ( SELECT patient_id, clinic_id,
MAX(created_at) last_visit_date,
COUNT(*) visit_count
FROM patient_visits
GROUP BY patient_id, clinic_id
) pv ON patients.id = pv.patient_id
join clinics ON pv.clinic_id = clinics.id
order by pv.last_visit_date
See how this works? You don't want all the visits, just an aggregate of them giving the date of the most recent one and the count.
I don't realy understand your complex query. Your Query should be straight forward:
select
pv.patient_id,
pv.clinic_id,
max(pv.visit) as last_visit,
count(*) as visit_count
from
patient_visit pv,
patients p
-- You may now here join the other tables
where
pv.patients_id = p.id
and pv.clinic_id = ?
group by
pv.patient_id
As I see this, your use of distinct is in the inner select. And you are selecting patient_visit twice creating a power set of the table getting all combinations.
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;
i have table with student_uid,grade,test_name as columns i want to count how many got each grade..for this
SELECT a.grade,COUNT(a.grade) AS count1
FROM 2015_2016_x_english_grades AS a
where test_name='ut1_marks'
GROUP BY grade
for single table worked how to do it for more than one table
my query:
SELECT a.grade, COUNT(a.grade),b.grade,COUNT(b.grade)
FROM 2015_2016_x_english_grades a
INNER JOIN 2015_2016_x_hindi_grades b ON a.grade=b.grade
WHERE a.test_name = b.ut1_marks='ut1_marks'
GROUP BY a.grade,b.grade
what is wrong in this?
i also tried this
SELECT a.grade,COUNT(a.grade),(SELECT COUNT(b.grade)FROM 2015_2016_x_biology_grades b where b.test_name='ut1_marks' GROUP BY b.grade)as count1 FROM 2015_2016_x_biology_grades a where test_name='ut1_marks' GROUP BY a.grade
it says [Err] 1242 - Subquery returns more than 1 row
Do the counting in subqueries, and join the subqueries.
SELECT e.grade, english_count, hindi_count
FROM (SELECT grade, COUNT(*) AS english_count
FROM 2015_2016_x_english_grades
WHERE test_name = 'ut1_marks'
GROUP BY grade) AS e
JOIN (SELECT grade, COUNT(*) as hindi_count
FROM 2015_2016_x_hindi_grades
WHERE test_name = 'ut1_marks'
GROUP BY grade) AS h
ON e.grade = h.grade
Or if there's a unique key in each table, you can do:
SELECT e.grade, COUNT(DISTINCT e.id) AS english_count, COUNT(DISTINCT h.id) AS hindi_count
FROM 2015_2016_x_english_grades AS e
JOIN 2015_2016_x_hindi_grades AS h ON e.grade = h.grade AND e.test_name = h.test_name
WHERE e.test_name = 'ut1_marks'
GROUP BY e.grade
Note that both of these queries will only show a grade if it exists in both tables. To get grades that only exist in one table, you need a FULL OUTER JOIN, but MySQL doesn't have this operation. See
Full Outer Join in MySQL
for how to emulate them.
Below are the two tables, customer and department. I am struggling very hard to get the output.
I want to write the query which shows only the department name which have maximum number of employees.
Answer should be like this ...
Please help me to write the query.
I would suggest using a sub-query, and then selecting from that query. With the outer select, you order by the number of employees and then limit it to 1. This will give you the top department, but also has the flexibility to be modified to give you a list of the x-number of top departments.
SELECT Dep_Name FROM (
SELECT
d.Dep_Name, COUNT(*) AS `count`
FROM
Departments d
JOIN Employees e ON e.Dep_id = d.Dep_id
GROUP BY
d.Dep_id
) AS q
ORDER BY `count` DESC
LIMIT 1
UPDATE
Per a comment by #Dems, you can actually handle this without a sub-query:
SELECT
d.Dep_Name
FROM
Departments d
JOIN Employees e ON e.Dep_id = d.Dep_id
GROUP BY
d.Dep_id
ORDER BY
COUNT(*) DESC
LIMIT 1
SELECT *
FROM
(
SELECT
d.dep_id,
d.dep_name,
count(c.cus_id) cusCount
FROM
cus c,
dep d
WHERE
c.dep_id = d.dep_id
GROUP BY
d.dep_id,d.dep_name
ORDER BY
cusCount desc)
WHERE
ROWNUM = 1;
I created cus & dep tables in Oracle 10g database and tested my code successfully.
What database are you using, and could you post you code.
There error message shows that your "Order by" clause is wrong.