MySQL select where row is greater than one - mysql

I am working on a query that is joining multiple tables to drill down to get the number of subscribers who voted by region where subscribers have more than one vote.
The issue I am stuck at is trying to write in the query of figuring out the calculation of where subscribers voted more than one.
SELECT COUNT(*), regions.name,
(SELECT COUNT(*) FROM votes
LEFT JOIN profiles on votes.subscriber_id = profiles.subscriber_id
LEFT JOIN countries on profiles.country_id = countries.id
WHERE countries.region_id = regions.id GROUP BY votes.subscriber_id) as vote_count
FROM subscribers
LEFT JOIN profiles on subscribers.id = profiles.subscriber_id
LEFT JOIN countries on profiles.country_id = countries.id
LEFT JOIN regions on countries.region_id = regions.id
LEFT JOIN votes on subscribers.id = votes.subscriber_id
WHERE subscribers.created_at < '2011-04-22 00:00:00'
GROUP BY regions.id
HAVING vote_count > 1;
With the above query I am getting the error of, Subquery returns more than 1 row
Any ideas?

The section
SELECT COUNT(*) FROM votes
LEFT JOIN profiles on votes.subscriber_id = profiles.subscriber_id
LEFT JOIN countries on profiles.country_id = countries.id
WHERE countries.region_id = regions.id GROUP BY votes.subscriber_id
is returning more than one result. Try removing the "GROUP BY votes.subscriber_id" which should solve the problem

if your subquery:
(SELECT COUNT(*) FROM votes
LEFT JOIN profiles on votes.subscriber_id = profiles.subscriber_id
LEFT JOIN countries on profiles.country_id = countries.id
WHERE countries.region_id = regions.id GROUP BY votes.subscriber_id)
returns more than 1 row, then it will error, because it's trying to put a collection of rows into the value vote_count. You could solve this by guaranteeing the query has only 1 row result by adding a HAVING clause.

Since you place the sub query in the SELECT part of the query, only one return value is expected (since result sets are two dimensional).
You have to add somewhere in the inner query's WHERE clause a match to the outer query to make sure only one row matches.
What COUNT(*) is it you're looking for that matches regions.name? You have to connect the inner query to that.

Try putting the HAVING vote_count > 1 clause in the subquery. Also, try the subquery on its own to see what it's yielding.

Related

SQL Left Join a Table on a Left Joined Table

Iam currently trying to left join a table on a left joined table as follows.
I have the tables:
accounts (id, vorname, nachname)
projektkurse (id, accounts_id, projektwochen_id)
projektkurs_einzel (id, projektkurse_id)
projektkurs_einzel_zeiten (id, date, shift, projektkurs_einzel_id)
Now I want to get every account and the amount times they have an entry inside of projektkurs_einzel_zeiten, which should also be unique. So having the same date and shift multiple times does not count as multiple entries. The result should also be limited by the column projektwochen_id from the table projektkurse. This column should match a certain value for example 8.
Some Accounts don't have any entries in projektkurse, projektkurs_einzel and projektkurs_einzel_zeiten, this is why my first thought was using LEFT JOIN like this:
SELECT accounts.id, accounts.vorname, accounts.nachname, COUNT(DISTINCT projektkurs_einzel_zeiten.date, projektkurs_einzel_zeiten.shift) AS T
FROM accounts
LEFT JOIN projektkurse on accounts.id = projektkurse.creator_id
LEFT JOIN projektkurs_einzel on projektkurse.id = projektkurs_einzel.projektkurs_id
LEFT JOIN projektkurs_einzel_zeiten ON projektkurs_einzel.id = projektkurs_einzel_zeiten.projektkurs_einzel_id
WHERE projektkurse.projektwochen_id = 8
GROUP BY accounts.id
This query does not achieve exactly what I want. It only returns accounts that have atleast one entry in projektkurse even if they have none in projektkurs_einzel and projektkurs_einzel_zeiten. The Count is obviously 0 for them but the accounts that have no entries in projektkurse are being ignored completly.
How can I also show the accounts that don't have entries in any other table with the Count 0 aswell?
I would recommend writing the query like this:
SELECT a.id, a.vorname, a.nachname,
COUNT(DISTINCT pez.date, pez.shift) AS T
FROM accounts a LEFT JOIN
projektkurse
ON a.id = pk.creator_id AND
pk.projektwochen_id = 8 LEFT JOIN
projektkurs_einzel pe
ON pk.id = pe.projektkurs_id LEFT JOIN
projektkurs_einzel_zeiten pez
ON pe.id = pez.projektkurs_einzel_id
GROUP BY a.id, a.vorname, a.nachname;
Notes:
Your problem is fixed by moving the WHERE condition to the ON clause. Your WHERE turns the outer join into an inner join, because NULL values do not match.
Table aliases make the query easier to write and to read.
It is a best practice to include all unaggregated columns in the GROUP BY. However, assuming that id is unique, your formulation is okay (due to something called "functional dependencies").
You should not use eft join table's column ins where condition this work as inner join
You should move the where condition for a left joined table in the corresponding ON clause
SELECT accounts.id, accounts.vorname, accounts.nachname, COUNT(DISTINCT projektkurs_einzel_zeiten.date, projektkurs_einzel_zeiten.shift) AS T
FROM accounts
LEFT JOIN projektkurse on accounts.id = projektkurse.creator_id
AND projektkurse.projektwochen_id = 8
LEFT JOIN projektkurs_einzel on projektkurse.id = projektkurs_einzel.projektkurs_id
LEFT JOIN projektkurs_einzel_zeiten ON projektkurs_einzel.id = projektkurs_einzel_zeiten.projektkurs_einzel_id
GROUP BY accounts.id

