Left Join with subquery returns Null - php

I am applying Left Join with Sub query & where clause
It seems fine no syntax error but the columns I am selecting from that sub query always returns me Null. I have executed the same part in my SQL section, it gives me record. Kindly have a look on the query and let me know if any thing is possible or if question is not clear.
SELECT alt.userId, u.name, t.name AS teamName, alt.startDateTime, v.name AS villageName, c.name AS clusterName, startLat, startLong, latlng.lat, latlng.long
FROM activity_log_tim AS alt
JOIN user AS u ON u.userId = alt.userId
JOIN team_members AS tm ON tm.memberId = u.userId
JOIN team AS t ON t.teamId = tm.teamId
JOIN village AS v ON v.villageId = alt.villageId
JOIN cluster_villages AS cv ON cv.villageId = v.villageId
JOIN cluster AS c ON c.clusterId = cv.clusterId
LEFT JOIN (SELECT lat, long,dateTime, scheduleId FROM activity_log_gps LIMIT 1) AS latlng ON latlng.scheduleId = alt.scheduleId
WHERE DATE(alt.startDateTime) = '2015-09-05' AND DATE(alt.endDateTime) = '0000-00-00' GROUP BY alt.userId ORDER BY latlng.dateTime DESC

Well it's supposed to since you are performing a LEFT JOIN which produces NULL if no match occurs. So either you can perform a INNER JOIN or use a COALESCE function like below
SELECT alt.userId, u.name,
t.name AS teamName,
alt.startDateTime,
v.name AS
villageName,
c.name AS clusterName,
startLat,
startLong,
COALESCE(latlng.lat, 23), //Notice the use of COALESCE. If null will return 23 as default
COALESCE(latlng.long, 32)

Related

how to use INNER JOIN and IN Clause in same query

i have three tables and want to run INNER JOIN and IN clause on them.
can anyone tell me where i am doing wrong
SELECT `tblinvoices`.id,`tblinvoices`.userid,`firstname`,`lastname`
FROM `tblinvoices`
WHERE `paymentmethod`IN
(SELECT `gateway` FROM `tblpaymentgateways` WHERE `setting`='type' AND `value` = 'CC')
INNER JOIN `tblclients` ON `tblinvoices`.userid=`tblclients`.id"
JOIN comes before WHERE:
SELECT tblinvoices.id,
tblinvoices.userid,
firstname,
lastname
FROM
tblinvoices
INNER JOIN tblclients
ON tblinvoices.userid = tblclients.id
WHERE
paymentmethod IN
(select gateway
FROM tblpaymentgateways
WHERE setting='type'
AND value = 'CC')

Trying to JOIN an empty table nothing returns

I have a problem trying to JOIN an empty table (comments table) to my existing prepared statement.
This is working perfectly:
// prepare images
if ($stmt = $mysqli->prepare(" SELECT uu.*, m.*,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID AND t.user_id = ?
) AS user_likes,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID
) AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
ORDER BY up_time DESC")) {
$stmt->bind_param('i', $user_id);
$stmt->execute(); // get imgs
// foreach print images
// working as expected
}
And I don't know why if I JOIN another table (img_comments) that is empty, the images are not printed... if I add a row to the table and refresh the page, one image is printed...
The statement that I'm trying and it's not working is this:
SELECT uu.*, m.*, ic.*,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID AND t.user_id = ?
) AS user_likes,
(
SELECT COUNT(*)
FROM img_likes AS t
WHERE t.img_id = uu.imgID
) AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
INNER JOIN img_comments AS ic ON ic.img_id = uu.imgID
ORDER BY up_time DESC
Why is only printing images based on the number of the table rows?? I also tried LEFT JOIN but I'm not too familiareize with this. I only use INNER JOIN in other scripts and I never had a problem like this.
I would appreciate any optimization to my query.
What does an inner join do? It joins all records of table a with all matching records of table b. So when there are no records in table b, there is no match for any record of table a, hence no result at all. Why does this surprise you?
A left join is an outer join (short for LEFT OUTER JOIN). It means: Give me all records of table a with all matching records of table b, and when there is no match then give me the record of table a anyhow. This seems to be what you are wanting here. But you say you tried it. I don't see how this would fail in your query.
A typical error for an outer join not to work would be to have some field of b in your where clause (e.g. where b.id > 100). As the outer-joined records have no matching b record, all b fields are null, so that such a where clause would fail. You'd just get matches again, just like with the inner join.
EDIT: As to optimization, you can get the two counts in one pass by counting conditionally:
SELECT
uu.*, m.*, ic.*,
il.count_user AS user_likes,
il.count_total AS total_likes
FROM user_uploads AS uu
INNER JOIN members AS m ON m.id = uu.user_id
LEFT OUTER JOIN img_comments AS ic ON ic.img_id = uu.imgID
LEFT OUTER JOIN
(
select
img_id,
count(*) as count_total,
count(case when t.user_id = ? then 1 end) as count_user
from img_likes
group by img_id
) AS il ON il.img_id = uu.imgID
ORDER BY uu.up_time DESC;
As far as I know, INNER JOIN will only retrieve data which have both data. So if let say the table that you join have no data with that join condition. It will not return any data at all.
LEFT JOIN is just a normal join. It will retrieve data on both table. But if the joined table is empty, then only the primary table will have data, the secondary table will have null as its data.
You can just modify your code, replacing INNER JOIN with LEFT JOIN and see if it works/

