Fetch data from two SQL tables with INNER JOIN, display HTML table - php

I am trying to display a table which will print out a list of themes I am creating for a forum software (there are several dozen), and display their version number from another table, by using an INNER JOIN statement.
Here's the HTML table I want to print:
Theme Name Version Number
-------------------------------
Elegance 1.7.0
Smarty 1.7.4
Aria 1.8.1
etc etc
The themes and their IDs are stored in xf_style table:
--------------------------------
style_id | title
--------------------------------
1 | Elegance
2 | Smarty
3 | Aria
The theme version numbers are stored in the options table xf_style_property. There's hundreds of options in the backend system, each with an option ID (style_property_id). The "Theme Version" option I'm looking for has ID of "5145".
xf_style_property table
---------------------------------------------------------------------
style_id | style_property_id | property_label | property_value
---------------------------------------------------------------------
1 | 5144 | Logo Size | 110px
2 | 5144 | Logo Size | 145px
3 | 5144 | Logo Size | 120px
1 | 5145 | Theme Version | 1.7.0
2 | 5145 | Theme Version | 1.7.4
3 | 5145 | Theme Version | 1.8.1
There are many repeating values in this table. Basically I want to fetch the property_value for each theme where the style_property_id equals 5145, and inner join this with the xf_style table.
My full script:
<?php
$servername = "localhost";
$username = "***";
$password = "***";
$dbname = "***";
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
$sql = "SELECT xf_style.title, xf_style_property.property_value FROM xf_style_property WHERE property_definition_id = 5145, INNER JOIN xf_style ON xf_style_property.style_id=xf_style.style_id";
$result = $conn->query($sql) or die($conn->error);
?>
<table border="2" style= "background-color: #84ed86; color: #761a9b; margin: 0 auto;" >
<thead>
<tr>
<th>Theme Name</th>
<th>Theme Version</th>
</tr>
</thead>
<tbody>
<?php
while ($row = $result->fetch_assoc()) {
echo "<tr><td>" . $row['title'] . "</td><td>" . $row['property_value'] . "</td></tr>";
}
?>
</tbody>
</table>
I've been trying a dozen different tweaks including this guide:
https://www.w3schools.com/sql/sql_join.asp
and other guides here at SE and can't seem to make it work. Any help would be appreciated from a SQL newbie.
Disclaimer: the property_label column doesn't actually exist.. I only wrote it in for reader understanding. It's already known from another table which ID represents what option label.

The where conditions are after the join
This should fix it
$sql = "SELECT xf_style.title, xf_style_property.property_value FROM xf_style_property INNER JOIN xf_style ON xf_style_property.style_id=xf_style.style_id" WHERE property_definition_id = 5145,;
Otherwise if you want to avoid repeated themes (even if they ahve diferent propety value) you can use Group By

Your query should simply be
SELECT xfs.title, xfsp.property_value
FROM xf_style_property xfsp
INNER JOIN xf_style xfs ON xfsp.style_id = xfs.style_id
WHERE xfsp.style_property_id = 5145

Related

How to print for each primary key all the foreign keys column related to it?

