Count group by across multiple tables - mysql

I am trying to get individual counts for multiple table join results.
I have a table of several divisions that should be joined to a table of dealers, which in turn, should be joined to a table of all the transactions by those dealers. I want to show how many dealer and transactions there are per division.
The following query returns the total number of transactions for both the transactionCount and the dealerCount, instead of unique values for each.
SELECT
d.*,
COUNT(dlr.id) AS dealerCount,
COUNT(t.id) AS transactionCount
FROM
division AS d
INNER JOIN
dealers AS dlr ON dlr.division = d.id
INNER JOIN
transactions AS t ON t.dealer_code = dlr.dealer_code
GROUP BY
d.id

I haven't tested this, but what about using
count(distinct dlr.id)
in your select?

Related

Join mysql table with distinct value from another table

I encountered a problem on a database I am working with. I have a table of counsels which may hold repeating values, but their is an enrolment number filed which is unique and can be used to fetch them. However, I want to join from a cases_counsel table on the "first" unique value of the counsel table that matches that column on the cases counsel table.
I want to list the cases belonging to a particular counsel using the enrolment_number as the counsel_id on the cp_cases_counsel table. That means I want to pick just a distinct value of a counsel, then use it to join the cp_cases_counsel table and also return the count for such.
However, I keep getting duplicates. This was the mysql query I tried
SELECT T.suitno, T.counsel_id, COUNT(*) as total from cp_cases_counsel T
INNER JOIN (SELECT
enrolment_number as id, MIN(counsel)
FROM
cp_counsel
GROUP BY
enrolment_number
) A
ON A.id = T.counsel_id
GROUP BY T.suitno, T.counsel_id
and
SELECT enrolment_number as id, MIN(counsel) as counsel, COUNT(*) as total FROM cp_counsel
JOIN cp_cases_counsel ON cp_cases_counsel.counsel_id = cp_counsel.enrolment_number
GROUP BY enrolment_number
For the second query, it's joining twice and I am having like double of what I am supposed to get.
The columns that you want in the results are councel (actually only one of all its values) from cp_counsel and counsel_id from cp_cases_counsel, so you must group by them and select them:
SELECT a.counsel, t.counsel_id, COUNT(*) AS total
FROM cp_cases_counsel t
INNER JOIN (
SELECT enrolment_number, MIN(counsel) AS counsel
FROM cp_counsel
GROUP BY enrolment_number
) a ON a.enrolment_number = t.counsel_id
GROUP BY a.counsel, t.counsel_id;

I'm unable to join two tables without a duplicates in mysql

I have two tables:
Members (member_id, member_gender)
Orders (order_id, member_id, order_amount)
I have to retrieve data about the amount of members, amount of buyers (members with at least 1 order), amount of orders
But unfortunately I have a hard time because when i try to join these two tables i recieve dublicates and I am unable to count distinctive members
So my initial code was:SELECT count(m.member_id) AS Amount_of_members ,count(o.order_id) ,sum(o.order_amount) FROM tbl_member m LEFT JOIN tbl_order o ON m.member_id = o.member_id
You can ask the db to count only unique occurrences of the member id
SELECT count(DISTINCT m.member_id) AS Amount_of_members
You can also run a subquery to group the orders up so there is only one row per member before you join to the members table, which means the members data won't be doubled up if a member has 2 orders, tripled up if they have 3 etc
SELECT
count(m.member_id) AS Amount_of_members ,
sum(x.count_orders) as total_count_of_orders,
sum(x.sum_orders) as total_sum_of_orders
FROM
tbl_member m
LEFT JOIN (
SELECT
o.member_id,
count(o.order_id) as count_orders ,
sum(o.order_amount) as sum_orders
FROM
tbl_order o
GROUP BY o.member_id
)x ON m.member_id = x.member_id
Generally the "squash the many side of a 1:M relationship down to one row before the join is done" is a helpful way to manage the data, especially if there are multiple joins that need to be made. Getting everything 1:1 means no duplicates pop up

Counting amount of base records in (My)Sql 1-to-many relation

I have these two tables:
invoices (contains id field)
contracts (contains fk to invoice + 'code' field)
Let's say I have one record in the invoices table and two records in the contracts table. Both records in the contracts table point to the same invoice record.
Desire: I'd like to count the amount of invoices.
What I've got so far:
select
c.code, count(*)
from
invoices i
join
contracts c
on
c.invoice_id = i.id
group by
c.code
Although the count shows two instead of the desired 1. I understand that this is because of the join on the contract table, but not sure how to fix this.
Try with COUNT(DISTINCT i.id); it should count the different invoice id's in the resultset.
select
c.code, count(distinct i.id)
from
invoices i
join
contracts c
on
c.invoice_id = i.id
group by
c.code
You want the number of invoices?
select count(*)
from invoices i
You want invoices with contracts?
select count( distinct c.invoice_id)
from
contracts
Your code finds number of contracts per each invoice

