Query Returning One Row in MySQL - mysql

When I run the following query, I only get the first row:
SELECT
u.name AS Firstname, u.lastname AS Lastname, count( DISTINCT(p.id) ) AS Count
FROM
projects p
INNER JOIN users u ON p.user_fk = u.id
order by user_fk;
I have two tables, Projects and Users and the project table has a user ID which I am using to get the name from the users table. I then want to see how many unique projects there are for each user and display the amount of projects each user has.

You need a group by:
SELECT u.name AS Firstname, u.lastname AS Lastname,
count( DISTINCT p.id ) AS Count
FROM projects p INNER JOIN
users u
ON p.user_fk = u.id
GROUP BY u.name, u.lastname
order by user_fk;
In almost any other database, your query would return an error, because it has columns in the SELECT that are not aggregated and not in the GROUP BY. I think MySQL is moving toward making that the default behavior.

Related

Selecting Number of Values of a Child Table for Parent Table

On SQL, I have to return all user's name, phone and the number of tickets have, even if it's 0. I so far have tried using group by but the problem with that is it doesn't show the values of USERS that aren't associated with the ticket table and some extra random names.
User
Ticket
Here's what I've tried so far:
SELECT
U.Name,
U.Phone,
COUNT(*)
FROM
Users U
LEFT JOIN ticket T
ON U.USRID = T.USRID
GROUP BY T.USRID
I think you are looking for:
SELECT U.Name, U.Phone, COUNT(T.USRID)
FROM Users U LEFT JOIN
ticket T
ON U.USRID = T.USRID
GROUP BY U.Name, U.Phone;
Your GROUP BY columns should match the SELECT columns.

Order rows by amount of columns in another table

I'm currently outputting all of my members by adding the MySQL clause ORDER BY id DESC, but I feel that doesn't reward people that are active on my service.
I thought about judging the order by the amount of entries in another table they have under their ID.
Essentially, I'm asking if it's possible to order columns in a MAIN table counting the amount of rows where the users ID is in the column of the row.
Something pseudo to this
SELECT user_id,name,etc FROM users ORDER BY (
COUNT(SELECT FROM users_interactions WHERE user_id = user_id) *******
) ASC
In the end of the COUNT statement, the user_id = user_id was just a guess.
You are almost there - what you need to do is to put COUNT inside SELECT:
SELECT user_id,name,etc FROM users u ORDER BY (
SELECT COUNT(*)
FROM users_interactions i
WHERE i.user_id = u.user_id
) ASC
You could also do it using a JOIN, like this:
SELECT u.user_id, u.name, u.etc
FROM users u
LEFT OUTER JOIN users_interactions i ON i.user_id = u.user_id
GROUP BY u.user_id, u.name, u.etc
ORDER BY COUNT(*) ASC

SQL intermediate table having column = max(column)

