ORDER BY on joined table - php

I am attempting to join two tables, and also order the query results by one of the columns within the table I am joining. Everything works great until I add ORDER BY cm.num, at which point I get this error:
Call to a member function fetch_assoc() on boolean
Here is my full query:
SELECT *
FROM course
JOIN cm ON (course = cm.course)
WHERE title LIKE '%$searchTerm%'
LIMIT $limit
ORDER BY cm.num
Anyone have any suggestions?
EDIT:
Full code as requested:
function getCourses($searchTerm) {
$mysqli = new mysqli('localhost', 'scott', 'tiger', 'courses');
if ($mysqli->connect_errno) {
header("HTTP/1.1 500 Internal Server Error");
die("Failed to connect to MySQL: {$mysqli->connect_error}");
}
$mysqli->set_charset('utf8');
$courses = [];
$limit = $searchTerm == '' ? 1000 : 10;
$res = $mysqli->query("SELECT * FROM course JOIN cm ON (course = cm.course) WHERE title LIKE '%$searchTerm%' ORDER BY cm.num LIMIT $limit");
while($row = $res->fetch_assoc()) {
$course = new Course(
$row['id'],
$row['title'],
$row['href'],
$row['level'],
$row['award'],
$row['summary'],
$row['dept'],
$row['subject'],
$row['overview'],
$row['wyl'],
$row['careers']
);
array_push($courses, $course);
}
return $courses;
}

Put the limit after the order by and specify the columns specifically
i.e. JOIN cm ON (course.course = cm.course)
SELECT *
FROM course
JOIN cm ON (course.course = cm.course)
WHERE title LIKE '%$searchTerm%'
ORDER BY cm.num
LIMIT $limit

You have (course = cm.course) in your code. course is a table, and you want to join two columns. so it should be something like (course.itsColumn = cm.course)
Let me know if that helped!

Try to add an alias. It's recommended that every table in a join is referenced via a alias.
SELECT *
FROM course AS c
LEFT JOIN cm AS cm ON (c.course = cm.course)
WHERE title LIKE '%$searchTerm%'
LIMIT $limit
ORDER BY cm.num

You are using self join in your code. So can you please check with the following code :
SELECT * FROM course c
JOIN course cm ON (c.course = cm.course)
WHERE c.title LIKE '%$searchTerm%'
ORDER BY cm.num LIMIT $limit

Related

PHP search box issuse

I have a problem with some php code. So, when I write some text inside search box I should get more results, but I only get 1. This happened to my when I added second query with INNER JOIN. I have no idea why I'm getting only 1 result instead of more, anyone can help?
When I remove second query, it shows me all results.
$STH = $DBH->prepare('SELECT * FROM tv_shows WHERE title like :q ORDER BY title ASC LIMIT 5');
$STH->setFetchMode(PDO::FETCH_OBJ);
$STH->execute(array(
':q' => "%$q%"
));
if($STH->rowCount()) {
while($row = $STH->fetch()) {
$poster = $row->poster;
$mtitle = $row->title;
$mrd = $row->release_date;
$mid = $row->id;
$genres = "";
$STH = $DBH->prepare('SELECT g.title from genres g INNER JOIN tv_show_genres tg ON g.id = tg.genre_id INNER JOIN tv_shows t ON t.id = tg.tv_show_id WHERE t.id = :tid');
$STH->setFetchMode(PDO::FETCH_OBJ);
$STH->execute(array(
':tid' => $mid
));
if($STH->rowCount()) {
while($row = $STH->fetch()) {
$genres .= $row->title.", ";
}
echo
'<li>
<span class="search-poster"><img src="'.$poster.'"></span>
<span class="search-title">'.$mtitle.' ('.$mrd.')</span>
<span class="search-genre">'.substr($genres,0,-2).'</span>
</li>';
}
}
}
You're using the same variable $STH for both queries. So when the outer loop gets back to the
while ($row = $STH->fetch())
line, $STH now refers to the second query. Since you've reached the end of the results from that query, calling fetch() here returns false, so this loop ends as well.
Just use different variable names, e.g. $show_STH and $genre_STH.
However, an even better solution is to use a single query.
SELECT s.poster, s.title AS show_title, s.release_date, g.title AS genre_title
FROM (SELECT *
FROM tv_shows
WHERE title like :q
ORDER BY title ASC
LIMIT 5) AS s
INNER JOIN tv_show_genres tg ON s.id = tg.tv_show_id
INNER JOIN genres g ON tg.genre_id = g.id
ORDER BY s.title
Most of the time when you find yourself performing queries in nested loops like this, you can replace it with a single query that joins the two queries.

