Inner join 2 tables with same column names - php

I'm working on displaying the achievements from my minecraft server on my website.
But I can't get it to work.
function achievements() {
global $id;
$sql="SELECT * FROM achievements
INNER JOIN stats ON achievements.type=stats.type
INNER JOIN stats ON achievements.block=stats.block
INNER JOIN stats ON achievements.data=stats.data
INNER JOIN stats ON achievements.value=stats.value
WHERE player_id = $id";
$result=mysql_query($sql) or die(mysql_error());
$rows=mysql_fetch_array($result);
}
Will I be able to use $rows['achievements.type']; and $rows['stats.type']; to get the column "type" from the selected table, or is there a another way to do it?
The column and table names are defined by the plugin I use, so the names can't be changed.

the reason why it is not working is because (in my own opinion) the server is a little confused on where how it will handle the columns names properly. In order it to work, add an alias on every table that has the same name that you want to join as well as the columns, eg
SELECT achievements.*,
a.Name as TypeName,
b.Name AS BlockName,
c.Name as DataName,
d.Name AS ValueName
FROM achievements
INNER JOIN stats a ON achievements.type = a.type
INNER JOIN stats b ON achievements.block = b.block
INNER JOIN stats c ON achievements.data = c.data
INNER JOIN stats d ON achievements.value = d.value
WHERE player_id = $id
assuming you want to get the names for every specific columns.

Give the columns you want to have while you SELECT them an alias as example:
SELECT `achievements`.`type` AS `Achieve-Type`
FROM `achievements`
Now you can get the values like this: $rows['Achieve-Type'];

It's easier to alias the table names with...
SELECT * FROM achievements AS ac INNER JOIN stats as st
You could even alias the results if you wish so they are more distinguishable when you select them from $rows

Related

UNION SELECT tables with inner join and GET values with "ALIAS"

So I have 2 tables, Matches and Teams, what I want to do is get some values from the match and Inner join "Teams" to get the names of both teams and add them to a php array later on (getting it all in one sql)
Matches
- IDMatch
- IDLocalTeam
- IDVisitorTeam
- Time
- Half
- Stopped
Teams
- IDTeam
- name
What I have by now is
$query = "SELECT * FROM `Matches`
INNER JOIN `Teams` ON `Matches`.IDLocalTeam = `Teams`.IDTeam
UNION SELECT * FROM `Matches` INNER JOIN `Teams`
ON `Matches`.IDVisitorTeam = `Teams`.IDTeam
ORDER BY IDMatch DESC;";
If someone could help me it would be great! Thanks alot
Wouldn't it be easier to use INNER JOIN twice? It's definitely quicker way of doing joins anyway.
SELECT
*
FROM
`Matches` m
INNER JOIN `Teams` t1
ON m.IDLocalTeam = t1.IDTeam
INNER JOIN `Teams` t2
ON m.IDVisitorTeam = t2.IDTeam
ORDER BY
m.IDMatch DESC;
Also start using aliases instead of table names to identify fields in query, it will SQL much smaller.

Joins from same table

I am trying to join the same table "travel_plan" twice, as the value(s) I need are location_from & location_to in which I can then join the value to my cities table to grab the city name.
SELECT * FROM travel_plan
LEFT JOIN Cities ON Cities.CityID = travel_plan.location_to AS plan_to
LEFT JOIN Cities ON Cities.CityID = travel_plan.location_from AS plan_from
LEFT JOIN user_table ON travel_plan.user_id = user_table.id
ORDER BY date_from DESC LIMIT 0,4") or die(mysql_error());
You need to use table aliases correctly when you're joining the same table more than once, as you're doing with Cities in this query.
SELECT *
FROM travel_plan AS tr
LEFT JOIN Cities AS C1 ON C1.CityID = tr.location_to
LEFT JOIN Cities AS C2 ON C2.CityID = tr.location_from
LEFT JOIN user_table AS us ON tr.user_id = us.id
ORDER BY date_from DESC
LIMIT 0,4
The way you wrote your query, the LEFT JOIN AS clauses were misplaced and not used for qualifying the column names.
This use of SELECT * is really suboptimal, however. From this four-table JOIN, SELECT * kicks back lots of columns with duplicate names, which fouls up _fetch_assoc() methods in php.
Your best bet is to enumerate the columns you fetch, and provide aliases so they don't end up with the same names. I don't know the names of your columns so I have to guess, but it would go something like this.
SELECT us.name, us.id AS userid,
C1.cityname AS to_cityname,
C2.cityname AS from_cityname,
FROM ....
Then you'll find the values in $result['from_cityname'] after you fetch each row.
You misuse the AS keyword, it can be only used in the select part of the query (before FROM), or optionally as alias for table references. But not in the ON part of a join. I guess what you want is:
SELECT *, c1.City as toCity, c2.City as fromCity FROM travel_plan LEFT JOIN Cities c1 ON c1.CityID = travel_plan.location_to LEFT JOIN Cities c2 ON c2.CityID = travel_plan.location_from LEFT JOIN user_table ON travel_plan.user_id = user_table.id ORDER BY date_from DESC LIMIT 0,4
Now you can access the the column aliases toCity and fromCity in your resultset, even though the the original column names are the same.

SQL query to get all rows that have data linked by a FK in another table