I have 2 tables: user and review, a one-to-many relationship.
When I execute the following query:
SELECT
user_id,
count(*) totalReviews,
USER . NAME
FROM
review,
USER
WHERE
USER .id = review.user_id
GROUP BY
user_id
I get:
1 2 marius
2 2 daniela
3 1 alin
What I want to do now is to display first 2 users because they have given the most reviews(2).
I tried adding having, if I hardcode having totalReviews=2 it works, but if I write having total = max(total) I get 0 results, while if I'm trying with,
SELECT
*
FROM
(
SELECT
user_id,
count(*) total,
USER . NAME
FROM
review,
USER
WHERE
USER .id = review.user_id
GROUP BY
user_id
) A
WHERE
total = (SELECT max(total) FROM A) `
I get an error (table A doesn't exist)
You would do this with ORDER BY and LIMIT:
SELECT u.id, count(*) as totalReviews, u.name
FROM review r JOIN
user u
ON u.id = r.user_id
GROUP BY u.id, u.name
ORDER BY totalReviews DESC
LIMIT 2;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Table aliases make the query easier to write and read.
EDIT:
If occurs to me that you want all users with the maximum number of reviews, not exactly 2. Here is one method:
SELECT u.id, COUNT(*) as totalReviews, u.name
FROM review r JOIN
user u
ON u.id = r.user_id
GROUP BY u.id, u.name
HAVING totalReviews = (SELECT COUNT(*)
FROM review r2
GROUP BY r2.user_id
ORDER BY COUNT(*) DESC
LIMIT 1
);
Note that the subquery in the HAVING clause is simpler than the outer query. There is no need to bring in the user name.

MySQL Inline View "unknown fields"

I am presently in a DBS course and I am working on an inline view:
SELECT userId, firstname, lastname, gender
FROM
(SELECT COUNT(dvdId) dvdId, u.userId
FROM userDVD
JOIN users u ON userDVD.userId = u.userId
GROUP BY userId) as T
WHERE gender = 'F';
When I run the Query it returns the error unknown column in field list. If I try to specify
u.firstname, u.lastname, u.gender
I return the same error. Any thoughts?
SELECT T.userId, T.firstname, T.lastname, T.gender
FROM (
SELECT users.userId, users.firstname, users.lastname, users.gender
FROM userDVD
JOIN users ON userDVD.userId = users.userId
WHERE gender = 'F' GROUP BY userId
) as T;
I worked through it and it turns out I didn't realize that because I had to alias my inline view that I needed to specify it in the original select statement. This concept was sadly not covered in my course. I appreciate those who gave helpful tips versus rude comments. So, Thank you Drew and Matt
Drew is right that you have a derived table T, but I'll attempt to add some details which might be useful to you as you are in a course.
you have a derived table T
an outer query (first select)
an inner query (second select in brackets)
the inner query uses a table alias of u for users.
the final columns of the inner query are dvdId which is a count of the dvdIds in userDvd table and userId
Because an outer query is constrained to use the final recordset of the inner query only those 2 columns are available to be selected and seeing they don't include firstname, lastname, or gender you are recieving the error.
If you want to keep your query the same but to use those columns you could join your derived table back to the user table and get the columns you desire. Such as this:
SELECT userId, firstname, lastname, gender
FROM
(SELECT COUNT(dvdId) dvdId, u.userId
FROM userDVD
JOIN users u ON userDVD.userId = u.userId
GROUP BY userId) as T
INNER JOIN users u2
ON t.user_id = u2.user_id
WHERE gender = 'F';
That technique to join back to the original table is great for when you have to optimize an aggregation that is on a large table or look for duplicates or something like that. However in your case you really just need a single query aggregating on all of the columns you want in the result set such as this:
SELECT
u.userId, u.firstname, u.lastname, u.gender, COUNT(d.dvdId) as DVDCount
FROM
userDVD d
JOIN users u
ON d.userId = u.userId
WHERE u.gender = 'F'
GROUP BY
u.userId, u.firstname, u.lastname, u.gender
;

select a column corresponding to max value in two joined tables

I have two tables, say Users and Interviews. One user can have multiple interview records.
Users
-----
UserID
FirstName
LastName
Interviews
----------
InterviewID
UserID
DateOfInterview
I want to get only the latest interview records. Here's my query
select u.UserID, firstname, lastname, max(DateOfInterview) as latestDOI
from users u
left join interviews i
on u.UserID = i.UserID
GROUP BY u.UserID, firstname, lastname
ORDER BY max(DateOfInterview) DESC
How do I update the query to return the InterviewID as well (i.e. the one which corresponds to max(DateOfInterview))?
Instead of using an aggregate function in your select list, you can use an aggregate subquery in your WHERE clause:
select u.UserID, firstname, lastname, i.InterviewId, DateOfInterview as latestDOI
from users u
left join interviews i
on u.UserID = i.UserID
where i.UserId is null or i.DateOfInterview = (
select max(DateOfInterview)
from interviews i2
where i2.UserId = u.UserId
)
That does suppose that max(DateOfInterview) will be unique per user, but the question has no well-defined answer otherwise. Note that the main query is no longer an aggregate query, so the constraints of such queries do not apply.
There are other ways to approach the problem, and it is worthwhile to look into them because a correlated subquery such as I present can be a performance concern. For example, you could use an inline view to generate a table of the per-user latest interview dates, and use joins to that view to connect users with the ID of their latest interview:
select u.*, im.latestDOI, i2.InterviewId
from
users u
left join (
select UserID, max(DateOfInterview) as latestDOI
from interviews i
group by UserID
) im
on u.UserId = im.UserId
left join interviews i2
on im.UserId = i2.UserId and im.latestDOI = i2.DateOfInterview
There are other alternatives, too, some standard and others DB-specific.
Rewrite to use an OUTER APPLY when grabbing your interview, that way you can use order by rather than MAX
select u.UserID, firstname, lastname, LatestInterviewDetails.ID, LatestInterviewDetails.DateOfInterview as latestDOI
from users u
OUTER APPLY (SELECT TOP 1 Id, DateOfInterview
FROM interviews
WHERE interviews.UserID = u.UserId
ORDER BY interviews.DateOfInterview DESC
) as LatestInterviewDetails
Note: This is providing you are using Microsoft SQL Server