MySQL selection using LEFT JOIN - php

I am trying to join two tables and select from 'railstp'. I have simplified the tables.
Table 'railstp' looks like below
count startdate startlocation atoc
1 2013-09-28 lester a
2 2013-09-28 nottm a
3 2013-09-20 lester a
4 2013-09-28 birm a
Table 'location' looks like below
count startlocation goodlocation
1 lester Leicester
2 nottm Nottingham
I am trying to get the 'proper' (goodlocation) description from the table 'location' to replace the abbreviated description (startlocation) and also SELECT all the locations with a startdate of 2013-09-28. If there is not a 'proper' description it would be great if I just show the abbreviated description
So the result I am looking to achieve is
2013-09-28 Leicester a
2013-09-28 Nottingham a
2013-09-28 birm a
My code is as below:-
require('connect_db.php');
mysqli_select_db($mysql_link,"Timetable");
function show_records($mysql_link)
{
$q="SELECT railstp.startdate,railstp.startlocation,railstp.atoc,location.startlocation,location.goodlocation
FROM railstp
LEFT JOIN location
ON railstp.startlocation=location.startlocation
WHERE railstp.startdate='2013-09-28'
ORDER BY startdate";
$r=mysqli_query($mysql_link,$q);
if ($r)
{
echo "<Table id='customers'>
<tr>
<th>From</th>
<th>Departing</th>
<th>ATOC</th>
</tr>";
while ($row=mysqli_fetch_array($r,MYSQLI_ASSOC))
{
echo "<tr>";
echo "<td>".$row['startdate']."</td>";
echo "<td>".$row['startlocation']."</td>";
echo "<td>".$row['atoc']."</td>";
echo "</tr>";
}
echo "</Table>";
}
else {echo '<p>'.mysqli_error($mysql_link).'</p>' ;}
}
show_records($mysql_link);
mysqli_close($mysql_link);
The selection does not show the 'Proper' (goodlocation) description - ie it should show Nottingham instead of nottm and Leicester instead of lester
Thank you for your help

You can use the SQL-function COALESCE() for that.
This function uses the first non-null value in its arguments.
SELECT railstp.startdate,
COALESCE(location.goodlocation, railstp.startlocation) as startloc,
railstp.atoc
FROM railstp
LEFT JOIN location
ON railstp.startlocation=location.startlocation
WHERE railstp.startdate='2013-09-28'
ORDER BY startdate
So here, if location.goodlocation is NULL, railstp.startlocation is used.
See SQL-fiddle.
UPDATE
If you want to add an endlocation, you can join the location table again.
I'll point out that, in order to make things a bit easier, I've added table aliases to distinguish between the different tables.
SELECT r.startdate,
COALESCE(l1.goodlocation, r.startlocation) as startloc,
COALESCE(l2.goodlocation, r.endlocation) as endloc,
r.atoc
FROM railstp r
LEFT JOIN location l1
ON r.startlocation = l1.startlocation
LEFT JOIN location l2
ON r.endlocation = l2.startlocation
WHERE r.startdate='2013-09-28'
ORDER BY r.startdate
This, off course, if the location table is used for both start and end locations.

You have two columns with the same name in your query. There is no way to tell which one you want in the php code, so the first is chosen. Use as to rename one of them:
SELECT rs.startdate, rs.startlocation as shortstartlocation, rs.atoc,
coalesce(l.startlocation, rs.startlocation) as startlocation,
l.goodlocation
FROM railstp rs LEFT JOIN
location l
ON rs.startlocation = l.startlocation
WHERE rs.startdate = '2013-09-28'
ORDER BY startdate

Related

The Mysql INNER JOIN fetch same data repeatly