Can i write two foreach in only one?

In my code I have this:
$im = $database->query("SELECT * FROM cms_messaggi_importanti WHERE messo_da = :id ORDER BY ID DESC", array("id"=>$functions->Utente("id")));
foreach($im as $imp){
$mex_i = $database->query("SELECT * FROM cms_messaggi WHERE id = :id ORDER BY ID DESC", array("id"=>$imp['id_mex']));
foreach($mex_i as $mex_imp){
}
}
Can I write this code in only one? Because I have to use a lot of variable with this method. Is there a solution to my problem? For example, using "JOIN"?
You can (and should) do your query in one go, and then iterate over those results:
$im = $database->query("
SELECT *
FROM cms_messaggi_importanti mi
LEFT JOIN cms_messaggi m ON m.id = mi.id_mex
WHERE messo_da = :id
ORDER BY mi.ID DESC,
m.ID DESC",
array("id"=>$functions->Utente("id")));
foreach($im as $imp){
//...
}
You will probably need to replace the SELECT * by a more precise column list, which will be the columns available in the result set.

Inner/Left join with two different where clauses

i'm in the process of joining two tables together under two different conditions. For primary example, lets say I have the following nested query:
$Query = $DB->prepare("SELECT ID, Name FROM modifications
WHERE TYPE =1 & WFAbility = '0'");
$Query->execute();
$Query->bind_result($Mod_ID,$Mod_Name);
and this query:
$Query= $DB->prepare("SELECT `ModID` from `wfabilities` WHERE `WFID`=?");
$Query->bind_param();
$Query->execute();
$Query->bind_result();
while ($Query->fetch()){ }
Basically, I want to select all the elements where type is equal to one and Ability is equal to 0, this is to be selected from the modifications table.
I further need to select all the IDs from wfabilities, but transform them into the names located in modifications where WFID is equal to the results from another query.
Here is my current semi-working code.
$Get_ID = $DB->prepare("SELECT ID FROM warframes WHERE Name=?");
$Get_ID->bind_param('s',$_GET['Frame']);
$Get_ID->execute();
$Get_ID->bind_result($FrameID);
$Get_ID->fetch();
$Get_ID->close();
echo $FrameID;
$WF_Abilties = $DB->prepare("SELECT ModID FROM `wfabilities` WHERE WFID=?");
$WF_Abilties->bind_param('i',$FrameID);
$WF_Abilties->execute();
$WF_Abilties->bind_result($ModID);
$Mod_IDArr = array();
while ($WF_Abilties->fetch()){
$Mod_IDArr[] = $ModID;
}
print_r($Mod_IDArr);
$Ability_Name = array();
foreach ($Mod_IDArr AS $AbilityMods){
$WF_AbName = $DB->prepare("SELECT `Name` FROM `modifications` WHERE ID=?");
$WF_AbName->bind_param('i',$AbilityMods);
$WF_AbName->execute();
$WF_AbName->bind_result($Mod_Name);
$WF_AbName->fetch();
$Ability_Name[] = $Mod_Name;
}
print_r($Ability_Name);
See below:
SELECT ModID,
ID,
Name
FROM modifications M
LEFT JOIN wfabilities WF
ON WF.ModID = M.ID
WHERE TYPE =1 & WFAbility = '0'
To do this, you need to join your tables, I'm not quite sure what you are trying to do so you might have to give me more info, but here is my guess.
SELECT ID, Name, ModID
FROM modifications
JOIN wfabilities
ON WFID = ID
WHERE TYPE = '1'
AND WFAbility = '0'
In this version I am connecting the tables when WFID is equal if ID. You will have to tell me exactly what is supposed to be hooking to what in your requirements.
To learn more about joins and what they do, check this page out: MySQL Join
Edit:
After looking at your larger structure, I can see that you can do this:
SELECT modifications.Name FROM modifications
JOIN wfabilities on wfabilities.ModID = modifications.ID
JOIN warframes on warframes.ID = wfabilities.WFID
WHERE warframes.Name = 'the name you want'
This query will get you an array of the ability_names from the warframes name.
This is the query:
"SELECT A.ID, A.Name,B.ModID,C.Name
FROM modifications as A
LEFT JOIN wfabilities as B ON A.ID = B.WFID
LEFT JOIN warframes as C ON C.ID = B.WFID
WHERE A.TYPE =1 AND A.WFAbility = '0' AND C.Name = ?"

Joining two tables to get a count

I am attempting to count comments on a particular page with the following problematic sql query:
$query = "SELECT * FROM `comments` WHERE is_approved = '1' AND page_id = '943'"
$query = mysql_query($query);
$total = mysql_num_rows($query);
echo $total;
the problem is it is outputting 0 and not 2.
The tables are as follows:
pages:
id:1 page_id:943
id:2 page_id:978
id:3 page_id:977
comments:
id:2 page_id:1 "hello"
id:3 page_id:1 "great"
id:4 page_id:3 "super"
So really the original query should be getting each comment's true page_id from the page_id as set in the pages tables, as joined by comments.page_id = pages.id
What would the final code look like to either make that join, and/or get that count? Thank you.
Try:
SELECT c.* FROM `comments` c
JOIN `pages` p on c.page_id = p.id
WHERE c.is_approved = '1' AND p.page_id = '943'
"SELECT * FROM comments, pages WHERE comments.page_id = pages.id AND is_approved = '1' AND comments.page_id = '943'"
Try using:
SELECT count(*) as cnt
FROM `comments` c join pages p on c.page_id = p.id
WHERE c.is_approved = '1' AND p.page_id = '943'
It seems like a very poor database design to have two columns with the same name in different tables that mean different things. You should probably change the name of pages.page_id to something else.
And, this returns the count directly, so you can read the value from the row. If you just want the count, there is no reason to return all the matching rows.
no join is needed:
$query = "SELECT * FROM `comments` WHERE is_approved = '1' AND WHERE page_id IN (SELECT id WHERE page_id = '943')"
$query = mysql_query($query);
$total = mysql_num_rows($query);
echo $total;
ofcourse i would suggest a count statement if you do not need/use the data:
$query = "SELECT COUNT(*) as total FROM `comments` WHERE is_approved = '1' AND WHERE page_id IN (SELECT id WHERE page_id = '943')"
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);
$total = $row['total'];
echo $total;

