MySQL SELECT to subquery a many-to-many relationship - php

I have a bilingual dictionary database that I've created, and the tables are set up like so:
lemma (lemmaID, lemma, meaning)
collocate (collocateID, lemmaID, collocate, notes, connection)
collusage (usageID, lemmaID_u, collocateID_u, japanese, english, englishalt)
partofspeech (posID, partofspeech)
postolemma (lemmaID_p, posID_p)
So far, I have a query that returns tables for the results, and it works just how I'd like it to. (It looks like this)
$q = 'SELECT *
FROM lemma, collocates, collusage
WHERE lemma.lemmaID = collocates.lemmaID AND lemma.lemmaID = collusage.lemmaID_u AND collusage.collocateID_u = collocates.collocateID
ORDER BY lemma.lemmaID;';
$result = mysqli_query($con, $q) or die(mysql_error());
if (!$result || mysqli_num_rows($result) == 0) {
echo 'No rows found';
exit;
}
$lastCatID = 0;
while ($row = mysqli_fetch_assoc($result)) {
$reading = $row['reading'];
$headword = $row['lemma'];
$collocate = $row['collocate'];
if (isset($row['notes'])) {
$notes = '('.$row['notes'].')';
} else {
$notes = $row['notes'];
}
$japanese = $row['japanese'];
$english = $row['english'];
if (isset($row['englishalt'])) {
$englishalt = ', '.$row['englishalt'].'';
} else {
$englishalt = $row['englishalt'];
}
if ($lastCatID != $row['lemmaID']) {
//starting a new category
if ($lastCatID != 0) {
//close up previous table
echo ' </tbody>
</table> </div>';
}
//start a new div
echo '<div class="entry">
<h4>'.$reading.'【'.$headword.'】 <span class="pos">'.$WANT TO LIST PARTS OF SPEECH HERE.'</span></h4>
<table class="table table-striped table-hover">
<tbody>';
$lastCatID = $row['lemmaID'];
}
echo '<tr>
<td><span>'.$collocate.'</span><span class="notes">'.$notes.'</span></td>
<td>'.$japanese.'</td>
<td>'.$english.''.$englishalt.'</td>
</tr>';
}
if ($lastCatID != 0) {
//close up the final table
echo ' </tbody>
</table></div>';
}
mysqli_free_result($result);
What I can't figure out how to do is to use the postolemma junction table to get all of the partofspeech values for each lemmaID so I can list them next to the lemma in the table. Everything SELECT query I have done so far has duplicated collocation entries, which I don't want. Any help is appreciated!
Edit: Here is a link to the SQL Fiddle with data. I couldn't get my foreign key constraints to work so just that is missing.

if I understand you correctly you want to select all values from table partofspeech based on lemma table. Your query should look like this:
SELECT part.partofspeech
FROM partofspeech part
INNER JOIN postolemma post
ON part.posID = post.posID_p
INNER JOIN lemma l
ON post.lemmaID_p = l.lemmaID
Also I would suggest you to change the query you use and start using JOIN operator in syntax, it's good practice and it's not hard to switch from one to another... So your query:
SELECT *
FROM lemma, collocates, collusage
WHERE lemma.lemmaID = collocates.lemmaID
AND lemma.lemmaID = collusage.lemmaID_u
AND collusage.collocateID_u = collocates.collocateID
ORDER BY lemma.lemmaID;
Will look like this:
SELECT *
FROM lemma
INNER JOIN collocates
ON lemma.lemmaID = collocates.lemmaID
INNER JOIN collusage
ON collusage.collocateID_u = collocates.collocateID
AND lemma.lemmaID = collusage.lemmaID_u
ORDER BY lemma.lemmaID;
Also you can use aliases for table in you query like i do in first query I wrote here. It will make your life easier because you don't need to type whole name of table over and over...
GL!
P.S. also it's good to post your desired result in you question and provide SQL Fiddle with some data for our better understanding of your queston...
EDIT
After we consulted in the comments we come to this solution:
SELECT *
FROM lemma
INNER JOIN collocates
ON lemma.lemmaID = collocates.lemmaID
INNER JOIN collusage
ON collusage.collocateID_u = collocates.collocateID
AND lemma.lemmaID = collusage.lemmaID_u
INNER JOIN (SELECT post.lemmaID_p AS lemmaID, group_concat(part.partofspeech SEPARATOR ', ') AS partofspeach
FROM partofspeech part
INNER JOIN postolemma post
ON part.posID = post.posID_p
INNER JOIN lemma l
ON post.lemmaID_p = l.lemmaID
GROUP BY post.lemmaID_p) tmp
ON lemma.lemmaID = tmp.lemmaID
ORDER BY lemma.lemmaID;
Here is SQL Fiddle for that...

