issue with joins - mysql

I have the following query, in which I used JOINs. It says:
unknown column m.bv ..
Could you please take a look and tell me what I'm doing wrong?
$query4 = 'SELECT u.*, SUM(c.ts) AS total_sum1, SUM(m.bv) AS total_sum
FROM users u
LEFT JOIN
(SELECT user_id ,SUM(points) AS ts FROM coupon GROUP BY user_id) c
ON u.user_id=c.user_id
LEFT JOIN
(SELECT user_id ,SUM(points) AS bv FROM matching GROUP BY user_id) r
ON u.user_id=m.user_id
where u.user_id="'.$_SESSION['user_name'].'"
GROUP BY u.user_id';

You are selecting SUM(points) AS bv from the table with the alias r, there is no tables with the alias m. So that it has to be r.bv instead like so:
SELECT
u.*,
SUM(c.ts) AS total_sum1,
SUM(r.bv) AS total_sum
FROM users u
LEFT JOIN
(
SELECT
user_id,
SUM(points) AS ts
FROM coupon
GROUP BY user_id
) c ON u.user_id=c.user_id
LEFT JOIN
(
SELECT
user_id,
SUM(points) AS bv
FROM matching
GROUP BY user_id
) r ON u.user_id = m.user_id
where u.user_id="'.$_SESSION['user_name'].'"
GROUP BY u.user_id

Replace m., with r. Look at second Join

You have aliased the derived table with r and you reference that table (twice) with m. Correct one or the other.
Since you group by user_id in the two subqueries and user_id is (I assume) the primary key of table user, you don't really need the final GROUP BY.
I would write it like this, if it was meant for all (many) users:
SELECT u.*, COALESCE(c.ts, 0) AS total_sum1, COALESCE(m.bv, 0) AS total_sum
FROM users u
LEFT JOIN
(SELECT user_id, SUM(points) AS ts FROM coupon GROUP BY user_id) c
ON u.user_id = c.user_id
LEFT JOIN
(SELECT user_id, SUM(points) AS bv FROM matching GROUP BY user_id) m
ON u.user_id = m.user_id
and like this in your (one user) case:
SELECT u.*, COALESCE(c.ts, 0) AS total_sum1, COALESCE(m.bv, 0) AS total_sum
FROM users u
LEFT JOIN
(SELECT SUM(points) AS ts FROM coupon
WHERE user_id = "'.$_SESSION['user_name'].'") c
ON TRUE
LEFT JOIN
(SELECT SUM(points) AS bv FROM matching
WHERE user_id = "'.$_SESSION['user_name'].'") m
ON TRUE
WHERE u.user_id = "'.$_SESSION['user_name'].'"
The last query can also be simplified to:
SELECT u.*,
COALESCE( (SELECT SUM(points) FROM coupon
WHERE user_id = u.user_id)
, 0) AS total_sum1,
COALESCE( (SELECT SUM(points) FROM matching
WHERE user_id = u.user_id)
, 0) AS total_sum
FROM users u
WHERE u.user_id = "'.$_SESSION['user_name'].'"

Related

sql select distinc where max date

I have 3 tables "maintenances", "cars", "users" . I want to select all data from table maintenance with a distinct car_id and the last record for each distinct (based on max maintenance_date)
SELECT
m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM
maintenances AS m
LEFT JOIN users AS u ON u.id = m.user_id
LEFT JOIN cars AS c ON c.id = m.car_id
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
The problem is that this query returns only one record which has the max date from all records. I want all records (distinct car_id and from records with the same car_id to display only values for max(maintenance_date))
This is your query:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
----------------------------------------------------------------^
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id);
It is an aggregation query. Without a group by, only one row is returned (all the rows are in one group). So, add the group by:
SELECT m. * , u.username, c.Model, c.Make, c.License, c.Milage, COUNT( m.process_id ) AS count_nr
FROM maintenances AS m LEFT JOIN
users AS u
ON u.id = m.user_id LEFT JOIN
cars AS c
ON c.id = m.car_id
WHERE maintenance_date = (SELECT MAX(m2.maintenance_date) FROM maintenances m2 WHERE m2.car_id = m.car_id);
GROUP BY c.id
I also fixed the correlation statement, to be clear that it is correlated to the outer query.
add GROUP BY u.username .
WHERE
maintenance_date = (SELECT MAX(maintenance_date) FROM maintenances WHERE car_id = m.car_id)
GROUP BY u.username

Report Query for multiple subqueries