mysql join return 0 for one column with other columns intact

I wish to join multiple tables like- Categories, menus, restaurants, reviews, etc.
to return the restaurants that provide the inserted food with their prices.
Everything works except numberOfReviews in reviews table.
If a restaurant has no reviews then output should be 0 for numOfReviews column but other column values should be retrieved i.e. price, name, etc.
With following query I get all fields as null and count(numReviews) as 0:
select r.id
,r.`Name`
,r.`Address`
,r.city
,r.`Rating`
,r.`Latitude`
,a.`AreaName`
,m.`Price`
,count(rv.id)
from `categories` c, `menus` m, `restaurants` r, areas a, reviews rv
where m.`ItemName`="tiramisu"
and c.`restaurant_id`=r.`id`
and m.`category_id`=c.id
and r.`AreaId`=a.`AreaId`
and if I can't match rv.restaurant_id=r.id in where clause(obviously).
Where am I getting wrong? How do I solve this?
edited
select r.id,
r.`Name`,
r.`Address`,
r.city,
r.`Rating`,
r.`Latitude`,
a.`AreaName`,
m.`Price`,
r.`Longitude`,
r.Veg_NonVeg,
count(rv.id)
from restaurants r LEFT JOIN `reviews` rv on rv.`restaurant_id`=r.`id`
inner join `categories` c on c.`restaurant_id` = r.id
inner join `menus` m on m.`category_id` = c.id
inner join `areas` a on a.`AreaId` = r.`AreaId`
where m.`ItemName`="tiramisu"
First of all, don't use this old school syntax for the jointures.
Here is a query that may solve your problem:
SELECT R.id
,R.Name
,R.Address
,R.city
,R.Rating
,R.Latitude
,R.Longitude
,A.AreaName
,M.Price
,R.Veg_NonVeg
,COUNT(RV.id) AS numOfReviews
FROM restaurants R
INNER JOIN categories C ON C.restaurant_id = R.id
INNER JOIN menus M ON M.category_id = C.id
INNER JOIN areas A ON A.AreaId = R.AreaId
LEFT JOIN reviews RV ON RV.restaurant_id = R.id
WHERE M.ItemName = 'tiramisu'
GROUP BY R.id, R.Name, R.Address, R.city, R.Rating, R.Latitude, R.Longitude, A.AreaName, M.Price, R.Veg_NonVeg
I used explicit INNER JOIN syntax instead of your old school syntax and I modified the jointure with table reviews in order to get the expected result. The GROUP BY clause is required to use the aggregate function COUNT, every rows will be grouped by the enumerated columns (every column except the one used by the function).
Here is another solution that simplify the GROUP BY clause and allow the modification of SELECT statement without having to worry about the fact that every columns need to be part of the GROUP BY clause:
SELECT R.id
,R.Name
,R.Address
,R.city
,R.Rating
,R.Latitude
,R.Longitude
,A.AreaName
,M.Price
,R.Veg_NonVeg
,NR.numOfReviews
FROM restaurants R
INNER JOIN (SELECT R2.id
,COUNT(RV.id) AS numOfReviews
FROM restaurants R2
LEFT OUTER JOIN reviews RV ON RV.restaurant_id = R2.id
GROUP BY R2.id) NR ON NR.id = R.id
INNER JOIN categories C ON C.restaurant_id = R.id
INNER JOIN menus M ON M.category_id = C.id
INNER JOIN areas A ON A.AreaId = R.AreaId
WHERE M.ItemName = 'tiramisu'
As you can see here I added a new jointure on a simple subquery that does the aggregation job in order to provide me the expected number of reviews for each restaurant.
Hope this will help you.