I want to solve a PHP issue
I have a db with 2 tables:
first one is "document":
id | title |
================================
1 | equations |
2 | great |
3 | painting |
second one is "pic":
id | doc_id | description
===============================================
1 | 1 | "mathematics"
2 | 1 | "physic"
3 | 2 | "literature"
4 | 2 | "art"
the "doc_id" is a foreign key, related to the id of the table "document"
this is my question: I'm trying to print for each title, all the descriptions related to it, example:
for the title "equations" , the foreign key related to it, is "doc_id =1"
which means for "equations" I will print "mathematics" and "physic"
the final table printed using PHP and SQL, on my browser, should be:
| title | description
===============================================
| equations | mathematics, physic
| great | literature , art
| painting |
Here's my code:
<?php
$servername = "localhost";
$username = "root";
$password = "root";
$dbname = "doc-pic";
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
// Check connection
$sql = "SELECT * FROM pic LEFT JOIN document ON pic.doc_id=document.id";
$result = mysqli_query($conn, $sql);
$sql1 = "SELECT title from document";
$result1 = mysqli_query($conn, $sql1);
?>
<table>
<?php
if (mysqli_num_rows($result1) > 0)
while($row = mysqli_fetch_array($result1)){?>
<tr>
<td><?php echo $row["title"]; ?></td>
</tr>
<?php if (mysqli_num_rows($result) > 0 )
while($row = mysqli_fetch_array($result)){
?>
<tr>
<td><?php echo $row["doc_id"]; ?></td>
<td><?php echo $row["description"]; ?></td>
</td>
</tr>
</td>
<?php }
} ?>
Use left join and aggregation:
select d.*,
group_concat(p.description order by p.id) as full_description
from documents d left join
pic p
on p.doc_id = d.id
group by d.id;
Note that this uses group by d.id along with select d.*. This works because d.id is (presumably) the primary key of documents.

Selecting and displaying date from two tables using JOIN and an associative ID

I have a list of employees in one MySQL table, and a list of assignments in another.
The employees list contains these 4 fields:
+––––––––––––––––––––––––––––––––––––––––––––––
| userid | emp_name | emp_email | emp_role |
–––––––––––––––––––––––––––––––––––––––––––––––
| 4 | Jane | emp#emp.com | admin |
–––––––––––––––––––––––––––––––––––––––––––––––
| 5 | John | emp2#emp.com | guest |
–––––––––––––––––––––––––––––––––––––––––––––––
and in the assignments table, I have a list of jobs
+–––––––––––––––––––––––––––––––––––––––––––––––––––
| userid | job_name | job_numb | due_date |
––––––––––––––––––––––––––––––––––––––––––––––––––––
| 4 | Job1 | 012221200000 | 01/21/2017 |
––––––––––––––––––––––––––––––––––––––––––––––––––––
| 5 | Job2 | 012221200001 | 01/24/2017 |
––––––––––––––––––––––––––––––––––––––––––––––––––––
What I would like is to have all the information from both tables be accessible for data. What I initially wrote is:
<?php
$conn = mysqli_connect($servername, $username, $password, $dbname);
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
$sql = "SELECT * FROM assignments JOIN employees";
$results = mysqli_query($conn, $sql);
?>
Then in a loop:
<table>
<?php
foreach ($results as $result){
$userid = $result['userid'];
$emp_name = $result['emp_name'];
$emp_email = $result['emp_email'];
$emp_role = $result['emp_role'];
$job_name = $result['job_name'];
$job_numb = $result['job_numb'];
$due_date = $result['due_date'];
<tr>
<td><?php echo $emp_name;?></td>
<td><?php echo $emp_email;?></td>
<td><?php echo $emp_role;?></td>
<td><?php echo $job_name;?></td>
<td><?php echo $job_numb;?></td>
<td><?php echo $due_date;?></td>
?>
<?php
}
?>
</table>
Of course, this just outputs everything. I am having trouble understanding how to relate the data from table 1 to table 2 so what I get is the email and name of the employee associated with that job. Is there a way to have a conditional in the foreach statement?
You are forgetting the JOIN condition (a.userid = e.userid) as far as I can see. Without this condition in the WHERE clause of your SQL statement, you will get a cross product of all tuples from both tables.
Try the following statement:
SELECT * FROM assignments a JOIN employees e WHERE a.userid = e.userid;
Note that for the sake of conciseness, I have introduced aliases for the two tables.
A simple JOIN without any ON condition is like doing the cartesian product of two tables. You need to use ON as a join condition in your query. So your query should be like this:
$sql = "SELECT * FROM assignments JOIN employees ON employees.userid = assignments.userid";

Php/Mysql count dancers from each moment added issue