Selecting count(column) from different table

I have three tables area,vehicle and employee.
ward_no is the foreign key for vehicle and employee.
I want to select the number of vehicles and number of employees and display them along with other details of area.
The query i used is:
select a.* ,count(v.vid) as vehicles,count(e.eid) as employees from area a,vehicle v,employee e where v.ward_no=a.ward_no and e.ward_no=a.ward_no group by a.name;
But the output is not what I want. I get the same values in both the columns where the count is use instead of displaying the total number of vehicles/employees in that particular area.
I'm new to MySQl
The default behavior of count is to count the non-null values.
In your case, this counts repetitions of the value.
Try adding DISTINCT inside the count:
select a.* ,count(DISTINCT v.vid) as vehicles,count(DISTINCT e.eid) as employees
from area a,vehicle v,employee e
where v.ward_no=a.ward_no and e.ward_no=a.ward_no group by a.name;
Also, it's better to use explicit JOIN rather than implicit, like this:
select a.* ,count(DISTINCT v.vid) as vehicles,count(DISTINCT e.eid) as employees
from area a JOIN vehicle v ON v.ward_no=a.ward_no
JOIN employee e ON e.ward_no=a.ward_no
group by a.name;
There may be a chance that you are getting same vehicle and employee multiple times due to the joins, Use DISTINCT in COUNT() get count of unique vehicles and employees
SELECT
a.*,
COUNT(DISTINCT v.vid) AS vehicles,
COUNT(DISTINCT e.eid) AS employees
FROM
`area` a
JOIN vehicle v
ON v.ward_no = a.ward_no
JOIN employee e
ON e.ward_no = a.ward_no
GROUP BY a.name

MySQL Compare Result in WHERE clause

I imagine I'm missing something pretty obvious here.
I'm trying to display a list of 'bookings' where the total charges is higher than the total payments for the booking. The charges and payments are stored in separate tables linked using foreign keys.
My query so far is:
SELECT `booking`.`id`,
SUM(`booking_charge`.`amount`) AS `charges`,
SUM(`booking_payment`.`amount`) AS `payments`
FROM `booking`
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id`
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id`
WHERE `charges` > `payments` ///this is the incorrect part
GROUP BY `booking`.`id`
My tables look something like this:
Booking (ID)
Booking_Charge (Booking_ID, Amount)
Booking_Payment (Booking_ID, Amount)
MySQL doesn't seem to like comparing the results from these two tables, I'm not sure what I'm missing but I'm sure it's something which would be possible.
try HAVING instead of WHERE like this
SELECT `booking`.`id`,
SUM(`booking_charge`.`amount`) AS `charges`,
SUM(`booking_payment`.`amount`) AS `payments`
FROM `booking`
LEFT JOIN `booking_charge` ON `booking`.`id` = `booking_charge`.`booking_id`
LEFT JOIN `booking_payment` ON `booking`.`id` = `booking_payment`.`booking_id`
GROUP BY `booking`.`id`
HAVING `charges` > `payments`
One of the problems with the query is the cross join between rows from `_charge` and rows from `_payment`. It's a semi-Cartesian join. Each row returned from `_charge` will be matched with each row returned from `_payment`, for a given `booking_id`.
Consider a simple example:
Let's put a single row in `_charge` for $40 for a particular `booking_id`.
And put two rows into `_payment` for $20 each, for the same `booking_id`.
The query will would return total charges of $80. (= 2 x $40). If there were instead five rows in \'_payment\' for $10 each, the query would return a total charges of $200 ( = 5 x $40)
There's a couple of approaches to addressing that issue. One approach is to do the aggregation in an inline view, and return the total of the charges and payments as a single row for each booking_id, and then join those to the booking table. With at most one row per booking_id, the cross join doesn't give rise to the problem of "duplicating" rows from _charge and/or _payment.
For example:
SELECT b.id
, IFNULL(c.amt,0) AS charges
, IFNULL(p.amt,0) AS payments
FROM booking b
LEFT
JOIN ( SELECT bc.booking_id
, SUM(bc.amount) AS amt
FROM booking_charge bc
GROUP BY bc.booking_id
) c
ON c.booking_id = b.id
LEFT
JOIN ( SELECT bp.booking_id
, SUM(bp.amount) AS amt
FROM booking_payment bp
GROUP BY bp.booking_id
) p
ON p.booking_id = b.id
WHERE IFNULL(c.amt,0) > IFNULL(p.amt,0)
We could make use of a HAVING clause, in place of the WHERE.
The query in this answer is not the only way to get the result, nor is it the most efficient. There are other query patterns that will return an equivalent result.