I have three tables: Station, MonthlyNormalData and SubArea. I'm trying to get all stations in a sub area that have at least one monthly data tied to it. With the following query, I am able to get all stations in a sub area, but this is disregarding the part about monthly data ($region is a variable containing the region name in my PHP script):
SELECT S.station_id, S.name, SA.sub_area_name
FROM dev.Station AS S
INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id
WHERE sub_area_name = '$region'
I have also tried the following query, but it returns one row for each monthly data associated with a station, which is not really what I am looking for (only looking for something that sends me the names of the stations that have at least one monthly data associated to it, not all rows containing that data):
SELECT S.station_id, S.name, SA.sub_area_name
FROM dev.Station AS S
INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id
INNER JOIN data.MonthlyNormalData as MND ON MND.station_id = S.station_id
WHERE sub_area_name = '$region' AND MND.value IS NOT NULL
What would be the query I would need to run to only have one row per station that have a monthly data associated with it within a certain sub area?
You can just use DISTINCT in your second query to remove duplicated rows:
SELECT DISTINCT ...
Since you are only returning records from the tables Station and SubArea using Distinct will work for you.
SELECT distinct S.station_id, S.name, SA.sub_area_name
FROM dev.Station AS S
INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id
INNER JOIN data.MonthlyNormalData as MND ON MND.station_id = S.station_id
WHERE sub_area_name = '$region' AND MND.value IS NOT NULL
Another way to go about it would be to use exist
SELECT S.station_id, S.name, SA.sub_area_name
FROM dev.Station AS S
INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id
WHERE exists (select 1 from data.MonthlyNormalData where station_id = S.station_id) and
sub_area_name = '$region'

mysql query dont gets all posts

I have a MYSQL query who have to list all post i want it to post. But it dont do it. It shows posts when i have more then one post in the table "meaOrder" with the same "ordCode". But when i have only on post in meaOrder, i don't show it. What can i do?
SELECT koden, wish, rnamn, bild, pris, cname, onsktext
FROM (
SELECT m.wishText as onsktext, m.meaOID as midn, m.ordcode as koden, w.wish as wish, r.meaName as rnamn, r.meaImg as bild,
r.meaPrice as pris, k.catName as cname from cats k, meals r, wishes w,
meaOrder m
join orders c on c.ordNR=4401
WHERE c.ordStatus=1 AND m.ordNR=c.ordNR AND m.meaID=r.meaID AND m.wishesID=w.id
AND r.catID=k.catID
) T
GROUP BY koden, rnamn, bild, pris, cname
ORDER BY midn DESC
TABLE orders
http://grab.by/m74E
TABLE meaOrder http://grab.by/m74Q
Try replacing the JOIN with RIGHT JOIN in this case. The difference is explained at JOIN Syntax page in MySQL docs . In short - JOIN returns row only if there are corresponding rows in both joined tables (inner join). LEFT JOIN / RIGHT JOIN return all rows from one of the tables and corresponding row if it exists from the other table (those are outer joins)
Do you need a subselect?
This seems to cover it:-
SELECT m.ordcode AS koden, w.wish AS wish, r.meaName AS rnamn, r.meaImg AS bild, r.meaPrice AS pris, k.catName AS cname, m.wishText AS onsktext
FROM cats k
INNER JOIN meals r ON r.catID = k.catID
INNER JOIN meaOrder m ON m.meaID = r.meaID
INNER JOIN wishes w ON m.wishesID = w.id
INNER JOIN orders c ON m.ordNR = c.ordNR
WHERE c.ordStatus = 1
AND c.ordNR = 4401
GROUP BY m.ordcode, r.meaName, r.meaImg, r.meaPrice, k.catName
ORDER BY midn DESC

MySQL ISNULL with INNER JOIN

I have 2 tables: "shares" and "pending_share_changes". The "shares" table has the following columns:
share_ID, asset_ID, member_ID, percent_owner, is_approved
pending_share_changes has the following columns:
share_change_ID, asset_ID, member_ID, percent_owner, is_approved, requested_by
I have a form (php) which lists the pending changes which the members have to approve or deny. Everything works fine unless the member has no existing shares, which means there is no record in the "shares" table for them. The query I am using to view the pending share changes is as follows:
SELECT p.share_change_ID, assets.asset_desc, assets.asset_value, shares.percent_owner AS
percent_owner_old, p.percent_owner
FROM pending_share_changes as p
inner join assets on assets.asset_ID = p.asset_ID
inner join shares on shares.asset_ID = p.asset_ID AND shares.member_ID = p.member_ID
INNER JOIN orgs ON orgs.org_ID = assets.org_ID
WHERE orgs.org_ID = '$org_ID' AND p.member_ID = '$member_ID' AND p.is_approved = '0'
I tried using IFNULL(shares.percent_owner, 0) AS percent_owner_old but that didn't work. The query returns no results. I would like to have the percent_owner_old column display a "0" if there is no record in the shares table.
Thanks.
Try changing your join to shares from an INNER JOIN to a LEFT JOIN.
SELECT ....
FROM pending_share_changes p
....
LEFT JOIN shares ON shares.asset_ID = p.asset_ID AND shares.member_ID = p.member_ID
This means "for every member_ID and asset_ID in p, join it to the matching row in shares. If the member_ID/asset_ID exists in p but not shares, make a row anyway and set the corresponding values to NULL".
The INNER JOIN means to only show joined rows where the relevant record exists in both tables.
Then you can combine with the IFNULL(shares.percent_owner,0) AS percent_owner_old.

Categories