I am trying to perform a count across multiple, linked tables:
select
vpp.Name
,count(sx.Occurences) as sx_Occurences
,count(vpp.Occurences) as vpp_Occurences
,count(sd.Occurences) as sd_Occurences
from v_p vpp
left outer join s_x sx on sx.ID = vpp.ID
left outer join s_d sd on sd.ID = vpp.ID
group by vpp.Name
This however gives me incorrect results (doing a count on one table only works fine, but as soon as I add a second (or a third, fourth...) the numbers are wrong.
I believe you are looking for this:
SELECT vpp.Name,
(SELECT count(sx.Occurences) FROM s_x WHERE s_x.ID = vpp.ID) as sx_Occurences,
count(vpp.Occurences) as vpp_Occurences,
(SELECT count(sd.Occurences) FROM s_d WHERE s_d.ID = vpp.ID) as sd_Occurences
FROM v_p vpp
GROUP BY vpp.Name;
You probably have 1:n relationship between at least 2 of the 3 tables. In the resultset you will have more records than you would have if you counted the records by each table individually.
If you want to count the distinct values of the given fields, then use count(distinct ...):
select
vpp.Name
,count(distinct sx.Occurences) as sx_Occurences
,count(distinct vpp.Occurences) as vpp_Occurences
,count(distinct sd.Occurences) as sd_Occurences
from v_p vpp
left outer join s_x sx on sx.ID = vpp.ID
left outer join s_d sd on sd.ID = vpp.ID
group by vpp.Name
Otherwise, you need to do the counting individually by each table. You can combine the 3 queries as subqueries:
select
t1.Name
,sx_Occurences
,vpp_Occurences
,sd_Occurences
from
(select name, id, count(vpp.Occurences) as vpp_Occurences
from v_p vpp
group by name, id) t1
left outer join
(select id, count(sx.Occurences) as sx_Occurences
from s_x sx
group by id) t2 on t1.ID = t2.ID
left outer join
(select id, count(sd.Occurences) as sd_Occurences
from s_d sd
group by id) t3 on t1.ID = t3.ID
Related
So I have a large subquery and I would like to join on that subquery while using the result of the subquery in the join.
For example, I have a table called patient and one called appointment, and I would like to get the number of appointments per patient with given criteria.
Right now I am doing something like this:
SELECT
t1.*
FROM
(
SELECT
patient.name,
patient.id,
appointment.date
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
WHERE
/* a **lot** of filters, additional joins, etc*/
) t1
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
patient
LEFT JOIN appointment ON appointment.patient_id = patient.id
GROUP BY
patient.id
) t2 ON t1.id = t2.id
The problem is that this returns the number of appointments for each patient independent from the subquery above it. I tried writing the join as this:
LEFT JOIN (
SELECT
COUNT(*) number_of_appointments,
patient.id
FROM
t1
GROUP BY
patient.id
)
But obviously I'm getting an error saying that table t1 doesn't exist. Is there any way for me to do this cleanly without having to repeat all of the filters from t1 in t2?
Thanks!
Why not use window functions?
SELECT p.name, p.id, a.date,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_appointments
FROM patient p LEFT JOIN
appointment a
ON a.patient_id = p.id
WHERE . . .
This provides the count based on the WHERE filtering. If you wanted a count of all appointments, then do the calculation before applying the WHERE:
SELECT p.name, p.id, a.date,
COALESCE(a.cnt, 0) as num_total_appointments,
COUNT(a.patient_id) OVER (PARTITION BY p.id) as num_matching appointments
FROM patient p LEFT JOIN
(SELECT a.*,
COUNT(*) OVER (PARTITION BY a.patient_id) as cnt
FROM appointment a
) a
ON a.patient_id = p.id
WHERE . . .
I´m trying to make a query listing all clients, and also get the last comment and
the date of that comment inside the table of history_client inside a single query for it to be listed.
select a.id_client,a.name,a.lastname,(select b.date_created,b.comentary
from history_of_client b where a.id_client = b.id_client_asociate) from clients_main_table
You could use an inner join on max(date_created) for id_client on history table and join
SELECT a.id_client,a.name,a.lastname, h.commentary
FROM clients_main_table a
INNER join (
select b.id_client_asociate, max(b.date_created) max_date
from history_of_client
group by b.id_client_asociate ) t on t.id_client_asociate = a.id_client
INNER JOIN history_of_client h on h.id_client_asociate = t.id_client_asociate
and h.date_created = t.max_date
Use the LEFT JOIN and INNER join to get your desired result set.
select a.id_client,
a.name,
a.lastname,
hc.date_created,
hc.comentary
from clients_main_table c
left join (select id_client_asociate,max(date_created) dt from history_of_client group by id_client_asociate) h
on (c.id_client = b.id_client_asociate)
inner join history_of_client hc
on (hc.id_client_asociate = b.id_client_asociate and hc.date_created = h.date_created)
I have a table of establishments and I want to return a result set with the latest inspection date from the inspections table. Right now I have:
SELECT business_table.business_name, business_table.address, inspection_table.date
FROM business_table
LEFT JOIN inspection_table ON business_table.id = inspection_table.business_id
WHERE inspection_table.date = (
SELECT MAX(date)
FROM inspection_table)
The problem is I get only one result with the latest inspection date. I need all of the establishments returned. The query will need to be efficient because I have about 600K establishments and 3Million inspections.
You are using an outer join. When a business record has no matching inspection record, then an empty inspection record is created an joined instead. So that outer-joined inspection record will have all columns NULL. Then you have WHERE inspection_table.date = (...). This dismisses all outer-joined records again, because NULL will never match.
Use AND instead, to make the condition part of the WHERE clause:
SELECT
b.business_name,
b.address,
i.date
FROM business_table b
LEFT JOIN inspection_table i
ON i.business_id = b.id
AND i.date = (SELECT MAX(date) FROM inspection_table);
Ah, you are not looking for the latest inspection date at all. You are looking for the latest inspection date per business.
In your solution you are still using an outer join that doesn't work. Don't do that. Either use an outer join and use it properly or use an inner join if you are fine with that.
Here is how to get the latest inspection per business with an outer join (so you also show businesses that have had no inspection, yet):
SELECT
b.business_name,
b.address,
i.date,
...
FROM business_table b
LEFT JOIN inspection_table i
ON i.business_id = b.id
AND (i.business_id, i.date) IN
(
SELECT business_id, MAX(date)
FROM inspection_table
GROUP BY business_id
);
Same with joins:
SELECT
b.business_name,
b.address,
i.date,
...
FROM business_table b
LEFT JOIN
(
SELECT business_id, MAX(date) AS date
FROM inspection_table
GROUP BY business_id
) latest ON latest.business_id = b.id
LEFT JOIN inspection_table i
ON i.business_id = latest.business_id
AND i.date = latest.date;
I ended using the following:
SELECT business_table.business_name AS Name, business_table.address AS Address, business_table.city AS City, business_table.state AS Province, inspection_table.rating AS Rating, inspection_table.date AS "Inspected"
FROM business_table
LEFT JOIN inspection_table ON business_table.id = inspection_table.business_id
WHERE inspection_table.date = (
SELECT MAX(inspection_table.date)
FROM inspection_table
WHERE business_table.id = inspection_table.business_id)
ORDER BY inspection_table.date DESC
I have a query that selects data from several tables using LEFT JOINS. The problem is data is being duplicated.
Here's the query
SELECT
A.ID,
T.T_ID,
T.name,
T.pic,
T.timestamp AS T_ts,
(SELECT COUNT(*) FROM track_plays WHERE T_ID = T.T_ID) AS plays,
(SELECT COUNT(*) FROM track_downloads WHERE T.T_ID) AS downloads,
S.S_ID,
S.status,
S.timestamp AS S_ts,
G.G_ID,
G.gig_name,
G.date_time,
G.lineup,
G.price,
G.currency,
G.pic AS G_pic,
G.ticket,
G.venue,
G.timestamp AS G_ts
FROM artists A
LEFT JOIN TRACKS T
ON T.ID = A.ID
LEFT JOIN STATUS S
ON S.ID = A.ID
LEFT JOIN GIGS G
ON G.ID = A.ID
WHERE A.ID = '$ID'
ORDER BY S_ts, G_ts AND T_ts DESC LIMIT 20
The problem is data is duplicated if one of the tables in the join has more data than another. So if tracks has 1 row, status has 2 and gigs has no rows you would get the data from tracks doubled.
I have tried using GROUP BY A.ID but that eliminates data. So in the example given before there would nly be one row of status show.
I've also tried GROUP_CONCAT but am unsure on that function so can't tell you much.
USING SELECT DISTINCT has the same effect as just the GROUP BY A.ID.
Assuming that artists -> gigs and artists -> tracks are 1-N mappings then you have two choices. (both of which were covered in the comments on your OP
1) Specify which of the N rows you want to get back to achieve a 1-1 map:
FROM artists A
LEFT JOIN TRACKS T ON T.ID = A.ID AND T.<SOMETHING> = SOMETHING
LEFT JOIN STATUS S ON S.ID = A.ID
LEFT JOIN GIGS G ON G.ID = A.ID AND G.<SOMETHING> = SOMETHNING
2) Do the joins as you wrote and get multiple entries for tracks and gigs and then pivot them in your calling application. Generally you'd put an ORDER BY clause in the query and check for the same artist key and pivot the list.
I would like to get the data from one table, and count all results from other table, depending on the first table data, here is what I tried:
SELECT
cars.*, (
SELECT
COUNT(*)
FROM
uploads
WHERE
uploads.cid = cars.customer
) AS `count`,
FROM
`cars`
WHERE
customer = 11;
I dont really have an idea why its not working, as I'm not a regular MySQL user/coder...
Could anyone direct me in the right direction with this one?
SELECT
c.*, COUNT(u.cid) AS count
FROM
cars c
LEFT JOIN
uploads u
ON
u.cid=c.customer
WHERE
u.customer = 11;
GROUP BY c.cid
Try it by joining both tables using LEFT JOIN
SELECT a.customer, COUNT(b.cid) totalCount
FROM cars a
LEFT JOIN uploads b
ON a.customer = b.cid
WHERE a.customer = 11
GROUP BY a.customer
using COUNT(*) in LEFT JOIN will have records to have a minimum count of 1.
SELECT cars.*,COUNT(uploads.*) as uplloaded
from cars
left outer join uploads on uploads.cid = cars.customer
where cars.customer = 11
group by uploads.cid;
Try this :
SELECT customer, COUNT(cid) totalCount
FROM cars
INNER JOIN uploads
ON (customer = cid)
WHERE customer = 11
GROUP BY customer