Selecting only last record inside the JOIN statement

I have the following query:
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
I have three tables, from which I need to select data.
My problem begins with the last LEFT join.
modification_log table could have no entries, but also it could have more entries.
I want to select only the latest entry. With the above query, if I have 2 (or more) entries in the modification_log, I receive 2 identical results (repeated).
What I would like to get:
If there are no results in the modification_log, then it will return null. I think that is covered with LEFT JOIN. But also, in the case of many record, I would need to select the latest added one (amount)
I believe I might need a sub-query, but I fail to implement it.
You have to use a subquery for taking left join with modification_log table as
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN
(select * modification_log where subscription_id
IN ('447482') order by created_at desc LIMIT 1)
AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
Note that the where clause in subquery select * modification_log where subscription_id IN ('447482')
is the same as with the last where condition
Just add a max condition after your left join to get the latest entry to be joined, like below-
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
where usp.id IN ('447482') and ml.id = (select max(id) from modification_log)

MySQL - join two tables, group and count

I have two tables:
reviewStatusPhases - id|name
and
userPhase - id|reviewStatusPhase_id|user_id|created_at|updated_at
The reviewStatusPhases table have records inserted (Active, Inactive, On Pause, Terminated...), and userPhase is empty.
The tables are connected via
userPhase.reviewStatusPhase_id = reviewStatusPhases.id
one to one.
Is it possible that in one query I get all reviewStatusPhases, and cound how many users are in each phase? In this case I will get something like this:
Active (0 Users)
Inactive (0 Users)
On Pause (0 Users)
Terminated (0 Users)
I'm making some assumptions here (e.g. INNER JOIN versus LEFT JOIN in the join, and DISTINCT in the count), but it sounds like you just want
SELECT reviewStatusPhases.name, COUNT(DISTINCT userPhase.user_id)
FROM userPhase INNER JOIN reviewStatusPhases
ON userPhase.reviewStatusPhase_id = reviewStatusPhases.id
GROUP BY reviewStatusPhases.name
Query will be as follows:
SELECT r.name as `name`, count(u.id) as `count` FROM reviewStatusPhases r LEFT OUTER JOIN userPhase u ON r.id = u.reviewStatusPhase_id GROUP BY r.name
left outer join with reviewStatusPhases on left to show all names.
group by names of reviewStatusPhases.
display reviewStatusPhases name and count of user id's (to neglect null values)
Use LEFT JOIN as follows:
SELECT COUNT(m.UserId) FROM Table1 m
LEFT JOIN Table2 k ON k.StatusId = m.StatusId
WHERE k.Status = 'Inactive'
You can easily use the Status column to track the users and their activities. In your case, ReviewStatus.
I hope the following will be helpful
SELECT RPS.Name, COUNT(UP.user_id)
FROM reviewStatusPhases RPS
LEFT OUTER JOIN userphases UP ON RPS.id = UP.reviewStatusPhase_id
GROUP BY RPS.Name
ORDER BY RPS.Name
SELECT
DISTINCT s.s_level AS 'Level',
COUNT(DISTINCT s.s_id) AS Schools,
COUNT(DISTINCT st.st_id) AS Teachers
FROM schools AS s
JOIN school_teachers AS st ON st.st_school_idFk = s.s_id AND st.st_status = 1
WHERE s.s_status = 1
GROUP BY s.s_level

