I'm trying to get info from a table.
I have boards and sub-boards. The column sub_id in table board tells me whether or not the board is a sub-board or not. If it is a sub-board then the id of the parent board is the value, if it isn't then the cell is null.
I wrote this to display whether or not a board has any sub-boards:
<?php
$data = mysql_query("SELECT * FROM board WHERE sub_id='$boardId'")
or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "<br>Sub-collections:<br>";
Print "<font size='5pt'><a href='/board/index/".$info['id']."'>".$info['board_name']." </a></font>";
}
?>
This works fine.
Now I want to write a similar code to name the parent board (if the board is a sub) but this is where I'm having trouble.
I came up with:
<?php
$data = mysql_query("select * from board WHERE id='$boardId' AND sub_id IS NOT NULL") or die(mysql_error());
$issub = mysql_fetch_array($data);
?>
then using...
<?php if(($issub)): ?>
<?php echo $issub['sub_id'] ?>
<?php else: ?>
<?php endif ?>
To display.
The problem is without a join I cannot show anything other than the id of the parent board. I don't know which columns to join in order to extract info like board_name etc.
EDIT:
popovitsj's suggestion:
<?php
$data = mysql_query("SELECT * FROM board b WHERE EXISTS(SELECT * FROM board WHERE b.id = sub_id)") or die(mysql_error());
while($info = mysql_fetch_array( $data ))
{
Print "<br>Sub-collection of:<br>";
Print "<font size='5pt'><a href='/board/index/".$info['id']."'>".$info['board_name']." </a></font>";
}
?>
This works to a certain extent. It correctly displays the parent board on the subboard page, but also displays it erroneously on the parent board page.
EDIT2:
After researching LEFT JOIN at Meier's suggestion I eventually got it to work using this code:
SELECT * FROM board a LEFT JOIN board b ON a.sub_id = b.id WHERE a.sub_id LIKE b.id AND a.id='$boardId'
Before I answer the question: are you 100% sure that the $boardid does not come directly from http and is therefore manipulable by the user, so your users can not start a sql injection?
The join you need is a "outer self join". Outer join because you also want to display boards that do not have a parent. Outer join is also named left join.
A self join because the table is joined to itself. The trick with the self join is to give the table different names in the statement, so you can distinguish between th parent and the child.
A quick google search for "sql outer self join" gave me this, which explains it quite nicely.
The example is with employees and managers, and the managers are also employees. So the example is quite similar to yours:
http://blog.sqlauthority.com/2010/07/08/sql-server-the-self-join-inner-join-and-outer-join/
There are different solutions to this. One possible one is:
SELECT * FROM Board b
WHERE EXISTS
(SELECT * FROM Board
WHERE b.id = sub_id);
Another possible solution could be this, this only shows 'root' parent boards. (boards with no parents themselves).
SELECT * FROM Board b
WHERE sub_id IS NULL;
Related
I connected, I created a quick script in which I want to manage clients, domains and notes.
The problem is that when I add 2 notes to the client from ID: 1 - after viewing I see only one.
The following code shows what I have done so far
SQL Query:
$sql = "SELECT * FROM domain JOIN note ON domain.id = note.domain_id GROUP BY domain.id";
My PHP code:
while($rs = $resultdb->fetch_array(MYSQLI_ASSOC)) {
echo '<tr>';
echo '<td>'.$rs["id"].'</td>';
echo '<td><strong>'.$rs["domain_name"].'</strong></td>';
echo '<td>'.$rs["note"].'</td>';
echo '</tr>';
}
The result he gets is:
ID DOMAIN NOTE
1 "domain1.com" "note 1 to domain1.com"
2 "domain2.com" "note 2 to domain2.com"
However, in the database I have added a few notes to domain1.com.
I would like to see all the notes added to a given domain.
EDIT:
When I do: "SELECT * FROM domain JOIN note ON domain.id = note.domain_id";
I getting:
I getting
I expect
EDIT: Add screnshot
LEFT JOIN
Your GROUP BY is limiting the records retrieved by the query. If you want all of the notes together you can try using GROUP_CONCAT() to produce a single field with all of the notes in one...
$sql = "SELECT domain.id as id, domain.domain_name as domain_name,
GROUP_CONCAT(note.note) as note
FROM domain
LEFT JOIN note ON domain.id = note.domain_id
GROUP BY domain.id";
You might also change the JOIN to LEFT JOIN in case there are no notes for a particular domain.
Probably you need to use a separate query to get "Domain Notes" in the while. for example:
while ($rs = $resultdb->fetch_array(MYSQLI_ASSOC)) {
$sql_notes = "SELECT * FROM notes WHERE domain_id = '" . (int)$rs['domain_id'] . "'";
...
}
you need group_concat group by note.domain_id
if you need exact match the use inner join
"SELECT id, domain, group_concat(note) as note
FROM domain
INNER JOIN note ON domain.id = note.domain_id
GROUP BY note.domain_id";
if you needc result also for id without notes then try
"SELECT id, domain, (group_concat(ifnull(note,'')) as note
FROM domain
LEFT JOIN note ON domain.id = note.domain_id
GROUP BY note.domain_id";
I have a problem with this MySQL Statment. So basicly i have a table called games and i want to
display this table on my website. Table games has Foregin Keys like developer_id,
publisher_id, categorie_id, platform1_id, platform2_id, platform3_id, platform4_id, platform5_id.
I have 5 of platform because in Table platforms i have 5 records (PC, PS4, XB1, SWITCH, MOBILE). (If you guys know any better and easier solution to these platforms pls tell me.)
So now my output on my website works but for example instead of showing developer name it shows
it's ID. I know i have to INNER JOIN them and i probbably can INNER JOIN all foregin keys but the
platform one. Because i dont know how to INNER JOIN if you have more then one FK from one table.
If you need more info tell me. I will also include picture of my DB and my PHP code where i SELECT from table games.
$query = "SELECT * FROM games WHERE id = $id";
$result = mysqli_query($link, $query) or die(mysqli_error($link));
while ($row = mysqli_fetch_array($result)) {
echo '<tr>';
echo '<td>'.$row['developer_id'].'</td>';
echo '<td>'.$row['publisher_id'].'</td>';
echo '<td>'.$row['categorie_id'].'</td>';
echo '<td>'.$row['platform1_id'].'</td>';
echo '<td>'.$row['platform2_id'].'</td>';
echo '<td>'.$row['platform3_id'].'</td>';
echo '<td>'.$row['platform4_id'].'</td>';
echo '<td>'.$row['platform5_id'].'</td>';
echo '<td>'.$row['game_name'].'</td>';
echo '<td>'.$row['relese_date'].'</td>';
$intro = $row['introduction'];
$desc = $row['description'];
echo '<td>'.$row['rating'].'</td>';
echo '</tr>';
}
Picture of my DataBase
SELECT games.game_name, games.relese_date, games.introduction, games.rating, games.description, dev.name as developer, pub.name as publisher, (SELECT * FROM platforms WHERE platforms.id in (games.platform1_id,games.platform2_id,games.platform3_id,games.platform4_id,games.platform5_id)) as plats
FROM games
INNER JOIN developers AS dev ON dev.id = games.developer_id
INNER JOIN publishers AS pub ON pub.id = games.publisher_id
WHERE games.id = $id
Keep in mind that the platforms will be listed as a collection under the property plats, and each of those items will be an object of properties as.
E.X.
return object=>
developer_id
publisher_id
categorie_id
plats => [
platform1_id=>name,
platform2_id=>name,
platform3_id=>name,
platform4_id=>name,
platform5_id=>name
]
game_name
relese_date
introduction
description
rating
I have 2 tables, one for comments and one for the thread. They are both connected with the thread_id which checks what comments belong to what thread. Now I got a profile page and I want to show the comments posted by the user (which already works) and to what thread(column title) each comment belongs to. I am a beginner with cross table queries and I was wondering how I could accomplish this. Here is my code for showing the comments posted by the user:
$sql_result4 = $mysqli2->query("SELECT * FROM comments WHERE username = '".$profileusername."'");
while($postcomments = mysqli_fetch_assoc($sql_result4)){
echo"<a href='thread.php?thread_id={$postcomments['comment_id']}'>{$postcomments['comment']}</a></br>";
}
I was thinking about something like this:
$sql_result4 = $mysqli2->query("SELECT * FROM comments WHERE username = '".$profileusername."'");
$sql_result5 = $mysqli2->query("")
while($postthread = mysqli_fetch_assoc($sql_result5){
while($postcomments = mysqli_fetch_assoc($sql_result4)){
echo"<a href='thread.php?thread_id={$postcomments['comment_id']}'>{$postcomments['comment']}</a></br>";
}
}
but I have no idea what to use for $sql_result5
What should I put as $sql_result5
You can use just 1 query and use left join.
SELECT c.*, t.* FROM comments c
LEFT JOIN threads t ON t.id = c.thread_id
WHERE c.username = 'username'
Now you have all data in 1 result.
I'm loading comments for product with id = '3'
$get_comments = mysql_query("SELECT * FROM products_comments WHERE product_id = '3'");
Now I want to add the "report abuse" option for each comment, for this purpose I'm having another table as "abuse_reports" which user abuse reports will be stored in this table, now if a user reported a comment, the report abuse option should not be there for that comment for that user there anymore, for this I'm doing:
while($row = mysql_fetch_array($get_comments)){
echo blah blah blah // comment details
// now for checking if this user should be able to report this or not, i make this query again:
$check_report_status = mysql_query("SELECT COUNT(id) FROM abuse_reports WHERE reporter_user_id = '$this_user_id' AND product_id = 'this_product_id'");
// blah blah count the abuse reports which the current user made for this product
if($count == 0) echo "<a>report abuse</a>";
}
With the above code, for each comment I'm making a new query, and that's obviously wrong, how I should join the second query with the first one?
Thanks
Updated query (that is working now, commited by questioner)
SELECT pc. * , count( ar.`id` ) AS `abuse_count`
FROM `products_comments` pc
LEFT OUTER JOIN `abuse_reports` ar ON pc.`id` = ar.`section_details`
AND ar.`reporter_id` = '$user_id'
WHERE pc.`product_id` = '$product_id'
GROUP BY pc.`id`
LIMIT 0 , 30
The query works as follow: You select all the fields of your products_comments with the given product_id but you also count the entries of abuse_reports for the given product_id. Now you LEFT JOIN the abuse_reports, which means that you access that table and hang it on to the left (your products_comments table). The OUTER allows that there is no need for a value in the abuse_reports table, so if there is no report you get null, and therefore a count of 0.
Please read this:
However, I needed to group the results, otherwise you get only one merged row as result. So please extend your products_comments with a field comment_id of type int that is the primary key and has auto_increment.
UPDATE: abuse count
Now you can do two things: By looping through the results, you can see for each single element if it has been reported by that user or not (that way you can hide abuse report links for example). If you want the overall number of reports, you just increase a counter variable which you declare outside the loop. Like this:
$abuse_counter = 0;
while($row = mysql....)
{
$abuse_counter += intval($row['abuse_count']); // this is 1 or 0
// do whatever else with that result row
}
echo 'The amount of reports: '.$abuse_counter;
Just a primitive sample
I believe your looking for a query something like this.
SELECT pc.*, COUNT(ar.*)
FROM products_comments AS pc
LEFT JOIN abuse_reports AS ar ON reporter_user_id = pc.user_id AND ar.product_id = pc.product_id
WHERE product_id = '3'"
try this SQL
SELECT pc.*, COUNT(ar.id) AS abuse_count
FROM products_comments pc
LEFT JOIN abuse_reports ar ON pc.product_id = ar.product_id
WHERE pc.product_id = '3' AND ar.reporter_user_id = '$this_user_id'
GROUP BY pc.product_id
The result is list of products_comments with abuse_reports count if exist for reporter_user_id
I want multiple photos and multiple videos, the main problem is that I can't get them inline if I don't use joins.
So for example, I get 2 photos a video and again a photo.
I have a parent news table and 2 secondary table news_photos and news_videos and I want to get in one query the photos and videos for the news.
Is this somehow possible?
mysql_query("
SELECT *
FROM news_photos, news_videos
FULL JOIN news_videos
ON news_id = {$news_id}
FULL JOIN news_photos
ON news_id = {$news_id}
");
An image about the structure:
There's actually only a single FULL JOIN in that, since you are not involving the news table at all.
SELECT *
FROM news_photos
FULL JOIN news_videos
ON news_photos.news_id=news_videos.news_id
WHERE news_photos.news_id=... OR news_videos.news_id=...
FULL JOIN is not supported by MySQL. It can be less-efficiently simulated using two LEFT JOINs and a UNION, but it's relatively rare that you actually need to. Assuming every photo and video does belong to a news, you could avoid it and get a more conventional query by bringing the news table into it:
SELECT *
FROM news
LEFT JOIN news_photos ON news_photos.news_id=news.id
LEFT JOIN news_videos ON news_videos.news_id=news.id
WHERE news_id=...
But still, this is almost certainly not what you mean! If there are multiple photos and videos for a news item, you would be effectively creating a cartesian product, where every combination of photo and video produces a row. This is the sort of combinatorial explosion you almost never want!
If you just want one of each photo and video, I suppose you could hack that into a single query using a LEFT JOIN that will always give NULL on the other side:
SELECT * FROM news_photos
LEFT JOIN news_videos ON 0
WHERE news_photos.news_id=...
UNION SELECT * FROM news_photos
RIGHT JOIN news_videos ON 0
WHERE news_videos.news_id=...
But there's really nothing to be gained by this. Don't shoehorn two separate queries (“I'd like the photos for a news, and the videos for a news”) into one. Just do it the trivial way:
SELECT * FROM news_photos
WHERE news_id=...
SELECT * FROM news_videos
WHERE news_id=...
i would do it using a stored procedure that had multiple select statements as follows:
http://pastie.org/1141100
drop procedure if exists list_news_photos_videos;
delimiter #
create procedure list_news_photos_videos
(
in p_news_id int unsigned
)
proc_main:begin
select n.* from news n where n.news_id = p_news_id;
select p.* from news_photos p where p.news_id = p_news_id order by photo_id desc;
select v.* from news_videos v where v.news_id = p_news_id order by video_id desc;
end proc_main #
you would call this in mysql as follows:
call list_news_photos_videos(2);
then you can call the stored procedure from php (1 db call only) using mysqli as follows:
http://pastie.org/1141103
<?php
// quick and dirty demo - needs to be made more robust !!
$db = new Mysqli("localhost", "foo_dbo", "pass", "foo_db");
$sql = sprintf("call list_news_photos_videos(%d)", 2); // get all the news related data in one query
$result = $db->query($sql);
//news item
$row = $result->fetch_assoc();
echo sprintf("<h2>news item</h2>news_id = %d subject = %s <br/>", $row["news_id"], $row["subject"]);
$result->free();
//news photos
$db->next_result();
$result = $db->use_result();
echo "<h2>news photos</h2>";
while ($row = $result->fetch_assoc()){
echo sprintf("photo_id = %d subject = %s<br/>", $row["photo_id"], $row["subject"]);
}
$result->free();
//news videos
$db->next_result();
$result = $db->use_result();
echo "<h2>news videos</h2>";
while ($row = $result->fetch_assoc()){
echo sprintf("video_id = %d subject = %s<br/>", $row["video_id"], $row["subject"]);
}
$result->free();
$db->close();
?>