Getting multiple records from table with subquery joins
SELECT
COUNT(*) AS total_count,
(SELECT
chat_box.user_id,
chat_box.message,
members.id,
members.display_name
FROM chat_box INNER JOIN members
ON chat_box.user_id = members.id
ORDER BY chat_id DESC LIMIT 1),
(SELECT COUNT(DISTINCT user_id) FROM chat_box) AS users_count
FROM chat_box
This is what I have so far, I want to get the members.display_name from the inner join where the chat_box.user_id = members.id as an output along aside the chat_box.message and save members.display_name and chat_box.message to a variable. Any help is appreciated.
It is not exactly clear what you are trying to do, but it seems like you could use something like this:
select u.user_id,
u.message,
u.id,
u.display_name,
cb1.total_count,
cb1.users_count
from
(
SELECT cb.user_id ,
cb.message,
m.id,
m.display_name
FROM chat_box cb
INNER JOIN members m
ON cb.user_id = m.id
) u
CROSS JOIN
(
select COUNT(*) AS total_count,
COUNT(DISTINCT user_id) AS users_count
FROM chat_box
) cb1

Adding another subquery

I have this query as my main query, I use all the records from the members table, and selected columns from comments and chat_box.
SELECT members.*,
a.commenter_id,
b.user_id,
a.comcount,
b.chatcount
FROM members
LEFT JOIN (SELECT commenter_id,
Count(*) comCount
FROM comments
GROUP BY commenter_id) a
ON members.id = a.commenter_id
LEFT JOIN (SELECT user_id,
Count(*) chatCount
FROM chat_box
GROUP BY user_id) b
ON members.id = b.user_id
WHERE members.id = '290'
I would like to add this query to the above
SELECT Count(friend_id) AS totFriend,
friend_id AS fi,
logged_user_id AS user,
friend_accepted AS fa
FROM member_friends
WHERE logged_user_id = '1'
AND friend_id = '290'
Is it possible to add this to the mix without causing any errors? I have tried it myself but I maybe just putting my self in deeper problems. If it is possible could someone assist me in doing so, thank you :).
If you have a way to join the last query to your members table, then you should be able to use:
SELECT members.*,
a.commenter_id,
b.user_id,
a.comcount,
b.chatcount,
c.totFriend
FROM members
LEFT JOIN
(
SELECT commenter_id,
Count(*) comCount
FROM comments
GROUP BY commenter_id
) a
ON members.id = a.commenter_id
LEFT JOIN
(
SELECT user_id,
Count(*) chatCount
FROM chat_box
GROUP BY user_id
) b
ON members.id = b.user_id
LEFT JOIN
(
SELECT Count(friend_id) AS totFriend,
friend_id AS fi,
logged_user_id AS user,
friend_accepted AS fa
FROM member_friends
WHERE logged_user_id = '1'
AND friend_id = '290'
) c
on members.id = c.friend_id
WHERE members.id = '290'

MySQL INNER JOIN select only one row from second table

