views:

33

answers:

1

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..

+1  A: 

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');
Joe Hopfgartner
thank you! I will test it on real data as soon as I can..I will let you know of the 'developements'..
Lucius
gr8. use the second version wth the IS NULL condition.
Joe Hopfgartner
nice.. never even tought of using IS NULL.. d'oh!
Lucius
:) if it works it'd be nice to accept the answer
Joe Hopfgartner
perfect, that works nice and smooth.. thank you!
Lucius