Reputation: 963
This one has been haunting me for quite a while now.. I have been developing my own CMS using a MySQL database; each uploaded image is assigned to a category, according to which part of the site it is related to (I need to do this since each category has its own way to handle images).
I have several tables for the various entities, an 'images' table, and an associative table: 'images_assoc', their basic structure is as follows:
CREATE TABLE `images` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(50) NOT NULL default '',
`link` varchar(255) NOT NULL default '',
`idcategory` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
INSERT INTO `images` (`id`, `name`, `link`, `idcategory`) VALUES (1, 'some name', 'foo.jpg', 1);
CREATE TABLE `images_assoc` (
`id` int(11) NOT NULL auto_increment,
`idimage` int(11) NOT NULL default '0',
`idelement` int(11) NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `idimage` (`idimage`,`idelement`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
INSERT INTO `images_assoc` (`id`, `idimage`, `idelement`) VALUES (1, 1, 2);
CREATE TABLE v`some_entity` (
`id` int(11) NOT NULL auto_increment,
`title` varchar(250) NOT NULL,
`description` text NOT NULL,
-- some other data
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;
What I need to do, in the various pages of the site, is to retrieve a list of the page elements together with their related image(s). I have not yet been able to do it with one single select. What I am doing right now is to run a select for the page elements and then run a query for each single element to retrieve any associated image, with a query like this:
SELECT i.id, i.link, i.name
FROM images_assoc AS ia, images AS i
WHERE ia.idelement = '1'
AND i.idcategory = '1'
AND i.id = ia.idimage
one solution I initially came up with was:
SELECT t. * , i.id, i.link, i.name
FROM (
(
(
contents AS t
)
LEFT JOIN images_assoc AS ia ON t.id = ia.idelement
)
LEFT JOIN images AS i ON i.id = ia.idimage
)
WHERE i.idcategory = '1'
AND i.id = ia.idimage
but it left out any element with no associated image, which is the exact contrary of the purpose of the left join. Later, I tried changing the query to this:
SELECT t. * , i.id, i.link, i.name
FROM (
(
(
contents AS t
)
LEFT JOIN images_assoc AS ia ON t.id = ia.idelement
)
LEFT JOIN images AS i ON ( i.id = ia.idimage
AND i.idcategoriy = '1' )
)
But still, the query is faulty: I end up with a cross-join-like result, since the category restriction is applied later..
Does anyone have any suggestions? Any tips regarding the database structure are welcome as well..
Upvotes: 1
Views: 111
Reputation: 29874
well your idcategory condition can never match unless there is a corresponding counterpart in the other table, thats why your results with no corresponding image "disappear", left join is behaving correctly.
try this:
sql query:
SELECT some_entity.title, some_entity.description, some_entity.id as entityid, images.id as imageid, images.link, images.name
FROM
some_entity
LEFT JOIN images_assoc ON (some_entity.id = images_assoc.idelement)
LEFT JOIN (SELECT * FROM images WHERE idcategory=1) images ON (images.id = images_assoc.idimage)
or probably better (the obe only to illustrate why it didnt work):
SELECT some_entity.title, some_entity.description, some_entity.id AS entityid, images.id AS imageid, images.link, images.name
FROM some_entity
LEFT JOIN images_assoc ON ( some_entity.id = images_assoc.idelement )
LEFT JOIN images ON ( images.id = images_assoc.idimage )
WHERE images.idcategory = '1' OR images.idcategory IS NULL
test data:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
CREATE TABLE IF NOT EXISTS `images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT '',
`link` varchar(255) NOT NULL DEFAULT '',
`idcategory` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idcategory` (`idcategory`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=124 ;
CREATE TABLE IF NOT EXISTS `some_entity` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(250) NOT NULL,
`description` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=322 ;
CREATE TABLE IF NOT EXISTS `images_assoc` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`idimage` int(11) NOT NULL DEFAULT '0',
`idelement` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `idimage` (`idimage`,`idelement`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
INSERT INTO `images` (`id`, `name`, `link`, `idcategory`) VALUES
(123, 'some name', 'foo.jpg', 1);
INSERT INTO `images_assoc` (`id`, `idimage`, `idelement`) VALUES
(1, 123, 321);
INSERT INTO `some_entity` (`id`, `title`, `description`) VALUES
(321, 'test', 'test');
Upvotes: 1