mysql: group results, limit them and join to other tables in one query

i have a online application for wich i require a sort of dashboard (to use the white-space).
There are three tables used for the operation:
1.) categories: id, name
2.) entries: id, name, description, category_id, created, modified
3.) entryimages: id, filename, description, entry_id
on the dashboard i want to show 4-5 entries (with thumbnail images, so i require joins to the entryimages table and the categories table) for each category.
I read through some articles (and threads on s.o.) like this one:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
But am still not getting it right, i've tried to first extract all categories and for each and every category build a query and with "all union" attach them to one, but that is not working.
The last version of code i used:
foreach($categories as $id => $name)
{
$query .= "SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry` LEFT JOIN `entryimages` ON `entryimages`.`entry_id` = `entry`.`id`
WHERE `entry`.`category_id` = $id ";
if($i < count($groups))
{
$query .= 'UNION ALL ';
}
$i++;
}
$result = mysql_query($query);
Does anybody know what is the best right to accomplish this operation?
Thanks 1000
On the dashboard if you want to show three entries, the way you are doing is wrong. If my understanding is right, the entire query will be something like
"SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry`
INNER JOIN categories
ON (entry.category_id = categories.id)
LEFT JOIN (SELECT * FROM `entryimages` WHERE `entry_id` = `entry`.`id` LIMIT 1) AS `entryimages`
ON `entryimages`.`entry_id` =`entry`.`id`
ORDER BY `entry`.`created` DESC LIMIT 5";
Your code looks ok to me you should just add a LIMIT clause so that you get just five of them and an ORDER BY clause to get the latest
$query .= "SELECT `entry`.`id`,
`entry`.`name`,
`entry`.`description`,
`entry`.`category_id`,
`entry`.`created`,
`entry`.`modified`,
`entryimages`.`filename`,
`entryimages`.`description`
FROM `entries` as `entry` LEFT JOIN `entryimages` ON `entryimages`.`entry_id` = `entry`.`id`
WHERE `entry`.`category_id` = $id ORDER BY `entry`.`created` DESC LIMIT 5";

Categories