Retrieving data from two tables of mysql - php

I Have Two Tables
Table1
HTNO SUBJECTCODE INTERNALS EXTERNALS TOTAL
1 s1 20 58 78
1 s2 15 20 35
1 s3 10 60 70
2 s1 10 20 30
2 s2 12 30 42
2 s3 15 55 70
.
.
.
so on up to N
Table 2
SUBJECTCODE SUBJECT NAME
s1 MATHS
s2 SCIENCE
s3 SOCIAL
I will be giving a form for student to enter the hallticket Number
If student Enters 1 in form then the result should be
Subjectcode SubjectName Internals Externals Total
s1 Maths 20 58 78
s2 Science 15 20 35
s3 Social 10 60 70
The above should be the output
But Here I am unable to retrieve SubjectName from Table2 in the result
And here is my code which i am using
<?PHP
$userInputEntities = htmlentities($userInput);
echo $userInputEntities;
$username = "admin";
$password = "123456";
$database = "test";
$server = "localhost";
$db = new PDO ("mysql:host=$server;dbname=$database", "$username", "$password");
if ($db) {
$id = $_GET['id'];
$SQL = $db->prepare("SELECT * FROM Table1 WHERE htno = :id");
$SQL -> execute(array(':id'=>$id));
$n = $SQL->rowCount();
echo "
<center><table class='dynamic styled with-prev-next' data-table-tools='{'display':true}' align=center>
<thead>
<tr>
<TH class='table-header dark' scope='col'>SUBJECT CODE</TH>
<TH class='table-header dark' scope='col'>SUBJECT NAME</TH>
<TH class='table-header dark' scope='col'>INTERNALS</TH>
<TH class='table-header dark' scope='col'>EXTERNALS</TH>
<TH class='table-header dark' scope='col'>TOTAL</TH>
</tr></thead><center>";
while ($db_field = $SQL->fetch(PDO::FETCH_ASSOC)) {
echo "<tr><tbody>";
echo "<td align=center>" . $db_field['SubjectCode'] . "</td>";
echo "<td align=center>" . $db_field['Internals'] . "</td>";
echo "<td align=center>" . $db_field['Externals'] . "</td>";
echo "<td align=center>" . $db_field['Total'] . "</td>";
echo "</tbody></tr>";
}
with this code i am unable to get SUbject Name for a particualr subject code of a student
actually i have nt written any code to retrieve dubject name from Table2, I dont Know How to write it
Please Help me

Try this:
$SQL = $db->prepare(
"SELECT T2.Subjectcode, T2.SubjectName, T1.Internals, T1.Externals, T1.Total FROM Table1 as T1
JOIN Table2 as T2
ON T1.SUBJECTCODE = T2.SUBJECTCODE
WHERE T1.HTNO = :id");

You would need to do a join in your query.
MySQL documentation : Join

It looks like you need a SQL statement that will retrieve the resultset you want:
SELECT t1.SubjectCode
, t2.SubjectName
, t1.Internals
, t1.Externals
, t1.Total
FROM Table1 t1
JOIN Table2 t2
ON t2.SubjectCode = t1.SubjectCode
WHERE t1.htno = :id
To have the rows returned in a predictable order, you can include an ORDER BY clause in the query text, following the WHERE clause:
ORDER
BY t1.htno
, t1.SubjectCode
Q: "Before the result was faster but now it is taking much time to display the result - can u tell me y if u know the reason ?"
A: No, I don't have enough information to determine the exact reason for the slow performance of the new statement. But I can give you some likely possibilities.
(I have to tell you though, that I am hesitant to respond to your query, since you have already "selected" an answer to your question.)
The most likely explanation for the slow performance is that you do not have appropriate indexes defined on your tables. And the most likely candidate indexes (for best performance of your query) would be:
... Table2_IX1 ON Table2 (SubjectCode, SubjectName)
and
... Table1_IX1 ON Table1 (htno, SubjectCode, Internals, Externals, Total)
On Table, at a minimum, you want an index that has a leading column of htno, since your query includes an equality predicate (i.e. WHERE htno = 'literal constant'.
And it would be beneficial to have the next column in that same index be SubjectCode, especially if you specify ORDER BY t1.SubjectCode (or ORDER BY t1.htno, t1.SubjectCode) in your query, since MySQL can make use of that index, and bypass a "filesort" operation that would otherwise be required.
If you also include all of the other columns from Table1 that are referenced by your query, then you would have a "covering" index. That means that MySQL can obtain all of the data in needs directly from the index pages, without having to visit the pages of the underlying table.
On Table2, at a minimum, you want an index with a leading column of SubjectCode. That will allow MySQL to use that index to satisfy the join predicate. If that same index also includes theSubjectName` column, then that index would also be a "covering" index for your query, and MySQL could satisfy the query entirely from the index, without a need to visit any pages in the underlying table.
To really evaluate which indexes will give the best performance, you'd need to EXPLAIN your query, and take a look at the access paths. It's likely that the best performance of this query will be obtained when the Extra column in the EXPLAIN output shows "Using index".

Related

PHP Mysql Correctly Iterate Over Tables With Alias Names

I have the following Mysql query:
$sql = "select r.brand AS brand, r.name AS name, r.cost AS cost, e.price AS price, d.shipping as shipping
FROM tab.rawproduct r
INNER JOIN price e ON r.housecode=e.housecode
INNER JOIN product d ON e.productid=d.productid
WHERE r.housecode='$housecode'";
The houscode is assigned to a variable which is then passed to the sql statement:
<label>Housecode:</label><input class="boxes" type="text" name="housecode" value="<?php echo $housecode; ?>"><br />
$housecode = $_POST['housecode'];
Housecode is submitted through a form with action set to $_SERVER[PHP_SELF]
I am trying to iterate over the results with PHP with the following:
$result = $con->query($sql);
if ($result->num_rows >0) {
while($row = mysqli_fetch_array($result)) {
$brand = $row['brand'];
$housecode = $row['housecode'];
$name = $row['name'];
$cost = $row['cost'];
$salesprice = $row['price'];
$shipraw = $row['shipping'];
}
} else {
echo "0 Results";
}
$con->close();
Nothing is getting returned when a user submits a housecode and the "0 Results" is echoed.
I have looked into this problem and read Lucas Knuth's post:
If two or more columns of the result have the same field names, the
last column will take precedence. To access the other column(s) of the
same name, you must use the numeric index of the column or make an
alias for the column. For aliased columns, you cannot access the
contents with the original column name. So, you can either use an AS
in your SQL-query to set other names for the doubled rows or use the
numbered indexes to access them.
So I have used the AS keyword in the above query but I still don't get any results. I have also tried changing to mysqli_fetch_row($result) and tried to assign the $row[0], 1 ... etc instead. Again no luck.
When I run Apache error_log I get the following:
Trying to get property of non-object on line 34. On line 34 and 35 I have:
if ($result->num_rows >0) {
while($row = mysqli_fetch_array($result)) {
Any help would be much appreciated.
Cheers
I have figured out the answer for myself.
The problem was that I was selecting just one database, ie tab.rawproduct BUT tables price e and procduct d are from a totally different database.
So the sql query should have been this:
$sql = "SELECT r.brand, r.name, r.cost, e.price, d.shipping FROM
tab.rawproduct r
INNER JOIN t1.price e on r.housecode=e.housecode
INNER JOIN t1.product d on e.productid=d.productid
WHERE r.housecode = '$housecode' ";
If found the error by checking the mysqli->errno:
if(!$result = $mysqli->query($sql)) {
echo "Error: Our query failed to execute and here is why: \n";
echo "Query: " . $sql . "\n";
echo "Errno: " . $mysqli->errno . "\n";
echo "Error: " . $mysqli->error . "\n";
exit;
}
Hopefully this may help someone else facing the same problem.
Thanks for all your comments and help.
I reproduced your example and I found a bug in your select query: you're missing the r.housecode.
$sql = "select r.brand AS brand, r.name AS name, r.cost AS cost, e.price AS price, d.shipping as shipping, r.housecode AS housecode
FROM tab.rawproduct r
INNER JOIN price e ON r.housecode=e.housecode
INNER JOIN product d ON e.productid=d.productid
WHERE r.housecode='$housecode'";
Check if the cross references match in your tables, because in my examples the rows are correctly returned
table price:
housecode productid price
HT0008 4 3400
HT0008 5 5400
table product:
shipping productid
64 4
78 5
table rawproduct:
brand name cost housecode
Cani bellaaa 63824 HT0008

Querying efficiently

I have two tables: Exam (ExamID, Date, Modality) and CT(ctdivol, ExamID(FK)) with the attributes in brackets.
Note: CT table has about 100 000 entries.
I want to calculate the average of ctdivol in a specific interval of dates.
I have this code that works but is too slow:
function get_CTDIvolAVG($min, $max) {
$values = 0;
$number = 0;
$query = "SELECT (unix_timestamp(date)*1000), examID
from exam use index(dates)
where modality = 'CT'
AND (unix_timestamp(date)*1000) between '" . $min . "' AND '" . $max . "';";
$result = mysql_query($query) or die('Query failed: ' . mysql_error());
while($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
$avg = "SELECT SUM(ctdivol_mGy), count(ctdivol_mGy)
from ct use index(ctd)
where examID ='" . $line["examID"] ."'
AND ctdivol_mGy>0;";
$result1 = mysql_query($avg) or die('Query failed: ' . mysql_error());
while ($ct = mysql_fetch_array($result1, MYSQL_ASSOC)) {
$values = $values + floatval($ct["SUM(ctdivol_mGy)"]);
$number = $number + floatval($ct["count(ctdivol_mGy)"]);
}
}
if ($number!=0) {
echo $values/$number;
}
}
How can I make it faster?
Use EXPLAIN to see the query execution plan.
For that first query, MySQL can't make effective use of a index range scan operation. That expression in the WHERE clause has to be evaluated for every row in the table. We get better performance when we do the comparison to a bare column. Do the manipulation on the literal side... get those values converted to the datatype of the column you're comparing to.
WHERE e.date BETWEEN expr1 AND expr2
For expr1, you need an expression that converts your $min value into a datetime. Just be careful of timezone conversions. I think this might do what you need for expr1:
FROM_UNIXTIME( $min /1000)
Something like:
WHERE e.date BETWEEN FROM_UNIXTIME( $min /1000) AND FROM_UNIXTIME( $max /1000)
Then we should see MySQL able to make effective use of an index with leading column of date. The EXPLAIN output should show range for the access type.
If the number of columns being returned is a small subset, consider a covering index. Then the EXPLAIN will show "Using index", which means the query can be satisfied entirely from the index, with no lookups to pages in the underlying table.
Secondly, avoid running queries multiple times in a loop. It is usually more efficient to run a single query that returns a single resultset, because of the overhead of sending the SQL to the database, that database parsing the SQL text, for valid syntax (keywords in the right places), valid semantics (identifiers reference valid objects), considering possible access paths and determining which is lowest cost, then executing the query plan, obtaining metadata locks, generating the resultset, returning that to the client, and then cleaning up. It's not noticeable for a single statement, but when you start running a lot of statements in a tight loop, it starts to add up. Couple that with an inefficient query, and it starts to get really noticeable.
IF examID column in exam is unique and not null (or its the PRIMARY KEY of exam, then it looks like you could use a single query, like this:
SELECT UNIX_TIMESTAMP(e.date)*1000 AS `date_ts`
, e.examID AS `examID`
, SUM(ct.ctdivol_mGy) AS `SUM(ctdivol_mGy)`
, COUNT(ct.ctdivol_mGy) AS `count(ctdivol_mGy)`
FROM exam e
LEFT
JOIN ct
ON ct.examid = e.examID
AND ct.ctdivol_mGy > 0
WHERE e.modality = 'CT'
AND e.date >= FROM_UNIXTIME( $min /1000)
AND e.date <= FROM_UNIXTIME( $max /1000)
GROUP
BY e.modality
, e.date
, e.examID
ORDER
BY e.modality
, e.date
, e.examID
For best performance of that, you'd want covering indexes:
... ON exam (modality, date, examID)
... ON ct (examID, ctdivol_mGy)
We'd want to see the EXPLAIN output; we'd expect that MySQL could make use of the index on exam to do the GROUP BY (and avoiding a "Using filesort" operation), and also make use of a ref operation on the index to ct.
To reiterate... that query requires that examID be the PRIMARY KEY of the exam table (or at least be guaranteed to be unique and non-null). Otherwise, the result from that can be different than the original code. Absent that gurantee, we could use either an inline view, or subqueries in the SELECT list. But in terms of performance, we don't want to go there without good reason to.
That's just some general ideas, not a hard and fast "this will be faster".
You can write a join on the first table to a subquery table by exam_id:
$query = "SELECT (unix_timestamp(date)*1000) as time_calculation, ed.examID, inner_ct.inner_sum, inner_ct.inner_count "
" FROM exam ed,"
. " ( SELECT SUM(ctdivol_mGy) as inner_sum, count(ctdivol_mGy) as inner_count, examID"
. " FROM ct"
. " WHERE ctdivol_mGy>0 ) inner_ct"
. " WHERE ed.modality = 'CT' AND time_calculation between"
. " '$min' and '$max'"
. " AND ed.examId = inner_ct.examID";
The ( SELECT . . .) inner_ct creates an in memory table you can join from. Useful if you're selecting composed data (sums in your case) across a join.
Conversely, you can use the following syntax:
$query = "SELECT (unix_timestamp(date)*1000) as time_calculation, ed.examID, inner_ct.inner_sum, inner_ct.inner_count "
" FROM exam ed,"
. " LEFT JOIN ( SELECT SUM(ctdivol_mGy) as inner_sum, count(ctdivol_mGy) as inner_count, examID"
. " FROM ct"
. " WHERE ctdivol_mGy>0 ) inner_ct"
. " ON ed.examID = inner_ct.examID"
. " WHERE ed.modality = 'CT' AND time_calculation between"
. " '$min' and '$max'";
You have not provided sample data in the question so we resort to assumptions in an attempt to answer. If there is only one exam row for many rows in ct - but an exam row can exist that has no ct rows at all - then this single query should provide the results required.
SELECT
exam.examID
, (unix_timestamp(exam.date) * 1000
, SUM(ct.ctdivol_mGy)
, COUNT(ct.ctdivol_mGy)
FROM exam
LEFT OUTER JOIN ct on exam.examID = ct.examID AND ct.ctdivol_mGy > 0
WHERE exam.modality = 'CT'
AND exam.date >= #min AND exam.date < #max
GROUP BY
exam.examID
, (unix_timestamp(exam.date) * 1000)
;
Note I am not attempting the PHP code, just concentrating on the SQL. I have used #min and #max to indicate the 2 dates required in the where clause. These should be of the same data type as the column exam.date so do those calculations in PHP before adding into the query string.
I want to calculate the average of ctdivol in a specific interval of
dates.
If you are trying to return a single figure, then this should help:
SELECT
AVG(ct.ctdivol_mGy)
FROM exam
INNER JOIN ct on exam.examID = ct.examID AND ct.ctdivol_mGy > 0
WHERE exam.modality = 'CT'
AND exam.date >= #min AND exam.date < #max
;
Note for this variant we probably don't need a left join (but again due to a lack of sample data and expected result that is an assumption).

Comparing two MySQL tables to populate a dropdown

I'm trying to populate a dropdown menu by comparing two tables, one has a list of supervisor and employee numbers, the other has employee numbers and names. I need to take the numbers for each supervisor and employee and turn them into employee names for the drop down menu, so basically
TABLE payroll_employeelist
Supervisor Employee
1234 3456
1234 2239
1234 123
2910 338
2910 3901
TABLE payroll_users
number name
3456 John Smith
2239 Mary Jane
123 Joe Brown
etc
Supervisors are identified by a session variable callede $usernumber.
What I have so far and is returning one result (just one!) is the following:
if ($loademployees == 1){
echo "<option value=\"base\">---- Employee Name ----</option>";
$query = "SELECT payroll_employeelist.employee, payroll_users.number, payroll_users.name FROM payroll_employeelist WHERE supervisor='$usernumber' LEFT JOIN payroll_users ON payroll_employeelist.employee=payroll_users.number ";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
echo "<option value=\">" . $row{'name'} . "</option>";
}
echo "</select><br>";
}
Can anyone help with this? I get the feeling I've done something funny with the JOIN. It should look like a list of employee names in the dropdown.
UPDATE:
What I have now is:
if ($loademployees == 1){
echo "<option value=\"base\">---- Employee Name ----</option>";
$query = "SELECT payroll_employeelist.supervisor, payroll_employeelist.employee, payroll_users.number, payroll_users.name
FROM payroll_employeelist
INNER JOIN payroll_users
ON payroll_employeelist.employee = payroll_users.number
WHERE supervisor = '$usernumber' ";
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
echo "<option value=\">" . $row['name'] . "</option>";
}
echo "</select><br>";
}
This is successfully returning one of the three records in the test data set, just one, the middle record. The $usernumber is generated internally by the way, no injection possible.
LAST UPDATE- SOLVED
The problem believe it or not was
echo "</select><br>";
it was echoing that before echoing the results of the while loop so it thought the options list was empty. I can't explain the randomly appearing single employee mind you, but it's working now.
You need to join payroll_users twice on table payroll_employeelist since there are two columns that are dependent on it.
SELECT sup.Name SupervisorName,
empName EmployeeName
FROM payroll_employeelist a
INNER JOIN payroll_users sup
ON a.Supervisor = sup.number
INNER JOIN payroll_users emp
ON a.Employee = emp.Number
WHERE sup.Supervisor = '$usernumber'
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
That's probably because you put the join condition inside the WHERE, but you probably meant to have it outside:
SELECT payroll_employeelist.employee, payroll_users.number, payroll_users.name
INNER JOIN payroll_users ON payroll_employeelist.employee=payroll_users.number
FROM payroll_employeelist
WHERE supervisor='$usernumber'
Also, if you use LEFT JOIN you will also get employees that are not attached to any user. A few things about escaping:
$query = "SELECT ... WHERE supervisor='$usernumber' ... ";
That's susceptible to SQL injection if $usernumber comes from a web request; consider using either mysql_real_escape_string() to escape it or switch to PDO / mysqli and use prepared statements instead.
$result = mysql_query($query);
while ($row = mysql_fetch_array($result)) {
echo "<option value=\">" . $row{'name'} . "</option>";
}
You should escape $row['name'] as well, and you shouldn't use curly braces either:
echo "<option value=\">" .
htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8') .
"</option>";
SELECT
tb1.supervisor,
tb1.employee,
tb2.name
FROM
payroll_employeelist AS tb1
INNER JOIN payroll_users AS tb2
ON tb1.employee = tb2.number
As you want exact matches, without non-matching values, you need INNER JOIN instead of LEFT JOIN
Use
SELECT payroll_employeelist.employee, payroll_users.number, payroll_users.name FROM payroll_employeelist LEFT JOIN payroll_users ON payroll_employeelist.employee = payroll_users.number WHERE supervisor = '$usernumber'
instead.
You should look at using PDO for your queries. Since you are dynamically assigning values into your query PDO will be a bit more secure, and if you're running this query multiple times it will be faster with PDO.
As for your query, you have your SQL Clauses ordered incorrectly. Perhaps these links will help:
PDO Tutorial from MySQL
SQL Join Tutorial
you have a mistake in your sintax
please check
$query = "SELECT payroll_employeelist.employee, payroll_users.number, payroll_users.name FROM payroll_employeelist WHERE supervisor='$usernumber' LEFT JOIN payroll_users ON payroll_employeelist.employee=payroll_users.number ";
should be
$query = "SELECT payroll_employeelist.`employee`, payroll_users.`number`, payroll_users.`name` FROM `payroll_employeelist` LEFT JOIN `payroll_users` ON payroll_employeelist.employee` = payroll_users.`number` WHERE `supervisor` = '$usernumber' ";
about this
WHERE `supervisor` = '$usernumber' ";
what table does supervisor is in? you need to fix with prefix payroll_employeelist or payroll_users
documentation here
I would like to also to remember you that mysql_ functions are deprecated so i would advise you to switch to mysqli or PDO for new projects.

MySQL_Query from Multiple Tables with ROUND and Math

I'm trying to make a database of items for the game "EVE Online" for me and my friends to use, and I set up a SQL server and got tables created and the like, etc etc, and everything's running fine. However, I have one issue when I'm trying to import data from two different tables and compare them against each other within the same html table element. It works perfectly if I just import from one table with multiple columns, but I get issues when I try to select more than one source.
The tables I'm pulling from are...
testmetrics.eve_inv_types
and
testmetrics.items_selling
Ideally, I'd like to import the "name", "type_id", "jita_price_sell" columns from table #1, and "price", "type_id", "station_id", and "qty_avail" from table #2.
I'm also using the ROUND operator on jita_price_sell and price to get a 2 decimal approximation for price points of various items. I also have it so that in table #2 only results with the correct station_id will get displayed. But it keeps throwing up an error!
Here is my code so far...
<?php
$con = mysql_connect("testmetrics.db.10198246.xxxx.com","xxxx","xxxx");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("testmetrics", $con);
$result = mysql_query("
SELECT testmetrics.eve_inv_types.name, testmetrics.eve_inv_types.type_id, ROUND(testmetrics.eve_inv_types.jita_price_sell, 2) as jita_price_sell, ROUND(testmetrics.items_selling.price, 2) as price, testmetrics.items_selling.qty_avail, testmetrics.items_selling.sation_id, testmetrics.items_selling.type_id
FROM testmetrics.eve_inv_types, testmetrics.items_selling
WHERE testmetrics.eve_inv_types.type_id = testmetrics.items_selling.type_id, testmetrics.items_selling.station_id = '61000746'");
echo "<table class='sortable'>
<tr>
<th>Item Name</th>
<th>Price (Jita)</th>
<th>Price (K-6K16)</th>
<th>Qty Avail (K-6K16)</th>
</tr>";
while($row = mysql_fetch_array($result))
{
echo "<tr>";
echo "<td>" . $row['testmetrics.eve_inv_types.name'] . "</td>";
echo "<td>" . $row['jita_price_sell'] . "</td>";
echo "<td>" . $row['price'] . "</td>";
echo "<td>" . $row['testmetrics.items_selling.qty_avail'] . "</td>";
echo "</tr>";
}
echo "</table>";
mysql_close($con);
?>
Any help or insight you could give would be greatly appreciated. I'd also like to be able to do a math function where I'd go something like testmetrics.eve_inv_types.jita_price_sell + (testmetrics.eve_inv_types.volume * 300) to get shipping costs and have that exported to it's own column as well.
Anything you have to say is greatly appreciated!
EDIT: I know I'm already asking for alot of help here, but, does anyone know how to limit returns to "top 100" dependent on the column that it's sorted by? I'm using a Javascript addon to be able to sort easily!
This is the code that solved it for me!
SELECT eve_inv_types.name,
eve_inv_types.type_id,
Round(eve_inv_types.jita_price_sell, 2) AS jita_price_sell,
Round(items_selling.price, 2) AS price,
items_selling.qty_avail,
items_selling.type_id
FROM eve_inv_types
JOIN items_selling
ON eve_inv_types.type_id = items_selling.type_id
AND items_selling.station_id = '61000746'
SELECT eit.name,
eit.type_id,
Round(eit.jita_price_sell, 2) AS jita_price_sell,
Round(eis.price, 2) AS price,
eis.qty_avail,
eis.sation_id,
eis.type_id
FROM eve_inv_types eit
JOIN `items_selling` eis
ON eit.type_id = eis.type_id
AND eis.station_id = '61000746'
You can join tables (assuming you have a key that connects them), here's an example:
table A:
personId
firstName
lastName
numOfChildren
table B:
personId
streetName
cityName
countryName
Select from both (using personID as a join key):
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB USING (personId)
If you want to limit the result you can add:
LIMIT 100
And if you want the top 100 parents you can order by numOfChildren:
ORDER BY numOfChildren
Final Query will look like this:
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB USING (personId)
ORDER BY numOfChildren
LIMIT 100;
-- or --
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB ON (tableA.personId=tableB.personId)
ORDER BY numOfChildren
LIMIT 100;
Read more about join here: http://dev.mysql.com/doc/refman/5.1/en/join.html

How would I generate an HTML form based on table data from two different tables using PHP?

I am trying to write a PHP script that will create an HTML form using the “field_definitions” table as a source for input fields and set the default values of each field based on previously stored results from the “user_data” table. (based on the currently logged in user… I have an auth system setup and running using session variables.)
My tables are like so...
users TABLE
user_id user_email user_firstname user_lastname user_password
1 johndoe#mail.com John Doe password
field_definitions TABLE
field_id field_type field_length field_name field_desc field_section
1 text 40 color What is your favorite color? 1
user_data TABLE
response_id user_id field_id user_response
1 1 1 Blue
I’ve created a block of code that returns the rows from my “field_definitions” table and stores them in an array. I’m able to use a foreach loop to generate the form based on each row in the array, but I can’t figure out how to pull-in the second set of information from the other table for the default values.
$dbc = mysqli_connect(sqlhost, sqluser, sqlsecret, sqldb);
$field_definitions_query = "SELECT * FROM field_definitions WHERE field_section = '1'";
$field_definitions_data = mysqli_query($dbc, $field_definitions_query);
$field_definitions = array();
while ($row = mysqli_fetch_array($field_definitions_data)) {
array_push($field_definitions, $row);
}
echo '<form enctype="multipart/form-data" method="post" action="' . $_SERVER['PHP_SELF'] . '">';
foreach ($field_definitions as $row) {
echo '<label for="' . $row[field_name] . '">' . $row[field_desc] . ':</label>';
echo '<input type="' . $row[field_type] . '" id="' . $row[field_name] . '" name="' . $row[field_name]. '" value="temp" /><br />';
}
echo '<input type="submit" value="Save" name="submit" /></form>';
Do I need to create a second array of the other table data, then merge the two in someway?
Is my general approach feasible, or is there a better way?
I am a beginner in PHP and programming in general and would rather not try and conquer any of the frameworks out there; I’m trying to pull this off with my own code for the sake of learning.
Consider using SQL JOIN construction. In case of MySQL it would be something like this:
select t1.*, t2.user_response from field_definitions t1 left join user_data t2 using (field_id) where t2.user_id = %USER_ID% or t2.user_id is null. Then you can fetch data row-by-row to a single array/hash/whatever. See your SQL manual for more details on JOINs.
In short. We are joining tables t1 and t2 by field x. N is NULL (non-existent) record. Ljn is LEFT JOIN, Rjn is RIGHT JOIN, Ijn is INNER JOIN (INNER keyword is frequently ommited) and Fjn is FULL JOIN
t1.x: 1 2 3 4 5 N N
t2.x: N N N 4 5 6 7
Ljn : ^_______^----
Rjn : -----^______^
Ijn : -----^__^----
Fjn : ^___________^
You can check if record is non-existing one by t1.x IS NULL or t1.x IS NOT NULL in where clause.
Hope it will help.

Categories