Cardinality violation on mysql query - mysql

Im getting an error on this query:
SELECT i.name, i.surname, (SELECT u.username FROM user u WHERE u.info_id IN (1,9,10,15,25,40,42,43,44)) as email FROM `userinfo` i WHERE i.id IN (1,9,10,15,25,40,42,43,44)
Error:
Cardinality violation: 1242 Subquery returns more than 1 row
I know this could be solved by using a JOIN statment but i have no idea how to solve that.
To clarify more my question, I have two tables, user and userinfo:
User
id info_id username
Userinfo
id name surname
The info_id row from user is related to the id of userinfo, so having a list of userinfo ids in this format (1,4,7,8,9) I want name and surname (from userinfo) and username from user that match the info_id

You need to specify the relationship between the two table in the correlated subquery,
SELECT i.name,
i.surname,
(
SELECT u.username
FROM user u
WHERE u.info_id = i.id) as email
FROM userinfo i
WHERE i.id IN (1,9,10,15,25,40,42,43,44)
and by using JOIN (which I preferred more)
SELECT i.name,
i.surname,
u.username as Email
FROM userinfo i
INNER JOIN user u
ON u.info_id = i.id
WHERE i.id IN (1,9,10,15,25,40,42,43,44)
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins

You're only allowed to return one row in a field list. It seems like you want to group the results.
SELECT
i.name, i.surname,
GROUP_CONCAT(u.username) AS email
FROM
userinfo i
JOIN user u ON (i.id = u.info_id)
WHERE
i.id IN (1,9,10,15,25,40,42,43,44)
GROUP BY
i.id

SELECT i.name, i.surname, u.username as email
FROM `userinfo` i
INNER JOIN
`user` u ON i.info_id=u.id
WHERE i.id IN (1,9,10,15,25,40,42,43,44)
Learn to use joins, without them you are working wit both hands tied behind your back AND blindfolded. Joins are how to use the Relational part of Relational Databases.

Do you mean:
SELECT i.name, i.surname, (SELECT u.username FROM user u WHERE u.id IN (1,9,10,15,25,40,42,43,44)) as email
FROM `userinfo` i
WHERE i.id IN (1,9,10,15,25,40,42,43,44)

Related

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

mysql joining for relational lookup

I've never been all that great with much more then regular select queries. I have a new project that has users, roles and assigned_roles (lookup table for users with roles).
I want to group_concat the roles.name so that my result shows me what roles each user has assigned.
I've tried several things:
select users.id, users.displayname,users.email, rolenames from `users`
left join `assigned_roles` on `assigned_roles`.`user_id` = `users`.`id`
left join (SELECT `id`, group_concat(`roles`.`name`) as `rolenames` FROM `roles`) as uroles ON `assigned_roles`.`role_id` = `uroles`.`id`
This gives me the grouped role names but shows me duplicate entries if a user has two roles, so the second row in the result shows the same user but no role names.
select users.id, users.displayname,users.email, rolenames from `users`
join `assigned_roles` on `assigned_roles`.`user_id` = `users`.`id`
join (SELECT `id`, group_concat(`roles`.`name`) as `rolenames` FROM `roles`) as uroles ON `assigned_roles`.`role_id` = `uroles`.`id`
Just regular joins shows me what I want but wont lists users who do not have any assigned.roles, so its not complete.
I'll keep plugging away but I thought stack could help, hopefully I'll learn a bit more about joins today.
Thank you.
For GROUP CONCAT to work in this scenario, you'll need a GROUP BY to get the group info per user, something like;
SELECT u.id, u.displayname, u.email, GROUP_CONCAT(r.name) rolenames
FROM users u
LEFT JOIN assigned_roles ar ON ar.user_id = u.id
LEFT JOIN roles r ON r.id = ar.role_id
GROUP BY u.id, u.displayname, u.email

Joins In MySQL for fetching multiple tables data

I have two table user and follow. I want to write view such that it will fetch all details of particular user along with that two extra column as follower count and followee count alias.
eg. user id=11 then all details from user tables plus followcount 1 and followed count1
SELECT u.id,
u.userid,
u.name,
u.mobile,
(SELECT Count(*)
FROM follow f
WHERE f.followerid = u.userid) AS follower,
(SELECT Count(*)
FROM follow f
WHERE f.followeeid = u.userid) AS followee
FROM users u
You can achieve this is by using JOIN statements in your query:
example of how you can achieve your final result:
CREATE VIEW [Followers] AS
SELECT a.name, a.email, a.mobile, COUNT(SELECT COUNT(followerID) FROM follow WHERE followerID = a.userid), COUNT(SELECT COUNT(followeeID) FROM follow WHERE followeeID = a.userid) FROM users a INNER JOIN follow b ON b.followerID = a.userid

MYSQL JOIN syntax How to Join Three Tables

The following query does what I want. It returns all the resuls in the users table and then if there is a match in the details tble, returns the relevant data
users
id|username
details
id|userid|firstname|lastname
$sql = "SELECT u.*, d.*
FROM `users` u
LEFT JOIN `details` d on
u.id = d.userid
ORDER BY $strorder";
However, when I try to join an additonal table where I want to do the same thing--return all the results of the users table and if there is a match in the third table, return the relevant data (total followers of this user)--it only returns one record.
3rd table
follow
id|followerid|followedid
$sql = "SELECT u.*, d.*, COUNT(f.id)
FROM `users` u
LEFT JOIN `details` d on
u.id = d.userid
LEFT JOIN `follow` f on
u.id = f.followedid
ORDER BY $strorder";
Can anyone see what I am doing wrong? Thanks in advance for any suggestions.
Many thanks.
Try to avoid * to select fields, it will be clearer to group your datas (even if mysql is quite permissive with groupings).
When you have an aggregate function (like COUNT, SUM), the other "non aggregated" requested fields should be in a GROUP BY clause.
Mysql don't force you to GROUP BY all the fields, but... I think it's quite a good habit to be "as ANSI as possible" (usefull when you use another DBMS)
SELECT u.id, u.username, d.firstname, d.lastname, count(*) as numberfollowers
FROM user u
LEFT JOIN details d on u.id = d.userid
LEFT JOIN follow f on u.id = f.followedid
GROUP BY u.id, u.username, d.firstname, d.lastname --or just GROUP BY u.id with Mysql
ORDER BY count(*) desc
COUNT being an aggregate function, when selected with other columns, requires you to group your results by those other columns in the select list.
You should rewrite your query with columns that you want to select from users and details and group by those columns.