SQL statement group data from multiple tables under one - mysql

I was not sure how to phrase my question as I am new to SQL. It should not be too hard. Here is the scenario.
I have 3 tables:
customers
id,
contact
subscribers_from_x
customer_id
subscriber_name
subscribers_from_y
customer_id,
subscriber_name
here is the question:
Now, I want to select
customer.id
the number of times/count of customer.id occurs in subscribers_from_x
the number of times/count of customer.id occurs in subscribers_from_y
from these 3 tables
I have tried GROUP_BY COUNT(*) but not figuring it out. THanks

I might go with using two separate subqueries which aggregate counts by subscriber for the x and y tables:
SELECT t1.id,
t1.contact,
COALESCE(t2.x_count, 0) AS subscribers_from_x,
COALESCE(t3.y_count, 0) AS subscribers_from_y
FROM customers t1
LEFT JOIN
(
SELECT customer_id, COUNT(*) AS x_count
FROM subscribers_from_x
GROUP BY customer_id
) t2
ON t1.id = t2.customer_id
LEFT JOIN
(
SELECT customer_id, COUNT(*) AS y_count
FROM subscribers_from_y
GROUP BY customer_id
) t3
ON t1.id = t3.customer_id

SELECT DISTINCT(users.id),count(x.customer_id) 'X count',count(y.customer_id) 'Y Count'
FROM customers
LEFT JOIN subscribers_from_x x ON customers.id = x.customer_id
LEFT JOIN subscribers_from_y y ON customers.id = y.customerid
GROUP BY customers.id,subscribers_from_x.pk_col -- primary key col of subscribers_from_x
It will give you required output

Related

Wrong count result in mysql when joining two tables

I am trying to join two tables and get the count and grouped by specific field. However, it outputs same count values even if the other table consist only two rows. How should I fix this?
Here's my code:
SELECT tbl1.preferredDay, COUNT(tbl1.preferredDay) as count_1, COUNT(tbl2.preferredDay) as count_2
FROM tblschedule as tbl1
LEFT JOIN tblappointments as tbl2 ON (tbl1.preferredDay = tbl2.preferredDay)
WHERE tbl1.preferredDay = tbl2.preferredDay
GROUP BY preferredDay;
Here is the output but it should be [15, 0][3, 3]
Your query is based on left join it will return the same count().
This is a working query for Mysql 8:
with tbl1 as (
SELECT preferredDay, count(1) as count_1
FROM tblschedule
GROUP BY preferredDay
),
tbl2 as (
SELECT preferredDay, count(1) as count_2
FROM tblappointments
GROUP BY preferredDay
)
select t1.preferredDay, t1.count_1, t2.count_2
from tbl1 t1
inner join tbl2 t2 on t1.preferredDay = t2.preferredDay
There are two WITHs to get separately the count and then an INNER JOIN to join those results
For Mysql 5.7 and lower :
select t1.preferredDay, t1.count_1, t2.count_2
from (
SELECT preferredDay, count(1) as count_1
FROM tblschedule
GROUP BY preferredDay
) as t1
inner join (
SELECT preferredDay, count(1) as count_2
FROM tblappointments
GROUP BY preferredDay
) as t2 on t1.preferredDay = t2.preferredDay

Update row with maxdate where id from select and maxdate from select is given

I have a select statement that returns a set of ids and a maxdate. Now, I want to update the performance_date in the invoices table with the given maxdate where the given invoices ids.
Select invoices.id, max(invoicepositions.performance_date) as maxdate
from invoices
inner join invoicepositions on invoices.id = invoicepositions.invoice_id
where invoices.performance_date IS NULL
group by invoices.id
(How) is this possible with MySQL?
You can use your current SELECT query as a Derived Table and Join it to the invoices table using id, and then update.
UPDATE invoices AS i
JOIN
(
Select invoices.id, max(invoicepositions.performance_date) as maxdate
from invoices
inner join invoicepositions on invoices.id = invoicepositions.invoice_id
where invoices.performance_date IS NULL
group by invoices.id
) AS dt
ON dt.id = i.id
SET i.performance_date = dt.maxdate

SQL query to find comparision between different products

Hi i am a newbie to SQL and have one doubt on comparing different products across multiple tables.
I have 3 tables
T1:
Product_type
order_id
T2 and T3 also has the same fields.
All the tables have different product types. They may or may not have same order ids. Its like you can order product p1 from T1 and product p2 from T2 together on the same order id o1 or they can be separate orders.
I want to find the number of orders where product type(p1) from T1 and product type(p2) from T2 are ordered in the same order(having the same order id).
I am trying to run the query like this :
select COUNT(DISTINCT order_id) as CountOf from
(
select product_type from t1
UNION ALL select product_type from t2
)
AS m
where t1.product_type = p1 and t2.product_type = p2;
What i figured out is that i cannot access t1 and t2 in the outer query since they are used in the inner query. So is there a way i can make comparision between products?
Any help would be greatly appreciated.
Thank you
Try this:
select
count(distinct t1.order_id) as OrderCount
from
t1
inner join
t2 on t1.order_id = t2.order_id
where
t1.product_type = 'p1' and
t2.product_type = 'p2'
I can't understand what you want.
But inner query scope to brackets only. So you can not access outside to brackets. try to this
select COUNT(DISTINCT order_id) as CountOf from
(
select DISTINCT order_id from t1
where t1.product_type = p1
UNION ALL
select DISTINCT order_id from t2
where t2.product_type = p2
) m