How to JOIN 2 MySQL tables to determine if joined table has a match

I have 2 MySQL tables (countries) and (reservations)
I want to list every row from countries and simply indicate whether there is a match on reservations or not.
In each instance:
reservations will have 1 matching rows, or
reservations will have many matching rows, or
reservations will have no matching rows
So all I want from the join is to know whether there is a match to reservations or not. Nothing else.
Here is my query statement:
SELECT country.countryID, reservation.citizen
FROM countries AS country
LEFT JOIN (
SELECT reservationID
FROM reservations
LIMIT 1
) AS reservation ON reservation.citizen = country.countryID
ORDER BY reservation.citizen
It fails with Unknown column 'reservation.citizen' in 'on clause'
CONCLUSION:
JOINs cannot solve the problem.
The issue is in the subselect. Notice you have not included the field citizen inside reservation.
SELECT country.countryID, reservation.citizen
FROM countries AS country
LEFT JOIN (
SELECT reservationID, citizen
FROM reservations
LIMIT 1
) AS reservation ON reservation.citizen = country.countryID
ORDER BY reservation.citizen
By the other hand, why are you doing a subselect? And why the limit? Wouldn't be better to just query the following?
SELECT
country.countryID,
count(reservation.reservationID)
FROM
countries AS country
LEFT JOIN reservations AS reservation
ON country.countryID = reservation.citizen
GROUP BY
country.countryID
HAVING
count(reservation.reservationID) > 0
ORDER BY
reservation.citizen
;
You have an issue with the join, it should be like
LEFT JOIN reservations AS reservation ON reservation.citizen = country.countryID
ORDER BY reservation.citizen
OR
LEFT JOIN (
SELECT *
FROM reservations
LIMIT 1
) AS reservation ON reservation.citizen = country.countryID
ORDER BY reservation.citizen
OR better LEFT OUTER JOIN to get rows not matching join conditions.
LEFT OUTER JOIN reservations AS reservation ON reservation.citizen = country.countryID
ORDER BY reservation.citizen

MySQL proper way to SELECT with many tables involved

I have movie database that has these tables: new_movies, ratings, critic_ratings, colors
I'm trying to execute this SELECT statement which will combine these 4 tables on the same movie using 'mid' (movie id):
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
But I get this error:
The SELECT would examine more than
MAX_JOIN_SIZE rows; check your WHERE
and use SET SQL_BIG_SELECTS=1 or SET
SQL_MAX_JOIN_SIZE=# if the SELECT is
okay
How do I properly do this query?
If you don't want to enable big selects, you could reform this using correlated sub-queries. (I don't know if you'll still hit the limit or not though.)
SELECT DISTINCT
new_movies.*,
movies_db.*,
(SELECT rating FROM ratings WHERE new_movies.mid = ratings.mid) AS rating,
(SELECT count FROM ratings WHERE new_movies.mid = ratings.mid) AS rating_count,
(SELECT color FROM colors WHERE new_movies.mid = colors.mid) AS colour,
(SELECT rating FROM critic_ratings WHERE new_movies.mid = critic_ratings.mid) AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
Also, worth a test to see if the LEFT JOINs are actually the cause, can you execute the following?
SELECT DISTINCT
new_movies.*,
movies_db.*
FROM
new_movies
INNER JOIN
movies_db
ON new_movies.mid = movies_db.mid
ORDER BY
title ASC
why do you have a movies and a new_movies table? surely a release date field would be sufficient for that - would cut out a join too...
to that end I would create a view of that data and query that instead.
But back to your query:
SELECT DISTINCT
new_movies.*,
movies_db.*,
ratings.rating,
ratings.count,
color,
critic_ratings.rating AS critic_ratings
FROM
new_movies
INNER JOIN
movies_db
ON
new_movies.mid = movies_db.mid
LEFT JOIN
ratings
ON
new_movies.mid = ratings.mid
LEFT JOIN
colors
ON
new_movies.mid = colors.mid
LEFT JOIN
critic_ratings
ON
new_movies.mid = critic_ratings.mid
ORDER BY
title ASC
I can't see anything obvious... perhaps you can post the results of an explain query?
There is no problem with your query per se. It's just that you're selecting all movies (no WHERE, no LIMIT) and since you're joining ratings for e.g., it will join all ratings to each movie. You are just reaching the max amount of data allowed for joins.
I'm not sure why you'd need to select all movies. Perhaps you can use a limit. Otherwise you can just try the solutions in the error message.