Related

Why does one of my column shows empty?

I have my table that one of my column shows empty. It has the column of Id, Date, Cust name, Product + Qty, and amount. But only in Product + Qty shows empty even it has data in database.
PHP code
<?php
include('connect.php');
$start = isset($_GET['d1']) ? $_GET['d1'] : '';
$end = isset($_GET['d2']) ? $_GET['d2'] : '';
if(isset($_GET['submit']) && $_GET['submit']=='Search')
{
$result = mysql_query(
"SELECT
t1.qty,
t2.lastname,
t2.firstname,
t2.date,
t3.name,
t2.reservation_id,
t2.payable FROM prodinventory AS t1
INNER JOIN reservation AS t2
ON t1.confirmation=t2.confirmation
INNER JOIN products AS t3
ON t1.room=t3.id
WHERE str_to_date(t2.date, '%d/%m/%Y') BETWEEN
str_to_date('$start', '%d/%m/%Y') AND
str_to_date('$end', '%d/%m/%Y')
GROUP BY t2.confirmation") or die(mysql_error());
while ($row = mysql_fetch_array($result)){
echo'<tr class="record">';
echo '<td>'.$row['reservation_id'].'</td>';
echo '<td>'.$row['date'].'</td>';
echo '<td>'.$row['firstname'].' '.$row['lastname'].'</td>';
echo '<td><div align="left">';
$rrr=$row['confirmation'];
$results = mysql_query("SELECT * FROM prodinventory where confirmation='$rrr'");
while($row1 = mysql_fetch_array($results))
{
$roomid=$row1['room'];
$resulta = mysql_query("SELECT * FROM products where id='$roomid'");
while($rowa = mysql_fetch_array($resulta))
{
echo $rowa['name'].' x';
}
echo ' '.$row1['qty'].'<br>';
}
echo '<td>'.'PHP ' . number_format(floatval($row['payable']));
}
?>
Hmmmm I have deleted my answer but noone tried so...
I think this echo ' '.$row1['qty'].'<br>'; is the row you asked about. And all this looks like a typo. If this is the case:
You have no confirmation in the SELECT clause (it's used only in JOIN and GROUP BY) and it possible your $rrr to be blank. Echo it to be sure there is a value.
Check does your query works and return results. Echo the query string (or take it from the mysql log file) and test it.
You have SELECT *. Is the field name 'qty' correct in a case-sensivity environment? 'Qty' may be different and the query may work but you don't get the result.
i think that's because you have inner join and maybe the intersection tables have no data
try to do left join first if it works
insure that all of tables have data in it

php foreach in foreach in foreach

This is a hypothetical question. If I have 3 arrays from 3 separate sql db queries that all relate to another. For example...
//db
schools
id | school_name
classes
id | class_name | school_id
students
id | student_name | class_id
And I want to display everything in a huge list like this...
//php
foreach(schools as school){
echo '<h1>' . $school->school_name . '<h1>';
foreach(classes as class){
if($class->school_id == $school->id){
echo '<h2>' . $class->class_name . '<h2>';
foreach(students as student){
if($student->class_id == $class->id){
echo '<h3>' . $student->student_name . '<h3>';
}
}
}
}
}
I have to make 3 database calls. Is there a way to grab all this information in a single db query? Like maybe an array in an array in an array and then somehow loop through? Or is this the best way to do this?
You can do a join which will allow you to have 1 for each. Are you wanting everything or any sort of filter ?
You can join those table, to get one big array with flattened data. When looping through this data, you can check if the id of the previous record still matches the id of the current record. If not, you can output a new header. It is important, though, that the resultset is properly sorted for this.
SELECT
s.id AS school_id,
s.school_name,
c.id AS class_id,
c.class_name,
st.id AS student_id,
st.student_name
FROM
schools s
INNER JOIN classes c ON c.school_id = s.id
INNER JOIN students st ON st.class_id = c.id
ORDER BY
s.id,
c.id,
st.id
If you have it all in a flattened structure, you can even make it into a nested array structure again something like this:
foreach ($resultset as $row)
{
$schools[$row->school_id]->school_name =
$row->school_name;
$schools[$row->school_id]->classes[$row->class_id]->class_name =
$row->class_name;
$schools[$row->school_id]->classes[$row->class_id]->students[$row->student_id]->student_name =
$row->student_name;
}
var_dump($schools);
After that, you can still use the nested for loops to process the array, but it will be in a more efficient way, since the data is already sorted out: classes are already added to the school they belong to, and student are already added to the right class.
<?php
try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=school", "username");
} catch (PDOException $e) {
echo "PDO Connection failed: " . $e->getMessage();
exit(1);
}
$sql = <<<SQL
SELECT schools.school_name, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
SQL;
$result = $pdo->query($sql);
if ($result == false) {
die("query failed?!");
}
$school = "";
$class = "";
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
if ($school != $row['school_name']) {
$school = $row['school_name'];
echo "\nSchool: $school\n\n";
}
if ($class != $row['class_name']) {
$class = $row['class_name'];
echo " Class: $class\n\n";
echo " Student list:\n";
}
echo " {$row['student_name']}\n";
}
$res = mysql_query('SELECT school_name, class_name, student_name, sc.id AS scid, c.id AS cid, st.id AS stid FROM schools sc LEFT JOIN classes c ON (sc.id = c.school_id) LEFT JOIN students st ON (c.id = st.class_id) ');
$arr = array();
while ($v = mysql_fetch_assoc($res)) {
$arr[$v['school_name']][$v['class_name']][$v['stid']] = $v['student_name'];
}
print_r($arr);
You could do it all in one SQL query that might look something like:
SELECT schools.schoolname, classes.class_name, students.student_name
FROM
schools INNER JOIN classes ON (schools.id = classes.school_id)
INNER JOIN students ON (classes.id = students.class_id)
ORDER BY 1, 2;
Then you could walk the result set in one loop, but you'd probably want to add some logic to only display the school name and class name once for each time it changes.

Using PHP to get data from multiple database tables

I am trying to query five tables. I am able to query one of the tables with
$query = "SELECT * FROM Stats_player WHERE player='$user'";
However, when I try to query another table with
$query = "SELECT * FROM Stats_player, Stats_block WHERE player='$user'";
the website breaks. Here is the code I am using to echo the data on the screen
<?php
if ($result = $mysqli->query($query)) {
echo "<img src=\"https://minotar.net/avatar/{$user}/100\"><h1>{$user}</h1><br/>";
while ($row = $result->fetch_assoc()) {
//variables
$play_time = $row['playtime']/3600;
$play_time = round($play_time, 1);
$xpgained = $row['xpgained'];
$damagetaken = $row['damagetaken'];
$toolsbroken = $row['toolsbroken'];
$itemscrafted = $row['itemscrafted'];
$itemseaten = $row['omnomnom'];
$commandsused = $row['commandsdone'];
$teleports = $row['teleports'];
$itemspickedup = $row['itempickups'];
$itemsdroped = $row['itemdrops'];
$lastseen = date("F j, Y ", strtotime($row['lastjoin']));
//end of variables
echo "<p>Time on Server: {$play_time} HRS</p>";
echo "<p>Last Seen: {$lastseen}";
echo "<p>Commands Used: {$commandsused}";
echo "<p>XP Gained: {$xpgained}";
echo "<p>Blocks broken: {$row['blockID']}"; //this is data from the table Stats_block
}
$result->free();
}
$mysqli->close();
?>
Any ideas on how I might do this?
Table structor of Stats_player:
| counter | player | Playtime |
Stats_block is:
| counter | player | blockID |
$query = "SELECT * FROM Stats_player, Stats_block WHERE player='$user'"
That's very likely wrong. You should use a JOIN operator.
Here, you are just doing a cartesian products of the two tables, that's hardly what you want. And that may overrun your resource (memory etc.) if the tables have a lot of rows.
Something like
$query = "SELECT * FROM Stats_player p, Stats_block b
WHERE p.block_id = b.id AND p.player='$user'"
or
$query = "SELECT * FROM Stats_player p INNER JOIN Stats_block b ON p.block_id = b.id
WHERE p.player='$user'"
or maybe LEFT OUTER JOIN...
The exact query will depend on your schema.
Without seeing the structure of both tables, something like this could work.
SELECT columnList
FROM Stats_player a
LEFT JOIN Stats_block b ON b.player = a.player
WHERE a.player = '$user'
Have you tried something like this:
SELECT
table1.field1, table1.field2, table2.field1, table2.field2
FROM
table1, table2
WHERE
table1.field1 = " " and table2.field1 = " ";

Join MySQL Table then filter result as column name

here is my code i am using to fetch mysql result from 4 different tables
SELECT DISTINCT c.title as CourseTitle, t.title as TopicTitle, l.title as LessonTitle, r.title as ResourceTitle, r.location, r.type, r.duration
FROM j17_lessons l, j17_topics t, j17_courses c, j17_resources r
WHERE
CONCAT(c.title, t.title, l.title, r.title, r.type, r.location) LIKE '%Fatih%'
AND c.id = t.course_id
AND l.topic_id = t.id
AND r.lesson_id = l.id
ORDER BY c.title, t.id, l.id, r.id;
Here is screen shot of my fetch result
http://i40.tinypic.com/2v1w0ib.png
Now what i need is to create a HTML Tables for each 'CourseTitle' in database.
Using SQL statement and PHP Code i can get result for first query but i need a second query to split table foreach 'CourseTitle'
/* connect to the db */
$connection = mysql_connect('localhost','root','123');
mysql_select_db('alhudapk',$connection);
/* show tables */
$result = mysql_query('SELECT DISTINCT c.title as CourseTitle, t.title as TopicTitle, l.title as LessonTitle, r.title as ResourceTitle, r.location, r.type, r.duration
FROM j17_lessons l, j17_topics t, j17_courses c, j17_resources r
WHERE
CONCAT(c.title, t.title, l.title, r.title, r.type, r.location) LIKE '%Taleem%'
AND c.id = t.course_id
AND l.topic_id = t.id
AND r.lesson_id = l.id
ORDER BY c.title, t.id, l.id, r.id',$connection) or die('cannot show tables');
while($tableName = mysql_fetch_row($result)) {
$table = $tableName[0];
echo '<h3>',$table,'</h3>';
$result2 = mysql_query('SELECT '.$table . 'AS' .$table);
if(mysql_num_rows($result2)) {
Please guide me to build a correct and better code
What I would do is put the database results into a big array structure with the data arranged in the same sort of order it should be printed out. This makes maintaining the code a bit easier.
// run the query as you did in the question
$courses = array();
// use mysql_fetch_assoc as it makes the code clearer
while($row = mysql_fetch_assoc($result)) {
$ct = $row['CourseTitle'];
// Found a new Course Title? If so create an array to put the data rows in
if(!isset($courses[$ct]))
$courses[$ct] = array();
// add this row to the end of its course array
$courses[$ct][] = $row;
}
// now print the results out
foreach($courses as $title =>$course) {
echo "<h3>$title</h3>";
echo "<table>";
foreach($course as $line) {
echo "<tr><td>" . $line['TopicTitle'] . "</td><td>"
. $line['LessonTitle'] . "</td></tr>";
echo "</table>";
}
The code above is only printing out the first 2 columns
, but if you can get it to work you should be able to add the rest quite easily.
add:
GROUP BY c.title
to the end of your SQL statement.

MySQL use inner join in PHP

I have 2 tables, the unique id's in each table are the same in both tables.
How do I go about joining the data from both tables together in php?
When I normally pull data I do it like this:
$get_board_array = mysql_query("SELECT * FROM posts WHERE user_id_to = '$id' ");
while($posts = mysql_fetch_array($get_board_array))
{
$post_id = $get_post['post_id'];
$html_output .= "<p>".$post_id."</p>";
}
As for pulling the data from separate tables and not getting it all mixed up, I was thinking of doing something like this:
$get_arrayA = mysql_query("SELECT * FROM tableA WHERE age = '36' ");
while($dataA = mysql_fetch_array($get_arrayA))
{
$dataA_id = $dataA['id'];
$dataA_firstName = $dataA['FirstName'];
foreach($dataA_id)
{
$get_arrayB = mysql_query("SELECT * FROM tableB where id='".$dataA_id."'");
while($dataB = mysql_fetch_array($get_arrayB))
{
$dataB_lastName = $dataB['LastName'];
$html_output .= "<p>".$dataA_firstName.$dataB_lastName"</p>";
echo $html_output;
}
}
}
Or would this be just too weird of a thing?
I know how to do it within SQL using inner join but how do I do something like that in PHP and output html?
It is because of you misguide use of wildcard (*) characters. STOP THAT !! This is what happens when arrogant php developers imagine that they do not need to learn SQL. If you need something , then select it.
SELECT
foo.foo_id,
foo.data as paramX ,
bar.type,
bar.something_else
FROM foo
INNER JOIN bar USING (foo_id)
WHERE
foo.state = 'open'
AND bar.type = 3
This (I'm just guessing the schema and your needs) could be a better query for your situation:
SELECT a.id,a.FirstName,b.LastName
FROM tableA a
JOIN tableB b ON b.id = a.id
WHERE a.age = '36'

Categories