Mysql query across three tables? - mysql

I'm building a site that allows users to upload posters of television productions they have made. Other users can add themselves to the posters if they were involved with the production and their names get listed below the poster too.
I am having problems writing a mysql query that will allow me to list all the uploaded posters but also any of the users that have listed themselves as being involved with the production. I have made this sql fiddle that might help. The current query displays all the uploaded posters but not those who have added themselves to the poster. Any ideas?
The query
SELECT tbl_uploads.file_name, tbl_users.user_id, tbl_users.user_name, tbl_collab.collab_userid, tbl_collab.collab_username
FROM tbl_uploads
left join tbl_collab on tbl_collab.file_name = tbl_uploads.file_name
left join tbl_users on tbl_uploads.user_id = tbl_users.user_id
group by tbl_uploads.file_name
The tables
CREATE TABLE IF NOT EXISTS `tbl_users` (
`user_id` int(11) NOT NULL,
`user_name` varchar(25) NOT NULL,
`user_email` varchar(60) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
INSERT INTO `tbl_users` (`user_id`, `user_name`,`user_email`) VALUES
(2, 'julian', 'julian#email.com'),
(3, 'bob', 'bob#email.com'),
(4, 'sue', 'sue#email.com');
CREATE TABLE IF NOT EXISTS `tbl_uploads` (
`id` int(10) NOT NULL,
`file_name` varchar(100) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;
INSERT INTO `tbl_uploads` (`id`, `file_name`, `user_id`) VALUES
('7', 'Julians Picture','2' ),
('13', 'Julians 2nd picture','2' ),
('14', 'Bobs Picture','3' ),
('15', 'Another Picture','3' );
CREATE TABLE IF NOT EXISTS `tbl_collab` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`collab_username` varchar(255) NOT NULL,
`file_name` varchar(255) NOT NULL,
`collab_userid` varchar(255) NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1;
INSERT INTO `tbl_collab` (`id`,`file_name`,`collab_userid`, `user_id`,`collab_username`) VALUES ('1','Bobs Picture','4','4','Sue' ), ('2','Another Picture','3','3','Bob' )
,('3','Bobs Picture','2','2','Julian' );

This did what I was looking for. GROUP_CONCAT did the trick
SELECT up.file_name, GROUP_CONCAT(c.collab_username)
FROM tbl_uploads up
LEFT JOIN tbl_users p ON up.user_id = p.user_id
LEFT JOIN tbl_collab c ON up.file_name = c.file_name
GROUP BY up.file_name

Related

Joining data from 3 separate MySQL tables

I have 3 MySQL tables: person, review & team.
I have been able to join 2 (person & review) together, however I'd like to include data from the 3rd in my result.
Can someone explain how this is done? :-)
CREATE TABLE `person` (
`id` int NOT NULL AUTO_INCREMENT,
`reference` varchar(100) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
INSERT INTO `person` (`id`, `reference`, `email`) VALUES
(1, 'PK001', 'paulk#gmail.com');
CREATE TABLE `review` (
`id` int NOT NULL AUTO_INCREMENT,
`review_type` varchar(255) NOT NULL,
`review_body` varchar(255) NOT NULL,
`person_id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
INSERT INTO `review` (`id`, `review_type`, `review_body`, `person_id`) VALUES
(1, 'Personality', 'He has a great personality!', 1),
(2, 'Skills', 'He has multiple skills!', 1);
CREATE TABLE `team` (
`id` int(11) NOT NULL,
`person_id` int(11) NOT NULL,
`team_name` varchar(255) NOT NULL,
`value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `team` (`id`, `person_id`, `team_name`, `value`) VALUES
(1, 1, 'Man Utd', 500),
(2, 1, 'Real Madrid', 1500),
(3, 1, 'Ajax', 1000);
Using the following SQL:
SELECT p.id, group_concat(r.review_body)
FROM person p
inner join review r on r.person_id = p.id
group by p.id
gives me the output:
He has a great personality!,He has multiple skills!
However I'd ultimately like my output to be:
He has multiple skills!,He has a great personality,Man Utd-500|Real Madrid-1500|Ajax-1000
Is this possible to do with MySQL ? Any guidance would be greatly appreciated.
I realise I could optimise things a lot better - but I just want to see if I can connect all 3 tables together and go from there.
To get your required concatenated output you need to modify your join query.
For that your new query looks like this:
SELECT p.id,
GROUP_CONCAT(r.review_body) AS reviews,
(SELECT GROUP_CONCAT(CONCAT(team_name, '-', value) SEPARATOR '|')
FROM team
WHERE team.person_id = p.id) AS teams
FROM person p
INNER JOIN review r ON r.person_id = p.id
GROUP BY p.id;
Result :

need help in writing complex sql query with join and with case

Here is SQL Fiddle
Expected output is below:
id | firstname. | lastname. | country.| followerscount.| followingcount.| BottonText
------------------------------------------------------------------------------------
54 prince lal nepal 1 1 Unfollow
56. Rekha. Gupta United States 1 0 Unfollow
57. Nirmal null null 0 1 Follow Back
I tried below query assuming current logged in UserId= 55 & compare with other users. Can you write the correct query, it can be with join, i just need the output,query can be anything
TRY1
SELECT
u.user_id AS id, u.first_name AS firstname,u.last_name AS lastname,u.country as country,
(select count(uf.following_user_id) from user_follow uf where uf.followed_user_id=u.user_id)as followerscount,
(select count(uf.followed_user_id) from user_follow uf where uf.following_user_id=u.user_id)as followingcount,
CASE
WHEN uuf.following_user_id=55 AND uuf.followed_user_id=u.user_id THEN "Unfollow" # A is following B == unfollow
WHEN uuf.following_user_id=u.user_id AND uuf.followed_user_id NOT IN(55) THEN "Follow Back" #B is following A but A is not following B = followBack
ELSE "Follow"
END AS BottonText
FROM userdetails u,user_follow uuf
WHERE u.user_id NOT IN(55) AND u.record_status=1
TRY2
SELECT
u.user_id,
(count(uf.following_user_id)) as followers,
CASE
WHEN uf.following_user_id=55 AND uf.followed_user_id=u.user_id THEN "Unfollow" # A is following B == unfollow
WHEN uf.following_user_id=u.user_id AND uf.followed_user_id=55 AND uf.following_user_id !=55 AND uf.followed_user_id !=u.user_id
THEN "Follow Back" #B is following A but A is not following B = followBack
ELSE "Follow"
END AS BottonText,
(select count(uf.followed_user_id)
from user_follow uf
where uf.following_user_id = u.user_id) as following
from
(userdetails u left outer join user_follow uf on uf.followed_user_id=u.user_id)
where u.record_status=1 and u.user_id NOT IN(55)
group by u.user_id
Table defination
CREATE TABLE `userdetails` (
`user_id` int(11) NOT NULL,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) DEFAULT NULL,
`country` varchar(30) DEFAULT NULL,
`avatar_img_name` varchar(30) DEFAULT NULL,
`record_status` int(1) NOT NULL COMMENT '1- active'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `userdetails`
ADD PRIMARY KEY (`user_id`);
CREATE TABLE `user_follow` (
`id` int(11) NOT NULL,
`following_user_id` int(11) NOT NULL,
`followed_user_id` int(11) NOT NULL,
`created_date` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
#following_user_id and followed_user_id are foriegn key associated userdetails user_id
http://sqlfiddle.com/#!9/90d4ac/18
schema:
CREATE TABLE `userdetails` (
`user_id` int(11) NOT NULL,
`first_name` varchar(50) NOT NULL,
`last_name` varchar(50) DEFAULT NULL,
`country` varchar(30) DEFAULT NULL,
`avatar_img_name` varchar(30) DEFAULT NULL,
`record_status` int(1) NOT NULL COMMENT '1- active'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `userdetails`
ADD PRIMARY KEY (`user_id`);
INSERT INTO `userdetails` (`user_id`, `first_name`, `last_name`, `country`, `avatar_img_name`, `record_status`) VALUES
(1, 'Admin', 'Admin', 'India', NULL, 0),
(54, 'Prince', 'Lal', 'Nepal', 'p.jpg', 1),
(55, 'ashutosh', 'Singh', 'Afganistan', 'a.jpg', 1),
(56, 'Rekha', 'Gupta', 'United States', 'r.jpg', 1),
(57, 'Nirmal', NULL, NULL, NULL, 1);
CREATE TABLE `user_follow` (
`id` int(11) NOT NULL,
`following_user_id` int(11) NOT NULL,
`followed_user_id` int(11) NOT NULL,
`created_date` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `user_follow` (`id`, `following_user_id`, `followed_user_id`, `created_date`) VALUES
(1, 55, 56, '2021-02-07 02:14:26'),
(2, 55, 54, '2021-02-06 01:14:26'),
(3, 54, 55, '2021-02-07 10:33:45'),
(4, 57, 55, '2021-02-07 00:00:00');
ALTER TABLE `user_follow`
ADD PRIMARY KEY (`id`),
ADD KEY `following_user_id` (`following_user_id`),
ADD KEY `followed_user_id` (`followed_user_id`);
ALTER TABLE `user_follow`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
ALTER TABLE `user_follow`
ADD CONSTRAINT `user_follow_ibfk_1` FOREIGN KEY (`followed_user_id`) REFERENCES `userdetails` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `user_follow_ibfk_2` FOREIGN KEY (`following_user_id`) REFERENCES `userdetails` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT;
query:
SELECT
u.user_id, u.first_name, u.last_name, u.country,
(SELECT COUNT(*) FROM user_follow uf1 WHERE uf1.followed_user_id=u.user_id) AS followerscount,
(SELECT COUNT(*) FROM user_follow uf2 WHERE uf2.following_user_id=u.user_id) AS followingcount,
IF(
EXISTS(SELECT * FROM user_follow uf3 -- if I'm following the specified user
WHERE uf3.following_user_id=55 AND uf3.followed_user_id=u.user_id),
'Unfollow', -- then show 'unfollow button'
IF(
EXISTS(SELECT * FROM user_follow uf4 -- if the specified user is following me
WHERE uf4.followed_user_id=55 AND uf4.following_user_id=u.user_id),
'Follow Back', -- then show 'follow back button'
'Follow') -- then show 'follow button'
) AS ButtonText
FROM
userdetails u
WHERE
u.user_id<>55
AND u.user_id<>1 -- should not select the admin user
explanation: it seems that the expected table is based on "userdetails" table, so you should only select "userdetails" in FROM clause, and add other column with subquery in SELECT clause

SQL query not returning correct result using three table together?

I have 3 tables in which tbl_user_signup_info, tbl_main_lead_info and tbl_campaign_info, I need a result in which it display info such that each row display the lead id and campaign id added by corresponding registered users of the tbl_user_signup_info and display should be like User_Id, Lead_Id, Campaign_ID.
Actually i want Total number of leads added by particular user with there Lead Id and Total number of campaign added by that user with there Campaign_Id using those 3 tables.
But i am lacking to form SQL query.
My Result are as below which are wrong:
Table structure
--
-- Table structure for table `tbl_campaign_info`
--
DROP TABLE IF EXISTS `tbl_campaign_info`;
CREATE TABLE IF NOT EXISTS `tbl_campaign_info` (
`Campaign_Id` int(100) NOT NULL AUTO_INCREMENT,
`CampaignName` varchar(200) NOT NULL,
`CampaignStatus` varchar(200) NOT NULL,
`CampaignDescription` varchar(200) DEFAULT NULL,
`CampaignOwnerNotes` varchar(200) DEFAULT NULL,
`CampaignAdminNotes` varchar(200) DEFAULT NULL,
`CampaignStartDate` date NOT NULL,
`CampaignEndDate` date NOT NULL,
`CampaignLead_Id` int(100) NOT NULL,
`CampaignAddedBy` int(100) NOT NULL,
`CampaignAddedOn` date DEFAULT NULL,
UNIQUE KEY `Campaign_Id` (`Campaign_Id`)
) ENGINE=MyISAM AUTO_INCREMENT=18 DEFAULT CHARSET=latin1;
--
-- Table structure for table `tbl_main_lead_info`
--
DROP TABLE IF EXISTS `tbl_main_lead_info`;
CREATE TABLE IF NOT EXISTS `tbl_main_lead_info` (
`Lead_Id` int(100) NOT NULL AUTO_INCREMENT,
`FirstName` varchar(100) DEFAULT NULL,
`LastName` varchar(100) DEFAULT NULL,
`Company` varchar(100) DEFAULT 'NA',
`Website` varchar(100) DEFAULT 'NA',
`Designation` varchar(100) DEFAULT 'NA',
`Linkedin` varchar(100) DEFAULT 'NA',
`Email` varchar(100) DEFAULT NULL,
`Phone` varchar(100) DEFAULT NULL,
`State` varchar(100) DEFAULT NULL,
`Country` varchar(100) DEFAULT NULL,
`TechArea` varchar(100) DEFAULT NULL,
`FirmType` varchar(100) DEFAULT NULL,
`FirmSize` varchar(100) DEFAULT NULL,
`LastContactDate` date DEFAULT NULL,
`NextContactDate` date DEFAULT NULL,
`LeadDescription` varchar(200) DEFAULT NULL,
`OwnerNotes` varchar(200) DEFAULT NULL,
`SetReminder` date DEFAULT NULL,
`AdminNotes` varchar(200) DEFAULT NULL,
`LeadStatus` varchar(100) DEFAULT NULL,
`LeadAddedBy` int(100) NOT NULL,
`LeadAddedOn` datetime DEFAULT NULL,
PRIMARY KEY (`Lead_Id`),
UNIQUE KEY `FirstName` (`FirstName`,`LastName`,`Company`,`Website`,`Designation`,`Linkedin`,`Email`,`Phone`)
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=latin1;
--
-- Dumping data for table `tbl_main_lead_info`
--
INSERT INTO `tbl_main_lead_info` (`Lead_Id`, `FirstName`, `LastName`, `Company`, `Website`, `Designation`, `Linkedin`, `Email`, `Phone`, `State`, `Country`, `TechArea`, `FirmType`, `FirmSize`, `LastContactDate`, `NextContactDate`, `LeadDescription`, `OwnerNotes`, `SetReminder`, `AdminNotes`, `LeadStatus`, `LeadAddedBy`, `LeadAddedOn`) VALUES
(15, 'John', 'Doe', 'test', 'test', 'test', 'test', 'test', 'test', 'Texas', 'USA', 'test', 'Corporate', '11-50', '2020-01-09', '2020-01-10', 'Testing Description of Lead information', NULL, '2020-01-11', 'This need to be confidential by admin', 'Active', 18, '2020-01-09 16:07:17');
--
-- Dumping data for table `tbl_campaign_info`
--
INSERT INTO `tbl_campaign_info` (`Campaign_Id`, `CampaignName`, `CampaignStatus`, `CampaignDescription`, `CampaignOwnerNotes`, `CampaignAdminNotes`, `CampaignStartDate`, `CampaignEndDate`, `CampaignLead_Id`, `CampaignAddedBy`, `CampaignAddedOn`) VALUES
(16, 'Test', 'Active', 'Test', NULL, 'This is admin notes and need to be kept confidential', '2020-01-09', '2020-01-10', 15, 18, '2020-01-09'),
(17, 'Test', 'Active', 'Test ', NULL, 'NA', '2020-01-10', '2020-01-10', 15, 18, '2020-01-09');
--
-- Table structure for table `tbl_user_signup_info`
--
DROP TABLE IF EXISTS `tbl_user_signup_info`;
CREATE TABLE IF NOT EXISTS `tbl_user_signup_info` (
`User_Id` int(50) NOT NULL AUTO_INCREMENT,
`UserEmail` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`UserName` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`UserPassword` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`Admin` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`User_Id`) USING BTREE,
UNIQUE KEY `Email` (`UserEmail`),
UNIQUE KEY `UserName` (`UserName`),
UNIQUE KEY `UserEmail` (`UserEmail`,`UserName`)
) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `tbl_user_signup_info`
--
INSERT INTO `tbl_user_signup_info` (`User_Id`, `UserEmail`, `UserName`, `UserPassword`, `Admin`) VALUES
(18, 'test#gmail.com', 'test', 'test', 1),
(22, 'test1#gmail.com', 'test1', 'test1', 0),
(23, 'test2#gmail.com', 'test2', 'test2', 0);
COMMIT;
and My SQl Query is as below:
SELECT User_Id, Campaign_Id, Lead_Id
FROM tbl_campaign_info AS C,
tbl_main_lead_info AS M,
tbl_user_signup_info AS U
WHERE C.CampaignAddedBy IN ( SELECT User_Id
FROM tbl_user_signup_info AS U,
tbl_campaign_info AS C
WHERE U.User_Id = C.CampaignAddedBy)
AND M.LeadAddedBy IN (SELECT User_Id
FROM tbl_user_signup_info AS U,
tbl_main_lead_info AS M
WHERE U.User_Id = M.LeadAddedBy )
If I understand correctly, you want users campaign counts and lead counts per user. So, select campaign counts, select lead counts, join them.
You could use a full outer join of the two results for this (thus getting only those users that have at least one campain or lead), but MySQL doesn't support it. I take it that tbl_user_signup_info contains one row per user, though, so you can use this as a base table. The following query gives you a result for every user in that table.
select
u.user_id,
coalesce(c.total, 0) as campaign_count,
coalesce(l.total, 0) as lead_count
from tbl_user_signup_info u
left join
(
select campaignaddedby, count(*) as total
from tbl_campaign_info
group by campaignaddedby
) c on c.campaignaddedby = u.user_id
left join
(
select leadaddedby, count(*) as total
from tbl_main_lead_info
group by leadaddedby
) l on l.leadaddedby = u.user_id
order by u.user_id;
It seems like you can only use JOIN.
SELECT U.User_Id, Campaign_Id, Lead_Id
FROM tbl_user_signup_info AS U
JOIN tbl_campaign_info AS C ON U.User_Id = C.CampaignAddedBy
JOIN tbl_main_lead_info AS M ON U.User_Id = M.LeadAddedBy
Actually i want Total number of leads added by particular user with
there Lead Id and Total number of campaign added by that user with
there Campaign_Id using those 3 tables.
Try this:
SELECT
X.USER_ID,
X.LeadCount,
IF(Y.LEAD_ID IS NULL, 0, Y.LEAD_ID) LEAD_ID,
IF(Y.CampaignCount IS NULL, 0, Y.CampaignCount) CampaignCount
FROM (
SELECT
U.User_ID, COUNT(DISTINCT LEAD_ID) LeadCount
FROM
tbl_user_signup_info U
LEFT JOIN
tbl_main_lead_info M
ON (U.User_Id = M.LeadAddedBy)
GROUP BY
U.USER_ID
) X
LEFT JOIN
(
SELECT
M.LeadAddedBy, M.LEAD_ID, COUNT(DISTINCT Campaign_Id) CampaignCount
FROM
tbl_campaign_info C
LEFT JOIN
tbl_main_lead_info M
ON (C.CampaignAddedBy = M.LeadAddedBy)
GROUP BY
M.LeadAddedBy, M.LEAD_ID
) Y
ON (
X.USER_ID = Y.LeadAddedBy
)
SQL Fiddle link: http://sqlfiddle.com/#!9/4e138/40

why category name is null when select join with enry table

i have two tables ...first is entry
CREATE TABLE IF NOT EXISTS `entry` (
`entry_id` int(11) NOT NULL AUTO_INCREMENT,
`entry_cat_id` int(11) NOT NULL,
`entry_name` varchar(255) NOT NULL,
`entry_body` text NOT NULL,
`img_url` varchar(255) NOT NULL,
`image_link` varchar(255) NOT NULL,
`entry_state` tinyint(1) DEFAULT '0',
`comment_count` int(11) NOT NULL DEFAULT '0',
`entry_count` int(11) NOT NULL DEFAULT '0',
`entry_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`entry_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=41 ;
--
-- Dumping data for table `entry`
--
INSERT INTO `entry` (`entry_id`, `entry_cat_id`, `entry_name`, `entry_body`, `img_url`, `image_link`, `entry_state`, `comment_count`, `entry_count`, `entry_created`) VALUES
(27, 15, 'title fot entry', 'content', '', '', 0, 0, 0, '2013-04-14 14:47:56');
and the escond is entry_category
CREATE TABLE IF NOT EXISTS `entry_category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`category_name` varchar(150) NOT NULL,
`slug` varchar(150) NOT NULL,
`cat_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16 ;
--
-- Dumping data for table `entry_category`
--
INSERT INTO `entry_category` (`category_id`, `category_name`, `slug`, `cat_created`) VALUES
(10, 'rrrrrrrr', 'rrrrrrr', '0000-00-00 00:00:00'),
(15, 'gggggg', 'ttttttttt', '2012-12-10 13:47:28');
when select with inner join to get the category and entry name i see category_name is null
SELECT entry.entry_id, entry_category.category_name, entry.entry_name
FROM entry
INNER JOIN entry_category
ON entry.entry_id=entry_category.category_id;
why and what i shall do to see the the category name
join is having wrong clause
you need to join on category_id but in entry table category_id is in entry_cat_id field so you can join like this
SELECT entry.entry_id, entry_category.category_name, entry.entry_name
FROM entry
INNER JOIN entry_category
ON entry.entry_cat_id=entry_category.category_id;
I think you are joining on the wrong field. You are joining on the entry.entry_id field when I think you want to be joining on the entry.entry_cat_id field.
Try changing your query to:
SELECT entry.entry_id, entry_category.category_name, entry.entry_name
FROM entry
INNER JOIN entry_category
ON entry.entry_cat_id=entry_category.category_id;
BTW -- your existing query shouldn't return any results from your sample data. To see NULL records from your entry_category table, you'd need to use an OUTER JOIN.

Is it possible to achieve this selection with a single query?

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..
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');