Advanced many2many query for MYSQL - php

I im trying to build a imagegallery where people have access to different groups and the groups decide what catalogues and images they are allowed to see.
I though many2many structure would be best for this.
So far, ive manage to build the database like this:
image (image_name, image_file, image_id)
catalog (catalog_id, catalog_name)
supplier (supplier_id, supplier_name)
user (name, user_id)
image2cataloge (image_id, catalog_id)
image2supplier (image_id, supplier_id)
catalog2supplier (catalog_id, supplier_id)
user2supplier (user_id, supplier_id)
So... that been said, saving images and making supplier (or group if you want), adding users to supplier and linking images to supplier and catalogues is no problem. Inserting is no problem.
But selecting the right images based upon the users supplier setting and catalog they are in is harder.
For example, I have a user with user_id 1, which have access to supplier_id 1. supplier_id 1 have access to view catalogue 1, which holds images with image_id 1 and 2.
But supplier_id 1 only have access to image_id 2.
All this settings are stored in the database. How do I do the select query?
This is what i've tested;
//$catalog_id is the catalog_id we are in
//$user_id is the current users user_id
$sql = "SELECT i.*
FROM image i, user u, catalog cat, supplier s, supplier2user s2u, supplier2catalog s2c, image2catalog i2c, image2supplier i2s
WHERE u.id = '".$user_id."'
AND s2u.user_id = '".$user_id."'
AND s2u.supplier_id = s.id
AND s2c.catalog_id = '".$catalog_id."'
AND i2c.catalog_id = '".$catalog_id."'
AND i2s.supplier_id = s.id
AND s2c.supplier_id = s.id
GROUP BY i.id
ORDER BY i.name ASC
But when ive added more than one image, all images are shown for all users in all catalogues.
EDIT (2010/02/05):
Okey, so I've figured out how to at least show correct images in correct catalog. I do this by doing following:
$sql = "SELECT i.*
FROM
image i
INNER JOIN image2catalog i2c
ON i.id = i2c.image_id
AND i2c.catalog_id = '".$pages_level_0[$i]['id']."'
GROUP BY i.id
;";
This let's me output the correct images that belongs in the catalog the user is visiting at the moment. Now I just need to edit this query to filter out all images the user doesn't have access to. I very grateful for any help you can provide!
EDIT 2010/02/09:
---
CREATION SCHEME
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`email` varchar(250) NOT NULL,
`password` varchar(50) NOT NULL
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(250) character set utf8 NOT NULL default '',
`url` varchar(250) character set utf8 NOT NULL default '',
`childof` varchar(250) character set utf8 NOT NULL default '',
`hide` tinyint(4) NOT NULL,
`publishdate` varchar(14) NOT NULL,
`expiredate` varchar(14) NOT NULL,
`editdate` varchar(14) NOT NULL,
`editbygroup` varchar(250) NOT NULL,
`openby` varchar(250) NOT NULL,
`opendate` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci;
CREATE TABLE `imagebank_image` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(250) NOT NULL,
`img` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank_image2catalog` (
`image_id` int(11) NOT NULL,
`catalog_id` int(11) NOT NULL,
PRIMARY KEY (`image_id`,`catalog_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank_image2supplier` (
`image_id` int(11) NOT NULL,
`supplier_id` int(11) NOT NULL,
PRIMARY KEY (`image_id`,`supplier_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank_supplier` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(250) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank_supplier2catalog` (
`supplier_id` int(11) NOT NULL,
`catalog_id` int(11) NOT NULL,
PRIMARY KEY (`supplier_id`,`catalog_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `imagebank_supplier2user` (
`supplier_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`supplier_id`,`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
SOME DATA:
INSERT INTO `imagebank` (`id`, `name`, `url`, `childof`, `hide`, `publishdate`, `expiredate`, `editdate`, `editbygroup`, `openby`, `opendate`) VALUES
(1, 'Test 1', 'test-1', '', 0, '20100204230233', '', '', '', '', ''),
(2, 'Test 2', 'test-2', '', 0, '20100204230244', '', '', '', '', '');
INSERT INTO `imagebank_image` (`id`, `name`, `img`) VALUES
(1, 'Test img 1', 'labb_9noq80bik5.jpeg'),
(2, 'Test img 2', 'labb_53626114dz.jpeg');
INSERT INTO `imagebank_image2catalog` (`image_id`, `catalog_id`) VALUES
(1, 1),
(2, 2);
INSERT INTO `imagebank_image2supplier` (`image_id`, `supplier_id`) VALUES
(1, 2),
(2, 1);
INSERT INTO `imagebank_supplier` (`id`, `name`) VALUES
(1, 'Supplier1'),
(2, 'Supplier2'),
(3, 'Supplier3');
INSERT INTO `imagebank_supplier2catalog` (`supplier_id`, `catalog_id`) VALUES
(1, 2),
(2, 1);
INSERT INTO `imagebank_supplier2user` (`supplier_id`, `user_id`) VALUES
(1, 1),
(1, 11),
(1, 12),
(2, 1),
(2, 10),
(3, 1);
INSERT INTO `user` (`id`, `email`, `password`) VALUES
(1, 'User1#test.com', 'ff02dd5s33taa2ba5ff7c2c4d3327e444'),
(10, 'User2#test.com', 'ff02dd5s33taa2ba5ff7c2c4d3327e444'),
(11, 'User3#test.com', 'ff02dd5s33taa2ba5ff7c2c4d3327e444'),
(12, 'User4#test.com', 'ff02dd5s33taa2ba5ff7c2c4d3327e444');
WOW, now thats alot of stuff :P So I know that the tables, specially for "catalogs" which i call just "imagebank" might look abit strange. But I do have my reasons and thats not really the issue :) Its part of an even bigger picture. Hope this helps you to help me. Thanks again.

It looks like if you are passing in the user and catalogue id's then the supplier doesn't matter.
If you required the supplier information in the result, that would be a different matter.
It feels like you shouldn't be involving the user in this query at all as you seem to be looking for the images in a catalogue that are owned by a particular supplier.
If that is the case, then I would drop the requirement for the user id in the query and use the supplier id instead.
I am assuming that the user would have done the following to get to the point where they would be initiating this query:
login - obviously :)
click on 'list suppliers'
click on a supplier
click on a catalog
Either way you are going to have to do a lot of INNER JOIN's. For instance the query to retrieve the list of suppliers for a given user would be something like
SELECT
s.supplier_id,
s.Supplier_name
FROM
supplier s
INNER JOIN
user u
INNER JOIN
user2supplier u2s
ON
u.user_id = u2s.user_id
ON
u2s.supplier_id = s.supplier_id
WHERE
u.user_id = 3 -- for example...
(now, I haven't tested the SQL, but I think that is right...)
Let me know if I'm on the right track - if I have helped, I'd be happy to help some more if I can

Related

How could i display the items from 3 tables joined

How could i display the items from 3 tables below joining using the product_tbl id.
and using foreach. or if there is any alternative way to display it.
The tables
I couldn't get the 3rd table or pictures table.
using my existing code below.
still error.
$product_list = DB::table('product_tbl')
->leftjoin('brand_tbl', 'product_tbl.id', '=', 'brand_tbl.product_id')
->select('*')
->get();
return vehicles_list;
$prod_list = array();
foreach ($product_list as $key => $value) {
$prod_list [$value->products_name][] = $value;
}
print_r($prod_list);
please help me thank you.
If your table structure isn't set in stone you might try the following structure for a more normalized and indexable structure. I made some changes - changing product to category, and brand to product. These labels made more sense to me as I worked with this. I also do full namespaced field names to make joining possible without aliasing all field names.
see the bottom of this post for the SQL to generate and populate these tables
Then a different query will definitely help. You're not joining on the picture table in your code.
select * from so_category
left outer join so_product on ( product_category_id = category_id)
left outer join so_picture on ( picture_category_id = category_id )
But this will probably not return your data like you want to consume it.
In which case the Mysql Group Concat Function might help.
SELET
so_category.*,
so_product.*,
(select GROUP_CONCAT( DISTINCT picture_url order by picture_url asc separator "," )) AS images
FROM so_category
LEFT OUTER JOIN so_product ON ( product_category_id = category_id)
LEFT OUTER JOIN so_picture ON ( picture_category_id = category_id )
GROUP BY product_id
Which yields results that do not duplicate data.
SQL to create and populate tables.
-- Create syntax for TABLE 'so_category'
CREATE TABLE `so_category` (
`category_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`category_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB CHARSET=utf8;
-- Create syntax for TABLE 'so_picture'
CREATE TABLE `so_picture` (
`picture_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`picture_url` varchar(100) DEFAULT NULL,
`picture_category_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`picture_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Create syntax for TABLE 'so_product'
CREATE TABLE `so_product` (
`product_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`product_name` varchar(100) DEFAULT NULL,
`product_brand_id` int(11) unsigned DEFAULT NULL,
`product_category_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `so_category` (`category_id`, `category_name`)
VALUES
(1, 'chocolate'),
(2, 'flower');
INSERT INTO `so_picture` (`picture_id`, `picture_url`, `picture_category_id`)
VALUES
(1, 'dmc1', 1),
(2, 'dmc2', 1),
(3, 'dmc3', 2),
(4, 'dmc4', 2),
(5, 'dmc5', 2);
INSERT INTO `so_product` (`product_id`, `product_name`, `product_brand_id`, `product_category_id`)
VALUES
(1, 'hershey', NULL, 1),
(2, 'tobleron', NULL, 1),
(3, 'oreo', NULL, 1),
(4, 'roses', NULL, 2),
(5, 'sunflower', NULL, 2);

Find Tag with field_in_set over 3 Tables without Join

I have 3 tables :
link_art_a
link_art_b
link_art_c
I want to now search for "car" and this output on one side .
The tables are almost identical , fields that I need :
id, name , mod_name , picture , hits.
The field is where there wanted , is separated by a comma , for example :
Car , truck , SUV , bike
Field: "tag"
I've FIND_IN_SET attempts , but I always get all the entries in the database and not with the "car" .
What I have tried so far :
SELECT id, name, mod_name, picture, hits from link_art_a
UNION ALL
SELECT id, name, mod_name, picture, hits from link_art_b
UNION ALL
SELECT id, name, mod_name, picture, hits from link_art_c
where
find_in_field('Car', tag) > 0 order by name asc
Does anyone have an idea how I get my desired result ?
Edit:
Hello,
The problem is that I get all records including those that do not contain the desired word such as "car" .
The MySQL Dump:
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";
CREATE TABLE `link_art_a` (
`id` bigint(20) NOT NULL,
`name` varchar(100) NOT NULL,
`mod_name` varchar(200) NOT NULL,
`picture` varchar(100) NOT NULL,
`hits` bigint(20) NOT NULL,
`tag` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `link_art_a` (`id`, `name`, `mod_name`, `picture`, `hits`, `tag`) VALUES
(1, 'A8', 'a8.html', 'default.jpg', 251, 'car,sports car,sport,fast'),
(2, 'VW Beetle', 'vw-beetle', 'default.jpg', 269, 'car,fun,slow');
CREATE TABLE `link_art_b` (
`id` bigint(20) NOT NULL,
`name` varchar(100) NOT NULL,
`mod_name` varchar(200) NOT NULL,
`picture` varchar(100) NOT NULL,
`hits` bigint(20) NOT NULL,
`tag` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `link_art_b` (`id`, `name`, `mod_name`, `picture`, `hits`, `tag`) VALUES
(1, 'Surfboard', 'surfboard', 'default.jpg', 142, 'fun,sport,water'),
(2, 'Sport boat', 'sport-boat', 'default.jog', 163, 'sport,fun,water,fast');
CREATE TABLE `link_art_c` (
`id` bigint(20) NOT NULL,
`name` varchar(100) NOT NULL,
`mod_name` varchar(200) NOT NULL,
`picture` varchar(100) NOT NULL,
`hits` bigint(20) NOT NULL,
`tag` varchar(250) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `link_art_c` (`id`, `name`, `mod_name`, `picture`, `hits`, `tag`) VALUES
(1, 'Houseboat', 'houseboat', 'default.jog', 144, 'house,boat,water'),
(2, 'Speedboat', 'speedboat', 'default.jpg', 142, 'water,boot,speed,fast');
ALTER TABLE `link_art_a` ADD PRIMARY KEY (`id`), ADD KEY `tag` (`tag`);
ALTER TABLE `link_art_b` ADD PRIMARY KEY (`id`), ADD KEY `tag` (`tag`);
ALTER TABLE `link_art_c` ADD PRIMARY KEY (`id`), ADD KEY `tag` (`tag`);
ALTER TABLE `link_art_a`
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
ALTER TABLE `link_art_b`
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
ALTER TABLE `link_art_c`
MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;COMMIT;
your where clause applies to the last select only.
You have to add where to all select statements
Like this:
SELECT id, name, mod_name, picture, hits from link_art_a
where
find_in_set('Car', tag) > 0
UNION ALL
SELECT id, name, mod_name, picture, hits from link_art_b
where
find_in_set('Car', tag) > 0
UNION ALL
SELECT id, name, mod_name, picture, hits from link_art_c
where
find_in_set('Car', tag) > 0
NOTES:
you must remove order by in this case.
it is find_in_set() not find_in_field()
Or add it to all of them
SELECT id, name, mod_name, picture, hits from
(
SELECT id, name, mod_name, picture, hits, tag from link_art_a
UNION ALL
SELECT id, name, mod_name, picture, hits, tag from link_art_b
UNION ALL
SELECT id, name, mod_name, picture, hits, tag from link_art_c
) as t1
where
find_in_set('Car', t1.tag) > 0 order by t1.name asc

Searching String In All Tables And Displaying It With Pagination Technique

My database has five tables:
Computer|Mobile|Tablet|MusicSystem|Camera
All the tables are in same structure like:
productID|ProductBrand|Price|userId
Here, I want to search product's brand name in all the field of productBrand in all the tables, where userId=$userId and limit is 10 then display it with pagination technique.
How can I create such a query in MySQLi and display it in PHP?
Thanks in advance.
try this...
select * from Computer c,Mobile m,Tablet t,MusicSystem ms,Camera cam where userId = $userId and (c.productBrand = searchingProductBrand or m.productBrand = searchingProductBrand or t.productBrand = searchingProductBrand or ms.productBrand = searchingProductBrand or cam.productBrand = searchingProductBrand ) limit 10
If you are following same structure for each category table,better structure is to categorize all into single table as follows
CREATE TABLE IF NOT EXISTS `category` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`category_name` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `category` (`id`, `category_name`) VALUES
(1, 'Computer'),
(2, 'Mobile'),
(3, 'Tablet'),
(4, 'MusicSystem'),
(5, 'Camera');
CREATE TABLE IF NOT EXISTS `products` (
`ProductId` int(11) NOT NULL AUTO_INCREMENT,
`ProductBrand` varchar(255) NOT NULL,
`Price` varchar(100) NOT NULL,
`UserId` int(11) unsigned NOT NULL,
`CatId` int(11) unsigned NOT NULL,
PRIMARY KEY (`ProductId`),
KEY `CatId` (`CatId`),
CONSTRAINT `products_ibfk_1` FOREIGN KEY (`CatId`) REFERENCES `category` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
INSERT INTO `products` (`ProductId`, `ProductBrand`, `Price`, `UserId`, `CatId`) VALUES
(1, 'Lenovo', '35000', 5, 3),
(2, 'Asus', '28350', 5, 2),
(3, 'Dell', '25000', 5, 3),
(4, 'MotoG', '12500', 5, 2),
(5, 'Samsung', '52000', 4, 1);
You can get your result using
SELECT * FROM products WHERE userId = '5'
Check the FIDDLE

checkbox check with database data

i have two mysql tables and looks like as follows. iam using PHP and MySQL
CREATE TABLE IF NOT EXISTS `subject_category` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`sid` int(5) DEFAULT NULL,
`category` varchar(50) DEFAULT NULL,
`subject` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=191 ;
INSERT INTO `subject_category` (`id`, `sid`, `category`, `subject`) VALUES
(1, 1, 'GCE O/L', 'Sinhala'),
(2, 2, 'GCE O/L', 'Development Studies'),
(3, 3, 'GCE O/L', 'History'),
(4, 4, 'GCE O/L', 'Mathematics'),
(5, 5, 'GCE O/L', 'Citizan Education'),
and
CREATE TABLE IF NOT EXISTS `user_subjects` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`uid` bigint(20) NOT NULL,
`usid` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=43 ;
INSERT INTO `user_subjects` (`id`, `uid`, `usid`) VALUES
(11, 142247454430186, 1),
(12, 142247454430186, 3),
(13, 142247454430186, 5)
actually what i need is, need to create check-box array using first table data. this part is already done. then i need to checked checkbox match with second table (subject_category.id=user_subjects.usid) for the particular user_subject.uid
FINALLY i need 5 check boxes for data in first table and 3 of them have selected with to second table values
please help me to solve this problem
I think you start off the wrong way, you should do it in 1 step, not in two steps.
The mysql query you need is:
$query = 'SELECT sc.subject, CASE WHEN us.id IS NULL THEN "" ELSE "checked" AS checked
FROM subject_category sc
LEFT JOIN user_subjects us ON (us.usid = sc.id)';
With the result of this query you should be able to generate the checked and unchecked checkboxes at once.
NOTE: I don't know which columns you need and if you needed sc.id or sc.sid in the join, but I think you can create the right query with this example.
Next step PHP (with mysql_* function as the TS asks in comment, I know you should use PDO or mysqli):
$result = mysql_query($query);
while ($line = mysql_fetch_assoc($result)){
echo '<input type="checkbox" checked="'.$line['checked'].'" name="subject" value="'. $line['subject'] .'" /> '.$line['subject'];
}

Show proper categories for blogposts

I'm trying to get all the categories about the specific blogpost but it will not work as I wanted it to work. Below you can see the SQL and code. $blog fetch the information about the specific blogpost.
CREATE TABLE IF NOT EXISTS `blogposts` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`id_user_created` int(10) DEFAULT '0',
`id_user_edited` int(10) DEFAULT '0',
`post_subject` varchar(100) NOT NULL,
`post_message` text NOT NULL,
`post_categories` text NOT NULL,
`date_published` datetime NOT NULL,
`date_edited` datetime NOT NULL,
`info_ipaddress_created` text NOT NULL,
`info_ipaddress_edited` text NOT NULL,
`is_shared` enum('0','1') DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
)
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`id_user` int(10) DEFAULT '0',
`post_name` text NOT NULL,
`date_added` datetime NOT NULL,
`date_edited` datetime NOT NULL,
`info_ipaddress` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
)
$get_categories = "SELECT * FROM blogposts, categories
WHERE blogposts.id = '".(int)$blog['id']."'
AND blogposts.post_categories = categories.id
";
foreach($sql->query($get_categories) AS $category) {
echo '<a href="'.url('blog/category/'.$category['post_name']).'" class="grey-link">';
echo $category['post_name'];
echo '</a>';
}
INSERT INTO blogposts` (id, id_user_created, id_user_edited, post_subject, post_message, post_categories, date_published, date_edited, info_ipaddress_created, info_ipaddress_edited, is_shared)
VALUES (1, 1, 1, 'test', 'testar', '1', '', '', '', '', '0'),
(2, 1, 1, 'med kategorier', 'wiho!', '1|2', '', '', '', '', '0');
INSERT INTO categories` (id, id_user, post_name, date_added, date_edited, info_ipaddress)
VALUES (1, 1, 'test', '', '', ''),
(2, 1, 'test2', '', '', '');
Right now it's only prints Categorized in test, on both blogposts I have posted. It should prints out Categorized in test for the first post and Categorized in test, test2 for the second post. post_categories looks like this: 1|2 which is the ID for the specific category.
Thanks in advance.
If I look at your 'blogposts' table, your 'post_categories' field is of type text. I don't know what is in there but I can imagine it to be a string with id's separated by some character like a semi-colon. This approach limit's the flexibility of your queryies. You'd be better of by creating a link table. This means that you introduce a new table that is responsible for the linkage between a blogpost and it's categories. Looking something like:
CREATE TABLE IF NOT EXISTS `blogposts` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`post_message` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
)
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`category_name` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
)
CREATE TABLE IF NOT EXISTS `post_categories` (
`post_id` int(10) NOT NULL AUTO_INCREMENT,
`category_id` text NOT NULL
)
This last table can be used to get all categories that come with a blogpost. You can query over it by using a JOIN, like so:
SELECT *
FROM blogposts b
INNER JOIN post_categories pc ON pc.post_id=p.id
INNER JOIN categories c ON c.id=pc.category_id
WHERE b.id=<yourvariable>
You will than have a list with a lot of duplication but each row is for another category which you can use to display somewhere or whatever purpose you have with it. Maybe it is cleaner to separate this into two queries that a. get the blogpost with the id you have and b. get the categories that come with the blogpost by using the link table.

Categories