I have a dance contest site and each user can login and add dance moments,
in my html table with all moments from all users i have all the data but i want in a html column to add "number of dancers for each moment added by the logged user id".
I have this:
$c = mysql_query("SELECT * FROM moments");
$dancers = 0;
while($rows = mysql_fetch_array($c)){
for($i = 1; $i <= 24; $i++){
$dan_id = 'dancer'.$i;
if($rows[$dan_id] != "" || $rows[$dan_id] != null )
$dancers++;
}
}
echo "<th class="tg-amwm">NR of dancers</th>";
echo "<td class='tg-yw4l'>$dancers</td>";
phpMyAdmin moments table: has id, clubname, category, discipline, section, and this:
But this process is count all the dancers names from all users moments.
Example for this process: You have a total of 200 dancers !
I want the process to count for me all dancers names for each moment added in the form not a total of all entire users moments, something like this: if user john has two moments added: Moment 1: 5 dancers - moment 2: 10 dancers, and so on for each user.
Let me try to put you in the right way (it seems a long post but I think it's worth the beginners to read it!).
You have been told in the comments to normalize your database, and if I were you and if you want your project to work well for a long time... I'd do it.
There are many MySQL normalization tutorials, and you can google it your self if you are interested... I'm just going to help you with your particular example and I'm sure you will understand it.
Basically, you have to create different tables to store "different concepts", and then join it when you query the database.
In this case, I would create these tables:
categories, dance_clubs, users and dancers store "basic" data.
moments and moment_dancers store foreign keys to create relations between the data.
Let's see the content to understand it better.
mysql> select * from categories;
+----+---------------+
| id | name |
+----+---------------+
| 1 | Hip-hop/dance |
+----+---------------+
mysql> select * from dance_clubs;
+----+---------------+
| id | name |
+----+---------------+
| 1 | dance academy |
+----+---------------+
mysql> select * from users;
+----+-------+
| id | name |
+----+-------+
| 1 | alex |
+----+-------+
mysql> select * from dancers;
+----+-------+
| id | name |
+----+-------+
| 1 | alex |
| 2 | dan |
| 3 | mihai |
+----+-------+
mysql> select * from moments;
+----+--------------+---------------+-------------------+
| id | main_user_id | dance_club_id | dance_category_id |
+----+--------------+---------------+-------------------+
| 1 | 1 | 1 | 1 |
+----+--------------+---------------+-------------------+
(user alex) (dance acad..) (Hip-hop/dance)
mysql> select * from moment_dancers;
+----+-----------+-----------+
| id | moment_id | dancer_id |
+----+-----------+-----------+
| 1 | 1 | 1 | (moment 1, dancer alex)
| 2 | 1 | 2 | (moment 1, dancer dan)
| 3 | 1 | 3 | (moment 1, dancer mihai)
+----+-----------+-----------+
Ok! Now we want to make some queries from PHP.
We will use prepared statements instead of mysql_* queries as they said in the comments aswell.
The concept of prepared statement can be a bit hard to understand at first. Just read closely the code and look for some tutorials again ;)
Easy example to list the dancers (just to understand it):
// Your connection settings
$connData = ["localhost", "user", "pass", "dancers"];
$conn = new mysqli($connData[0], $connData[1], $connData[2], $connData[3]);
$conn->set_charset("utf8");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Here we explain MySQL which will be the query
$stmt = $conn->prepare("select * from dancers");
// Here we explain PHP which variables will store the values of the two columns (row by row)
$stmt->bind_result($dancerId, $dancerName);
// Here we execute the query and store the result
$stmt->execute();
$stmt->store_result();
// Here we store the results of each row in our two PHP variables
while($stmt->fetch()){
// Now we can do whatever we want (store in array, echo, etc)
echo "<p>$dancerId - $dancerName</p>";
}
$stmt->close();
$conn->close();
Result in the browser:
Good! Now something a bit harder! List the moments:
// Your connection settings
$connData = ["localhost", "user", "pass", "dancers"];
$conn = new mysqli($connData[0], $connData[1], $connData[2], $connData[3]);
$conn->set_charset("utf8");
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// Query to read the "moments", but we have their main user and dancers in other tables
$stmtMoments = $conn->prepare("
select
moments.id,
(select name from users where users.id = moments.main_user_id) as main_user,
(select name from dance_clubs where dance_clubs.id = moments.dance_club_id) as dance_club,
(select name from categories where categories.id = moments.dance_category_id) as dance_category,
(select count(*) from moment_dancers where moment_dancers.moment_id = moments.id) as number_of_dancers
from moments
");
// Five columns, five variables... you know ;)
$stmtMoments->bind_result($momentId, $momentMainUser, $momentDanceClub, $momentDanceCategory, $momentNumberOfDancers);
// Query to read the dancers of the "moment" with id $momentId
$stmtDancers = $conn->prepare("
select
dancers.name as dancer_name
from
dancers join moment_dancers on dancers.id = moment_dancers.dancer_id
where
moment_dancers.moment_id = ?
");
$stmtDancers->bind_param("i", $momentId);
$stmtDancers->bind_result($momentDancerName);
// Executing the "moments" query
$stmtMoments->execute();
$stmtMoments->store_result();
// We will enter once to the while because we have only one "moment" right now
while($stmtMoments->fetch()){
// Do whatever you want with $momentId, $momentMainUser, $momentDanceClub, $momentDanceCategory, $momentNumberOfDancers
// For example:
echo "<h3>Moment $momentId</h3>";
echo "<p>Main user: $momentMainUser</p>";
echo "<p>Dance club: $momentDanceClub</p>";
echo "<p>Category: $momentDanceCategory</p>";
echo "<p>Number of dancers: $momentNumberOfDancers</p>";
echo "<p><strong>Dancers</strong>: ";
// Now, for this moment, we look for its dancers
$stmtDancers->execute();
$stmtDancers->store_result();
while($stmtDancers->fetch()){
// Do whatever you want with each $momentDancerName
// For example, echo it:
echo $momentDancerName . " ";
}
echo "</p>";
echo "<hr>";
}
$stmtUsers->close();
$stmtMoments->close();
$conn->close();
Result in browser:
And that's all! Please ask me if you have any question!
(I could post the DDL code to create the database of the example with the content data if you want)
Edited: added dancers table. Renamed moment_users to moment_dancers. Changed functionality to adapt the script to new tables and names.

Getting entries from database where there are more than one entry in a corresponding database with a shared ID (prepared statement)

this is going to be a bit complicated. But I'll try to explain what I'm trying to do.
I've got a table in a database as follows:
Table - Entries
ID | User | Address | Workflow | Audit Date |
1 | Tim | 123 | 10 p/w | 22/2/2013 |
2 | Bob | 222 | 20 p/w | 22/2/2013 |
Now in a corresponding table i have pictures:
Table - Pictures
ID | JobNo | User | ImagePath | ImageName |
52 | 1 | Tim | /1.jpg | /2.jpg |
53 | 1 | Tim | /3.jpg | /4.jpg |
Now Pictures.Jobno corresponds to Entries.ID
Alright so what I'm after, is to list all entries from table Entries when the related jobNo has more than 2 image entries. if it has 1 or less, I want to ignore the listing.
So at the moment I can call entries like this through php:
function getAllEntries() {
$mysqli = new mysqli(DB_SERVER, DB_USER, DB_PASSWORD, DB_NAME);
if (!($query = $mysqli->prepare("SELECT * FROM Entries
ORDER BY Date DESC"))) {
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
if (!$query->execute()) {
echo "Execute failed: (" . $query->errno . ") " . $query->error;
}
$query->bind_result($ID, $User, $Address, $Workflow, $Audit);
while ($query->fetch()) {
//Echo each entry here
}
$query->close();
$mysqli->close();
}
My issue is, how do I then incorporate what I want to do? I want to say:
Select all entries, where in table Pictures there are 2 or more images corresponding to the job number/id comparison in the Entries table.
I'm sure this doable. But I can't think of the sql statement or how to bind it in a prepared statement correctly
SELECT * FROM Entries, Pictures, Where Pictures.Jobno = ID.Entries AND (row amount in pictures) >= 2.
Or something? Is this just an SQL problem? Or do I need an if statement and to run a separate SQL query.
I'm self taught with php and sql I'm afraid - so I don't quite know how to resolve this myself.
The way to handle this is typically by joining against a subquery which retrieves the number of Pictures per JobNo and filtering those >= 2 in the HAVING clause:
SELECT
entries.*,
numpics
FROM entries
LEFT JOIN (
/* Subquery joined returns aggregate COUNT() in pictures per JobNo */
SELECT JobNo, COUNT(*) AS numpics FROM pictures GROUP BY JobNo
) pcounts ON entries.ID = pcounts.JobNo
HAVING numpics >= 2
http://sqlfiddle.com/#!2/347f4/8
Because of MySQL's lenient treatment of the GROUP BY, you can probably get away with just a LEFT JOIN, against pictures without the subquery:
/* MySQL Only */
SELECT entries.*
FROM
entries
LEFT JOIN pictures ON entries.ID = Pictures.JobNo
GROUP BY entries.ID
HAVING COUNT(pictures.JobNo) >= 2

Is this relation can be possible(phpmyadmin)

Is it possible to do this??
table1 has a column name 'id'
table2 has a column name 'id' too.
because table2 accepts multiple value from selected checkbox, and I want to relate it with table1. table1 contains the firstname lastname and etc. while table2 contains selected value from the checkbox (1 or more selected).
table1
id | firstname | lastname
1 | John | Conner
table2
id | sports
1 | basketball
2 | volleyball
3 | tennis
john selected 3 values from the checkboxes...
how can I relate or make it that the first inserted data will own the 3 values or will be displayed like this:
id | firstname | lastname | sports
1 | John | Conner | basketball
| volleyball -------->
| tennis------------->
thanks in advance...
sorry for the illustrations.
To do that, you'll need a Many to Many relationship.
You'll need a third table that keeps the relationships between the other two.
You need 3rd table that connects users to sports.
connections
--------------------------
id | users_id | sports_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
--------------------------
The above table would connect user #1 to sports #1 and #2, user #2 to sport #1. (I renamed the tables from your question to make my example more readable: table1 -> users and table2 -> sports)
To combine the records using this method, you can call
SELECT users.firstname, users.lastname, sports.sports
FROM connections
JOIN users ON connections.users_id = users.id
JOIN sports ON connections.sports_id = sports.id
This also ables you to show users that have selected specific sport from the list. This way you can also edit sports name once to affect all results at the same time.
Good examples of JOIN, OUTER JOIN and LEFT JOIN on w3schools
Working example using PHP/MySQLi
$db = new mysqli('localhost', 'user', 'pass', 'database'); // Database connection
if ($db->connect_errno > 0) { // Do we have a connection?
die('Unable to connect to database [' . $db->connect_error . ']');
}
// Set the sql query
$sql = "SELECT users.firstname, users.lastname, sports.sports
FROM connections
JOIN users ON connections.users_id = users.id
JOIN sports ON connections.sports_id = sports.id";
if (! ($result = $db->query($sql))) { // Run the query, get results to $result, if errors die
die('There was an error running the query [' . $db->error . ']');
}
while (($row = $result->fetch_assoc())) { // Loop through the results and echo
echo $row['firstname'] . ' ' . $row['lastname'] . ' likes ' . $row['sports'] . '<br />';
// To see all $row variables in nice format we can do: echo '<pre>' . print_r($row, true) . '</pre>';
}
I added Kyle Reese as user id #2, so the output from my query results would be:
John Conner likes basketball
John Conner likes volleyball
Kyle Reese likes basketball
Read more about MySQLi (php.net)
Example adapted from 'MySQLi for Beginners' (codular.com)

Categories