I have a users table and a payments table, for each user, those of which have payments, may have multiple associated payments in the payments table. I would like to select all users who have payments, but only select their latest payment. I'm trying this SQL but i've never tried nested SQL statements before so I want to know what i'm doing wrong. Appreciate the help
SELECT u.*
FROM users AS u
INNER JOIN (
SELECT p.*
FROM payments AS p
ORDER BY date DESC
LIMIT 1
)
ON p.user_id = u.id
WHERE u.package = 1
You need to have a subquery to get their latest date per user ID.
SELECT u.*, p.*
FROM users u
INNER JOIN payments p
ON u.id = p.user_ID
INNER JOIN
(
SELECT user_ID, MAX(date) maxDate
FROM payments
GROUP BY user_ID
) b ON p.user_ID = b.user_ID AND
p.date = b.maxDate
WHERE u.package = 1
SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.id = (
SELECT id
FROM payments AS p2
WHERE p2.user_id = u.id
ORDER BY date DESC
LIMIT 1
)
Or
SELECT u.*, p.*
FROM users AS u
INNER JOIN payments AS p ON p.user_id = u.id
WHERE NOT EXISTS (
SELECT 1
FROM payments AS p2
WHERE
p2.user_id = p.user_id AND
(p2.date > p.date OR (p2.date = p.date AND p2.id > p.id))
)
These solutions are better than the accepted answer because they work correctly when there are multiple payments with same user and date. You can try on SQL Fiddle.
SELECT u.*, p.*, max(p.date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id
ORDER BY p.date DESC
Check out this sqlfiddle
SELECT u.*
FROM users AS u
INNER JOIN (
SELECT p.*,
#num := if(#id = user_id, #num + 1, 1) as row_number,
#id := user_id as tmp
FROM payments AS p,
(SELECT #num := 0) x,
(SELECT #id := 0) y
ORDER BY p.user_id ASC, date DESC)
ON (p.user_id = u.id) and (p.row_number=1)
WHERE u.package = 1
You can try this:
SELECT u.*, p.*
FROM users AS u LEFT JOIN (
SELECT *, ROW_NUMBER() OVER(PARTITION BY userid ORDER BY [Date] DESC) AS RowNo
FROM payments
) AS p ON u.userid = p.userid AND p.RowNo=1
There are two problems with your query:
Every table and subquery needs a name, so you have to name the subquery INNER JOIN (SELECT ...) AS p ON ....
The subquery as you have it only returns one row period, but you actually want one row for each user. For that you need one query to get the max date and then self-join back to get the whole row.
Assuming there are no ties for payments.date, try:
SELECT u.*, p.*
FROM (
SELECT MAX(p.date) AS date, p.user_id
FROM payments AS p
GROUP BY p.user_id
) AS latestP
INNER JOIN users AS u ON latestP.user_id = u.id
INNER JOIN payments AS p ON p.user_id = u.id AND p.date = latestP.date
WHERE u.package = 1
#John Woo's answer helped me solve a similar problem. I've improved upon his answer by setting the correct ordering as well. This has worked for me:
SELECT a.*, c.*
FROM users a
INNER JOIN payments c
ON a.id = c.user_ID
INNER JOIN (
SELECT user_ID, MAX(date) as maxDate FROM
(
SELECT user_ID, date
FROM payments
ORDER BY date DESC
) d
GROUP BY user_ID
) b ON c.user_ID = b.user_ID AND
c.date = b.maxDate
WHERE a.package = 1
I'm not sure how efficient this is, though.
SELECT U.*, V.* FROM users AS U
INNER JOIN (SELECT *
FROM payments
WHERE id IN (
SELECT MAX(id)
FROM payments
GROUP BY user_id
)) AS V ON U.id = V.user_id
This will get it working
Matei Mihai given a simple and efficient solution but it will not work until put a MAX(date) in SELECT part so this query will become:
SELECT u.*, p.*, max(date)
FROM payments p
JOIN users u ON u.id=p.user_id AND u.package = 1
GROUP BY u.id
And order by will not make any difference in grouping but it can order the final result provided by group by. I tried it and it worked for me.
My answer directly inspired from #valex very usefull, if you need several cols in the ORDER BY clause.
SELECT u.*
FROM users AS u
INNER JOIN (
SELECT p.*,
#num := if(#id = user_id, #num + 1, 1) as row_number,
#id := user_id as tmp
FROM (SELECT * FROM payments ORDER BY p.user_id ASC, date DESC) AS p,
(SELECT #num := 0) x,
(SELECT #id := 0) y
)
ON (p.user_id = u.id) and (p.row_number=1)
WHERE u.package = 1
This is quite simple do The inner join and then group by user_id and use max aggregate function in payment_id assuming your table being user and payment query can be
SELECT user.id, max(payment.id)
FROM user INNER JOIN payment ON (user.id = payment.user_id)
GROUP BY user.id
If you do not have to return the payment from the query you can do this with distinct, like:
SELECT DISTINCT u.*
FROM users AS u
INNER JOIN payments AS p ON p.user_id = u.id
This will return only users which have at least one record associated in payment table (because of inner join), and if user have multiple payments, will be returned only once (because of distinct), but the payment itself won't be returned, if you need the payment to be returned from the query, you can use for example subquery as other proposed.

Collecting data from 3 tables into 1 query

I have three different tables in my MySQL database.
table users: (id, score, name)
table teams: (id, title)
table team_Members: (team_id, user_id)
What I would like to do is to have 1 query that finds every team ID a given user ID is member of, along with the following information:
total number of members in that team
the name of the team
users rank within the team (based on score)
EDIT:
Desired output should look like this;
TITLE (of the group) NUM_MEMBERS RANK
------------------------------------------------
Foo bar team 5 2
Another great group 34 17
.
.
.
The query should be based on the users ID.
Help is greatly appreciated
I think this query should get what you ask for
select t.id, t.title, count(m.user_id) members, (
select count(1)
from users u3
inner join team_Members m3 on u3.id = m3.user_id
and m3.team_id = t.id and u3.score > (
select score from users where name = 'Johan'
)
) + 1 score
from teams t
inner join team_Members m on t.id = m.team_id
where t.id in (
select team_id
from team_Members m2
inner join users u2 on m2.user_id = u2.id
where u2.name = 'Johan'
)
group by t.id, t.title
To collect you just need use JOIN
SELECT
u.*, t.*, tm.*
FROM
users u
JOIN
team_Members tm ON u.id = tm.user_id
JOIN
teams t ON t.id = tm.team_id;
To get total of number of that team use COUNT with some group key
Some like that
SELECT
COUNT(t.id), u.*, t.*, tm.*
FROM
users u
JOIN
team_Members tm ON u.id = tm.user_id
JOIN
teams t ON t.id = tm.team_id GROUP BY t.id;
And to rank just:
SELECT
COUNT(t.id) as number_of_members, u.*, t.*, tm.*
FROM
users u
JOIN
team_Members tm ON u.id = tm.user_id
JOIN
teams t ON t.id = tm.team_id
GROUP BY t.id
ORDER BY u.score;