using outer alias in mysql subquery

I am writing a mysql query and I have a question. Can I / How do I do something like this:
select rating, user_id, (
-- in here I want to write a subquery to get the number of times the user_id in the outter query has rated this teacher
) as user_rated_frequency from teachers_rating where teacher_id = id
Essentially I am trying to get data and the frequency in which that user rated that teacher. Is it possible to use an alias from one of the items I want to select in a subquery that is still in the select and not in the where clause?
Check out this ...
SELECT rating,
user_id,
(SELECT COUNT(*)
FROM teachers_rating t1
WHERE teacher_id = 3
AND t1.user_id = t2.user_id) AS user_rated_frequency
FROM teachers_rating t2
WHERE teacher_id = 3;
or that one:
SELECT AVG (rating) AS average_rating,
user_id,
(SELECT Count(*)
FROM teachers_rating t1
WHERE teacher_id = 3
AND t1.user_id = t2.user_id) AS user_rated_frequency
FROM teachers_rating t2
WHERE teacher_id = 3
GROUP BY user_rated_frequency;
Links above show a SQL Fiddle example assuming that id is 3.
Alternatively you could have a sub query in the FROM clause:
SELECT AVG (t1.rating),
t1.user_id,
t2.user_rated_frequency
FROM teachers_rating t1,
(SELECT tr.teacher_id,
tr.user_id,
COUNT(*) AS user_rated_frequency
FROM teachers_rating tr
GROUP BY tr.teacher_id) t2
WHERE t1.teacher_id = t2.teacher_id
AND t1.user_id = t2.user_id
GROUP BY user_id, user_rated_frequency
Hat a look at this Fiddle.
You need to move your subquery (technically called a derived table) into your from clause.
Something like so:
select
rating,
user_id,
from teachers_rating,
(in here I want to write a subquery to get the number of times the user_id in the outter query has rated this teacher) as user_rated_frequency f
where teacher_id = f.id

MySQL COUNT of multiple left joins - optomization

I have a query that is getting counts from multiple tables by using a LEFT JOIN and subqueries. The idea is to get a count various activites a member has participated in.
The schema looks like this:
member
PK member_id
table1
PK tbl1_id
FK member_id
table2
PK tbl2_id
FK member_id
table3
PK tbl3_id
FK member_id
My query looks like this:
SELECT t1.num1,t2.num2,t3.num3
FROM member m
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
WHERE m.member_id = 27
Where 27 is a test id. The actual query joins more than three tables and the query is run multiple times with the member_id being changed. The problem is this query runs pretty slow. I get the info I need but I am wondering if anyone could suggest a way to optimize this. Any advice is very much appreciated. Thanks much.
You should refactor your query. You can do this by reordering the way the query collects the data. How?
Apply the WHERE clause first
Apply JOINs last
Here is your original query:
SELECT t1.num1,t2.num2,t3.num3
FROM member m
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
WHERE m.member_id = 27
Here is you new query
SELECT
IFNULL(t1.num1,0) num1,
IFNULL(t1.num2,0) num2,
IFNULL(t1.num3,0) num3
FROM
(
SELECT * FROM member m
WHERE member_id = 27
)
LEFT JOIN
(
SELECT member_id,COUNT(*) as num1
FROM table1
WHERE member_id = 27
GROUP BY member_id
) t1 ON t1.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num2
FROM table2
WHERE member_id = 27
GROUP BY member_id
) t2 ON t2.member_id = m.member_id
LEFT JOIN
(
SELECT member_id,COUNT(*) as num3
FROM table3
WHERE member_id = 27
GROUP BY member_id
) t3 ON t3.member_id = m.member_id
;
BTW I changed member m into SELECT * FROM member m WHERE member_id = 27 in case you need any information about member 27. I also added the IFNULL function to each result to produce 0 in case count is NULL.
You need to make absolutely sure
member_id is the primary key of the member table
member_id is indexed in table1, table2, and table3
Give it a Try !!!
Without knowing your schema and what you've done for indexes, one POSSIBLE way to make this faster is:
SELECT (select ifnull(count(*),0) from table1 where table1.member_id = m.id) as num1,
(select ifnull(count(*),0) from table2 where table2.member_id = m.id) as num2,
(select ifnull(count(*),0) from table3 where table3.member_id = m.id) as num3
from member m
WHERE m.member_id = 27
Now, this is a slightly risky recommendation, simply because I don't know anything about your DB or what else is running, or where the bottlenecks are.
In general, it would be a good idea to post an explain plan with your query to get a better answer.
SELECT num1, num2, count(*) as num3
FROM (
SELECT member_id, num1, count(*) as num2
FROM (
SELECT member_id, count(*) as num1
FROM member
LEFT JOIN table1 USING (member_id)
WHERE member_id = 27) as m1
LEFT JOIN table2 USING (member_id)) as m2
LEFT JOIN table3 USING (member_id);