I try to design a web that keep track the match history of students.
tablegame has 4 column: player 1, player2 ,player 3 and player4. All of them are represented as ids in tablegame.(each game has a maximum of 4 player)
The column player1 player2 always store the IDs who win this game, and column player 3 player4 always store IDs who lose this game.
Tableplayer store basic information about the student.
However, as I fetch associated array from the $AimStudentHistoryWin. Data get repeatly fetched.
THE web actually shows me this:
================
GAMEID 15
================
GAMEID 16
================
GAMEID 15
================
GAMEID 16
================
GAMEID: 15
================
GAMEID 16
BUT I expect the web to only show me
================ GAMEID 15
================ GAMEID 16
How could I Fix that?
echo "<br><br> <center><h2>match history:</h2> <br>";
$Aimstudenthistorywin=$conn ->query( "SELECT tablegame.*,tableplayer.Name FROM tablegame INNER JOIN tableplayer ON tablegame.player1 ='$studentid' OR tablegame.player2 ='$studentid'");
$Aimstudenthistoryloss=$conn ->query("SELECT tablegame.*,tableplayer.Name FROM tablegame INNER JOIN tableplayer ON tablegame.player3 ='$studentid'OR tablegame.player4 ='$studentid'" );
$Num=0;
While($row2= $Aimstudenthistorywin ->fetch_assoc()){
echo "<br>================<br><i style ='color:blue;'><h3>WIN</h3></i>";
echo "<br>Game".$Num;
$Num++;
echo "<br>".$row2['GameID'].":<br>".$row2['Name'];
}while($row2 = $Aimstudenthistoryloss -> fetch_assoc()){
echo "<br>================<br><i style ='color:red;'><h3>Lose</h3></i>";
echo "<br>Game".$Num;
$Num++;
echo "<h3>StudentName:".$TempStudentArray[$row2['player1']]."</h3><br>Game Date:".$row2['Date']."<br><br>"."----------------<br>Player1:".$TempStudentArray[$row2['player1']]."|||||||"."Player2:".$TempStudentArray[$row2['player2']]."<br><br>vs<br><br>Player3:".$TempStudentArray[$row2['player3']]."|||||||| Player4".$TempStudentArray[$row2['player4']]."<br>-------" ;
}
echo"</center>"
Ok it is solved.
instead of using
"SELECT tablegame.*,tableplayer.Name FROM tablegame INNER JOIN tableplayer ON tablegame.player1 ='$studentid' OR tablegame.player2 ='$studentid'");
We can just add more conditions into this. Eventhough I don't know why it works but it works
"SELECT tablegame.*,tableplayer.Name FROM tablegame INNER JOIN tableplayer ON (tableplayer.StudentID = tablegame.player1 OR tableplayer.StudentID = tablegame.player2) AND (tablegame.player1 ='$studentid' OR tablegame.player2 ='$studentid')");
Your duplicates come from your join's ON clause, which basically acts as if it was a WHERE clause.
To fix it, you can properly JOIN both tables (using a column of each), and then selecting only those involving your specific student (in the WHERE clause):
SELECT tablegame.*,tableplayer.Name
FROM tablegame
INNER JOIN tableplayer
ON tablegame.player1 = tableplayer.StudentID
OR tablegame.player2 = tableplayer.StudentID
WHERE tableplayer.StudentID = [the id of your student]
This request will avoid duplicates (assuming a student can't be player 1 and 2 at the same time)
And while at it, I would suggest always using prepared statements, to avoid potential SQL injections.

Count from selection and access both tables with joins

I stumbled upon a query that I have never done until now.
Before asking the question I looked for if another user had had the same need as me but nothing.
My goal is very simple:
having two tables:
collaboratori (collaborators)
invite (invitations)
I have to count how many invitations the collaborators have made.
table structure of collaboratori:
ID_Collaboratori | cod_manager
37 4675
150 6675
3 6575
table structure of inviti:
invite_id | invite_code_manager
37 6675
39 6575
40 4675
41 6675
if I execute the join obviously I access the two tables in this way:
$q_stats_prod_manager = $connessione->prepare("
SELECT * FROM invite
LEFT JOIN collaboratori
ON collaboratori.cod_manager = invite.invite_code_manager ");
$q_stats_prod_manager->execute();
$r_stats_prod_manager = $q_stats_prod_manager->get_result();
my need lies in showing in a table:
show me for each manager who has his cod_manager inside the inviti table, the number of times he sent them.
Name Surname Manager 1 | Number of invite: 200
Name Surname Manager 2 | Number of invite: 50
Name Surname Manager 3 | Number of invite: 10
not limiting myself to just one counter but also being able to access other table values ​​like any join
I take the liberty of putting the answer that was partially written by another user, adding a detail and explanation for future users. The resolution query for this case is the same:
$q_stats_prod_manager = $connessione->prepare("
SELECT count(invite.invite_id)
/*name of what you want to call the result you will see in the while*/
AS result_count, /*you can call this value whatever you want*/
/*Start | Values ​​of the tables you are interested in selecting*/
collaboratori.nome,
collaboratori.data_registrazione,
invite.invite_code_manager
/*End | Values ​​of the tables you are interested in selecting*/
FROM collaboratori
LEFT JOIN invite
ON invite.invite_code_manager = collaboratori.cod_manager group by invite.invite_code_manager
");
$q_stats_prod_manager->execute();
$r_stats_prod_manager = $q_stats_prod_manager->get_result();
$count_invite_manager=mysqli_fetch_array($r_stats_prod_manager);
$number_of_invite_manager = $count_invite_manager[0];
Select the id of the table you want to count
Give a name you wish you want to name the counted result
Select the values ​​of the tables on which you will perform the join you want to view
Join the tables
Show the result with while
Code while:
<?php while($rowstatspm = mysqli_fetch_assoc($r_stats_prod_manager)){ ?>
<!-- this is the fancy name you associated with your query when you wrote: AS nameofwhatyouwant -->
<?php echo $rowstatspm['result_count'] ;?>
<?php } ?>
You seem to want aggregation. I assume you want all rows for collaboratori, so that should be the first table for the LEFT JOIN:
SELECT c.cod_manager, COUNT(i.invite_code_manager)
FROM collaboratori c LEFT JOIN
invite i
ON c.cod_manager = i.invite_code_manager
GROUP BY c.cod_manager;
Your question doesn't describe where the name comes from. But those fields should be in both the SELECT and GROUP BY.
SELECT count(invite.invite_id),collaboratori.name FROM collaboratori
LEFT JOIN invite
ON invite.invite_code_manager = collaboratori.cod_manager group by invite.invite_code_manager

How to use group by statement on multiple fields in sql?

I have the following tables:
StudentProfile in which I have fields RollNumber, Major
StudentEnrollment in which I have fields RollNumber, CourseCode, Section, Semester
DepartmentFees in which I have fields DepartmentName, Semester, Fees
What I'm trying to do it to find the fees a student has to pay in a particular semester. The problem is the StudentEnrollment table has multiple repeated values which is making it difficult to find the exact fees.
My StudentEnrollment table is like this:
RollNO |CourseCode |Section |Semester
-----------+---------------+------------+------------
ST-0001 |BIOL 300 |A |Fall 2018
ST-0001 |BIOL 500 |A |Spring 2018
ST-0001 |BIOL 450 |B |Spring 2018
ST-0001 |BIOL 475 |A |Spring 2018
ST-0002 |CHEM 500 |A |Spring 2018
ST-0002 |CHEM 450 |B |Spring 2019
Now with repeated values of roll number and Semester how do I get the correct answer.
If I use GROUP BY (StudentEnrollment.RollNo) , the roll number does not repeat I cant get all the semesters the student has attended and if I use GROUP BY (StudentEnrollment.RollNo) I dont get all the student's rollnumbers in the semsester.
Initially I tried using
Select
a.RollNo,
b.Semester,
c.Fees
FROM StudentProfile a
LEFT JOIN StudentEnrollment b ON b.RollNo = c.RollNo
LEFT JOIN DepartmentFees C ON c.DepartmentName = a.Major //AND maybe join semester?
But it doesn't seem to work. What can I try next?
Just add the columns to the Group by clause:
Select
a.RollNo,
b.Semester,
sum(c.Fees) AS 'total'
FROM StudentProfile a
LEFT JOIN StudentEnrollment b ON b.RollNo = c.RollNo
LEFT JOIN DepartmentFees C ON c.DepartmentName = a.Major //AND maybe join semester?
GROUP BY
a.RollNo,
b.Semester
Since you have mention b.Semester, c.Fees in select statement, so to do group by RollNo and Semester, add a.RollNo and b.Semester in GROUP BY clause, I have used "JOIN" instead of "LEFT JOIN" cause use JOIN/INNER JOIN when you want to return only records having pair on both sides, and you’ll use LEFT JOIN when you need all records from the “left” table, no matter if they have pair in the “right” table or not.
Select
a.RollNo,
b.Semester,
sum(c.Fees) AS 'total'
FROM StudentProfile a
JOIN StudentEnrollment b ON b.RollNo = c.RollNo
JOIN DepartmentFees C ON c.DepartmentName = a.Major
GROUP BY
a.RollNo,
b.Semester

Echo data from two different mysql tables using php

I'm trying to display data from two different mysql tables on my website using php.
My aim is to display a match schedule with information from two tables. The first one includes all the teams plus their ID, the second includes all details on the games. I now want to "replace" the "home_id" and "away_id" fields with the respective team names from the first table.
The tables look as follows:
table "teams"
id name
-----------
1 Team 1
2 Team 2
3 Team 3
4 Team 4
...
table "matchschedule"
id home_id away_id goals_home goals_away date
1 1 2 0 2 2016-05-05
2 3 4 2 1 2016-05-06
...
With the following query I'm getting the required data within phpmyadmin:
SELECT
date, home.name, sp.goals_home, away.name, sp.goals_away
FROM
matchschedule sp
INNER JOIN
teams home on sp.home = home.id
LEFT JOIN
teams away on sp.away = away.id
However, when I implement this query into my website and add the code below to display the data the fields "home.name" and "away.name" are always empty. What do I need to change in order to get the team names displayed?
while($row = mysql_fetch_array($query)) {
?>
<table border=1>
<tr>
<?php
echo "<td>".$row['date']."</td>";
echo "<td>".$row['home.name']."</td>";
echo "<td>".$row['goals_home']."</td>";
echo "<td>".$row['away.name']."</td>";
echo "<td>".$row['goals_away']."</td>";
?>
</tr>
</table>
Final result (with missing info for both team names):
2016-05-05 [] 0 [] 2
2016-05-06 [] 2 [] 1
The issue is that when in query you request home.name mysql return to php column with title name and you can not reach that column using home.name anymore. And same for away.name.
That's why you need to set proper name for returned columns.
Change your query to:
SELECT
date, home.name home_name, sp.goals_home, away.name away_name, sp.goals_away
FROM
matchschedule sp
INNER JOIN
teams home on sp.home = home.id
LEFT JOIN
teams away on sp.away = away.id
and call those columns in php like:
echo "<td>".$row['date']."</td>";
echo "<td>".$row['home_name']."</td>";
echo "<td>".$row['goals_home']."</td>";
echo "<td>".$row['away_name']."</td>";
echo "<td>".$row['goals_away']."</td>";
Based on your table strcture, you should do the following :
SELECT
date, home.name AS homeName, sp.goals_home, away.name AS awayName, sp.goals_away
FROM
matchschedule sp
INNER JOIN
teams home on sp.home_id = home.id
LEFT JOIN
teams away on sp.away_id = away.id
So basically replace sp.home by sp.home_id and sp.away by sp.away_id and change the fields name as you have the same fields name in your tables.

Unexpected results from SQL Query using GROUP_CONCAT

I'm having an issue with an sql query and I'm not sure what I am doing wrong. Anyways let me explain:
Initially this was the original query:
SELECT cl.*,
c.id,c.type,
c.firstname,
c.surname,
c.job,
c.company,
c.directorycompany_id,
dc.id, dc.name,
es.id FROM contactlist_contact cl
INNER JOIN contact c ON cl.contact_id = c.id
LEFT JOIN directorycompany dc ON dc.id = c.directorycompany_id
LEFT JOIN expertsection es ON es.id = c.expertsection_id
WHERE cl.contactlist_id = 36311
ORDER BY dc.surname
The statement fetches all of the details from the contactlist table where the id is X. The information it returns is a row for each contact in the contactlist table along with information on the company (directorycompany) they work for and various other details about the contact from the contact table. So the information looks something like this:
contactlist_id contact_id id active id type firstname surname job company directorycompany_id id name id
36311 1939 316955375 1 1939 directory Joe Bloggs Deputy Editor 786 786 Herald People 0
36311 1935 316955374 1 1935 directory Jim Bloggs Advertising Manager 786 786 Herald People 0
36311 28034 316955373 1 28034 directory Jay Bloggs News Reporter 786 786 Herald People 0
I then went and attempted to modify the above SQL as additional functionality was required but I've been seeing unwanted results. Basically I am trying to JOIN 3 other tables
directorycolumn
directorysupplement
directoryprogramme
The idea being that it would return all of the columns, supplements and programmes that the contact in the contactlist has also written. Also to point out, in some cases a contact may have written more than 1 column, supplement or programme and as a result I ideally wanted to display this in the same row as the contact as opposed to duplicating the rows so I used the GROUP_CONCAT() function.
This is the modified SQL
SELECT cl.*,
c.id,
c.type,
c.firstname,
c.surname,
c.job,
c.company,
c.directorycompany_id,
dc.id, dc.name,
es.id,
GROUP_CONCAT(dirc.name) AS gcname,
GROUP_CONCAT(dirp.name) AS gpname,
GROUP_CONCAT(dirs.name) AS gsname
FROM contactlist_contact cl
INNER JOIN contact c ON cl.contact_id = c.id
LEFT JOIN directorycompany dc ON dc.id = c.directorycompany_id
LEFT JOIN expertsection es ON es.id = c.expertsection_id
LEFT JOIN directorycolumn dirc ON dirc.directorycontact_id = c.id
LEFT JOIN directoryprogramme dirp ON dirp.directorycontact_id = c.id
LEFT JOIN directorysupplement dirs ON dirs.directorycontact_id = c.id
WHERE cl.contactlist_id = 36311
ORDER BY dc.surname
This returns:
contactlist_id contact_id id active id type firstname surname job company directorycompany_id id name id gcname gpname gsname
36311 28034 316955373 1 28034 directory Jay Bloggs News Reporter 786 786 Herald People 0 The Arts Scene,Farming \N \N
So my question is, where have the other 2 results gone and why are they not showing? And also why is the information in gcname being displayed for this contact when in fact it is related to the contact with the id 1939
if you remove GROUP_CONCAT it would display correct records, because when you use this function you should have GROUP BY clause. Currently it will consider all records as a single group.
If you look values in gcname is multiple, which is correct.
Group_concat is part of mysql aggregate functions. That means it will group all equal values together into one row, in your case all three columns have the same value, thats why you only get one as result. what result would you expect using group_concat?

Categories