Loading details from multiple tables

I was using this:
SELECT res.*, rac.*, u.*, t.*, c.*
FROM Results res
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
INNER JOIN Cars c USING (CarID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
Which works fine, but I've since realised I need to have CarID added in to Results table, but when I add it in, it gives me the error that the field is ambiguous. What I'd like to do is get the Car name from Cars table where CarID joins Cars and Results. When I try to do this though:
SELECT res.*, rac.*, u.*, t.*, c.*
FROM Results res
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
INNER JOIN Cars c USING (res.CarID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
I get the following error:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '.CarID) WHERE res.SeasonNumber = '1' AND res.LeagueID = '1' AND
Position = '1' ' at line 6
You can replace your USING clause with ON(),in USING() clause i guess you add the columns name that are same in other table you are joining but you placed the join in last and using alias res mysql won't allow this
INNER JOIN Cars c ON(res.CarID =c.CarID)
If you need to use USING() clause you need to adjust the join placements like
SELECT res.*, rac.*, u.*, t.*, c.*
FROM
Cars c
INNER JOIN Results res USING (CarID)
INNER JOIN Races rac USING (RaceID)
INNER JOIN Users u USING (UserID)
INNER JOIN Teams t USING (TeamID)
WHERE res.SeasonNumber = '$SeasonNumber' AND res.LeagueID = '$LeagueID' AND Position = '1' AND ResultConfirmed = '1'
ORDER BY Position ASC
But ON() clause is more readable form

MySQL Join returning ALL data from left table and whatever is found in right table

Brain bad. Something isn't clicking that I know is probably simple. I'm trying my best to avoid a subquery but it may be unavoidable.
There are 11 records in the left table [cards_types] and between 1 and 11 records in the right table [users_cards]. I need to return all records from the left table and whatever is found in the right table. The only caveat to the right table is doing some IF / ELSE statements to return 0 values if it card_types.id is not found in users_cards. Also, there is a foreign key constraint on cards_types.id => users_cards.type_id (if it matters).
Query
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
IF (c.mtg_id IS NULL, 0, c.mtg_id) AS mtg_id,
IF (c.label IS NULL, 0, c.label ) AS card_label,
IF (uc.points IS NULL, 0, uc.points ) AS card_score
FROM cards_types t
JOIN users_cards uc
ON uc.type_id = t.id
JOIN cards c
ON c.id = uc.card_id
WHERE uc.user_id = 1
AND uc.season_id = 1
ORDER BY t.priority ASC
You are currently using an INNER JOIN, change it to a LEFT JOIN. I also moved your WHERE clause filters to the JOIN so you will return all rows from cards_type. If you leave the filters in the WHERE clause, then it will act like an INNER JOIN:
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1 -- < -- move the where filters here
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC
try with left join like that
SELECT
t.id,
t.slug,
t.label AS type_label,
t.points AS point_value,
COALESCE(c.mtg_id, 0) AS mtg_id,
COALESCE(c.label, 0) AS card_label,
COALESCE(uc.points, 0) AS card_score
FROM cards_types t
LEFT JOIN users_cards uc
ON uc.type_id = t.id
AND uc.user_id = 1
AND uc.season_id = 1
LEFT JOIN cards c
ON c.id = uc.card_id
ORDER BY t.priority ASC

Categories