Multiple LEFT JOIN doesn't work on SUM() - php

So the idea is to get information from 3 tables:
R_Regle: rule table, basic info of the rule
C_Commentaire: the number of comments this rule has
I_Interet: The SUM of all upvotes and downvotes from one rule.
The structure of my I_Interet:
I_ID / I_Idregle / I_Idpseudo / I_Upvote / I_Downvote
Each row can only contain 1 upvote or 1 downvote.
so with this request:
SELECT R_Id, R_Date, R_Titre, R_Contenu, R_Etape, COUNT(C_Commentaire.C_IdRegle) AS CountComment, SUM(I_Interet.I_Up) AS Up ,SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN C_Commentaire ON C_Commentaire.C_IdRegle = R_Regle.R_Id
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = R_Regle.R_Id
GROUP BY R_ID
I try to obtain all those information.
Problem is:
COUNT(C_Commentaire.C_IdRegle) AS CountComment
Gives me the count of all COMMENTS and UPVOTES/DOWNVOTES.
So if there are 4 comments and 3 downvotes, it will count it like that
$row['CountComment'] = 7;
But obviously, I don't want that. I want
$row['CountComment'] = 4;
Any ideas?
EDIT 1:
Here are the tables:
R_REGLE
CREATE TABLE `R_Regle` (
`R_Id` int(11) NOT NULL AUTO_INCREMENT,
`R_Auteur` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`R_Date` date NOT NULL,
`R_Titre` varchar(150) CHARACTER SET latin1 NOT NULL,
`R_Contenu` text CHARACTER SET latin1 NOT NULL,
`R_Etape` int(11) NOT NULL DEFAULT '1' COMMENT '1 = discussion 2= VOTE',
PRIMARY KEY (`R_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
C_COMMENTAIRE
CREATE TABLE `C_Commentaire` (
`C_Id` int(11) NOT NULL AUTO_INCREMENT,
`C_Date` datetime NOT NULL,
`C_Pseudo` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`C_Contenu` text COLLATE utf8_unicode_ci NOT NULL,
`C_IdRegle` int(11) NOT NULL,
PRIMARY KEY (`C_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I_INTERET
CREATE TABLE `I_Interet` (
`I_Id` int(11) NOT NULL AUTO_INCREMENT,
`I_IdRegle` int(11) NOT NULL,
`I_Pseudo` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`I_Up` tinyint(1) NOT NULL DEFAULT '0',
`I_Down` tinyint(1) DEFAULT '0',
PRIMARY KEY (`I_Id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

I can suggest using correlated query.. not sure if thats what you want since you didn't post any table structures its hard to know :
SELECT R_Id, R_Date, R_Titre, R_Contenu, R_Etape,
(select COUNT(*) from C_Commentaire where C_Commentaire.C_IdRegle = R_Regle.R_Id) AS CountComment,
SUM(I_Interet.I_Up) AS Up ,
SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = R_Regle.R_Id
GROUP BY R_ID

Write your query as below:
SELECT R_Regle.R_Id, R_Regle.R_Date, R_Regle.R_Titre, R_Regle.R_Contenu, R_Regle.R_Etape,
COUNT(C_Commentaire.C_IdRegle) AS CommentCounts,
SUM(I_Interet.I_Up) AS Up,
SUM(I_Interet.I_Down) AS Down
FROM R_Regle
LEFT JOIN C_Commentaire ON R_Regle.R_Id = C_Commentaire.C_IdRegle
LEFT JOIN I_Interet ON R_Regle.R_Id = I_Interet.I_IdRegle
GROUP BY R_Regle.R_ID

In your query there are duplicate records arisen when you make a left join among the three tables.
The following query is one of few ways to achieve your desired result.
SELECT
t.*,
SUM(I_Interet.I_Up) AS Up,
SUM(I_Interet.I_Down) AS Down
FROM
(
SELECT
R_Id,
R_Date,
R_Titre,
R_Contenu,
R_Etape,
COUNT(c_commentaire.C_IdRegle) countComment
FROM
R_Regle LEFT JOIN C_Commentaire ON C_Commentaire.C_IdRegle = R_Regle.R_Id
GROUP BY R_Regle.R_Id ) t
LEFT JOIN I_Interet ON I_Interet.I_IdRegle = t.R_Id
GROUP BY t.R_Id

Related

how can i join 3 tables in mysql php

I have 3 tables tags,tag_type,user_alert
table structure is as follows:
CREATE TABLE `tags` (
`tag_id` int(11) NOT NULL,
`tag_name` varchar(255) CHARACTER SET utf8 NOT NULL,
`tagtype_id` int(11) NOT NULL,
`status` tinyint(1) NOT NULL,
`is_deleted` tinyint(1) NOT NULL,
`created_at` datetime NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
CREATE TABLE IF NOT EXISTS `tag_types` (
`tagtype_id` int(11) NOT NULL,
`tagtype_name_en` varchar(100) CHARACTER SET utf8 NOT NULL,
`tagtype_name_fr` varchar(100) NOT NULL,
`display_order` int(11) NOT NULL,
`tag_color` varchar(50) CHARACTER SET utf8 NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '1',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
CREATE TABLE IF NOT EXISTS `user_alert` (
`user_alert_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`is_removed` enum('yes','no') DEFAULT 'no',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;
I have created query, but it is not working for me.
select t.tag_name,t.tag_id,ty.tag_color,ty.tagtype_name_en as tagtype_name from tags as t INNER JOIN tag_types as ty ON t.tagtype_id=ty.tagtype_id INNER JOIN user_alert as ua ON ua.tag_id != t.tag_id where t.tagtype_id='5' and ua.user_id != '14'
I want to make query such that
I am passing tagtype_id and user_id
when I pass tagtype_id I can get all tag which belongs to that tagtyped_id and don not want to select tags in which user has subscribed.
but I am not able to do it.I know the answer will be simple but don't know how to do it.can anybody please help me?
In JOIN, you must use "=" and dont use "!=".
your condition must apply in where statement NOT in join.
Maybe this is what you are looking for (untested as i don't have this DB)
select t.tag_name,
t.tag_id,
ty.tag_color,
ty.tagtype_name_en as tagtype_name
from tags as t
INNER JOIN user_alert as ua
ON ua.tag_id <> t.tag_id
INNER JOIN tag_types as ty
ON ua.tag_id = ty.tagtype_id
where t.tagtype_id = '5'
and ua.user_id <> '14
Assuming the Table definition you supplied here is accurate; the problem is that you don't have a tagtype_name_en Field in your "tag_types" table and you are trying to access it while it doesn't exist.
// YOUR TABLE DEFINITION/COLUMNS:::
TABLE 1 - tags:
tag_id
tag_name
tagtype_id
TABLE 2 - tag_types
tagtype_id
tag_color
tagtype_name_en
TABLE 3 - user_alert
tag_id
user_id
UPDATE: ADDED GROUP BY CLAUSE
$sql = "SELECT
t.tag_name, t.tag_id,
ty.tag_color,ty.tagtype_name_en AS tagtype_name
FROM tags AS t
LEFT JOIN tag_types AS ty ON t.tagtype_id=ty.tagtype_id
LEFT JOIN user_alert AS ua ON ua.tag_id!=t.tag_id
GROUP BY t.tag_id
WHERE t.tagtype_id='5' AND ua.user_id != '14'";
Why dont you try with this <> not equal to operator instead of !=
SELECT * FROM `tags` AS `t` INNER JOIN `tag_types` AS `ty` ON t.tagtype_id = ty.tagtype_id INNER JOIN `user_alert` AS `ua` ON ua.tag_id <> t.tag_id WHERE t.tagtype_id = '5' AND ua.user_id <> '14'
UPDATED
Try this "LEFT JOIN"
SELECT * FROM `tags` AS `t` INNER JOIN `tag_types` AS `ty` ON t.tagtype_id = ty.tagtype_id LEFT JOIN `user_alert` AS `ua` ON ua.tag_id = t.tag_id WHERE t.tagtype_id = '5' AND ua.user_id <> '14' AND ua.tag_id IS NULL

Issues with SQL JOIN failing

I have the following JOIN I am attempting to create.
SELECT rating_draft_result.COUNT(id), rating_draft_result.user_id, rating_draft_result.result
FROM rating_draft_result
INNER JOIN users ON
rating_draft_result.user_id, rating_draft_result.result = users.id
I am trying to COUNT the total id's of the rating_draft_result table and then also SELECT the user_id and result from that table. Then I am trying to match the user_id and result from the rating_draft_result table to the user's id column. Then I want to get the username from the user's table where the id matches, but I can't figure that part out and I am getting an error anyways with the following code.
I get the following error..
Survey SELECT total count prepare() failed: You have an error in your
SQL syntax; check the manual that corresponds to your MySQL server
version for the right syntax to use near '.id' at line 4
My database tables look like this...
users
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`lastname` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`phone_number` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
`username` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`salt` varchar(32) COLLATE utf8_unicode_ci NOT NULL,
`joined` datetime NOT NULL,
`group` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
rating_draft_result
CREATE TABLE `rating_draft_result` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`result` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
What am I doing wrong in my query?
DESIRED OUTPUT:
users
CREATE TABLE users (
id``firstname``lastname``email``phone_number``username``password``salt``joined group
1 Jack Johnson jack#email.com 2222 jackusername ffd fdddfd today 1
10 Tom Thompson fdfdfddf#fef.com 5555 Tomusername
rating_draft_result
`id` `user_id` `result`
20 1 10
I want to be able to match the rating_draft_result's user_id and result with the user table's id field.
So I want to get the jackusername and tomusername fields.
Check JOIN condition
SELECT rating_draft_result.user_id, rating_draft_result.result, COUNT(*)
FROM rating_draft_result
INNER JOIN users
ON rating_draft_result.user_id = users.id
GROUP BY rating_draft_result.user_id, rating_draft_result.result;
You have
ON rating_draft_result.user_id, rating_draft_result.result = users.id
The problem is in your JOIN ON clause. You need to change it like
INNER JOIN users ON
rating_draft_result.user_id = users.id
(OR) If you want to have both the conditions then use a AND operator like
FROM rating_draft_result
INNER JOIN users ON
rating_draft_result.user_id = users.id
AND rating_draft_result.result = users.id
Change your entire query to be like below
SELECT COUNT(rating_draft_result.id),
rating_draft_result.user_id,
rating_draft_result.result
FROM rating_draft_result
INNER JOIN users ON
rating_draft_result.user_id = users.id
AND rating_draft_result.result = users.id;

MySQL Select rows where the user has not voted yet (contest app)

I have a photo contest app where users can vote. I would like to select all of the contests where the logged in user has not voted yet.
So I have two tables.
The "contest" table :
CREATE TABLE `contest` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
`title` varchar(255) NOT NULL,
`desc` text NOT NULL,
`created_date` datetime NOT NULL,
`started_date` datetime NOT NULL,
`nb_user_min` int(11) NOT NULL,
`nb_photo_max` int(11) NOT NULL,
`nb_photo_per_user` int(11) NOT NULL,
`duration` int(11) DEFAULT NULL,
`status` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
The "contest_vote" table :
CREATE TABLE `contest_vote` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`pic_id` int(11) DEFAULT NULL,
`contest_id` int(11) DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`date` datetime DEFAULT NULL,
`ip` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
So to be clear, I want to get the number (or the list) of contests where the user has not voted yet. So I have tried with a LEFT JOIN but it doesn't return the good set of result. Here it the query I have until now :
SELECT DISTINCT c.id, c.title, cv.user_id
FROM contest c
LEFT JOIN contest_vote cv
ON cv.contest_id = c.id AND cv.user_id != ?
GROUP BY contest_id
("?" represents the user_id parameter).
Can you help me to solve this?
This is pretty simple do with a subquery. Just grab all contest without where user is voted like this:
SELECT DISTINCT c.id, c.title
FROM contest c
WHERE c.id NOT IN (SELECT DISTINCT cv.contest_id FROM contest_vote cv WHERE cv.user_id = ?)
Try this one :
SELECT DISTINCT c.id, c.title, cv.user_id
FROM contest c
LEFT JOIN contest_vote cv ON cv.contest_id = c.id AND cv.user_id != ? WHERE c.user_id = ?
GROUP BY contest_id

i want to use left and inner join in 3 tables in mysql?

these are my tables. first one is appusers table.
CREATE TABLE IF NOT EXISTS `appusers` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(50) NOT NULL,
`is_active` tinyint(2) NOT NULL DEFAULT '0',
`zip` varchar(20) NOT NULL,
`city` text NOT NULL,
`country` text NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=23 ;
second table is stickeruses table.
CREATE TABLE IF NOT EXISTS `stickeruses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`sticker_id` int(11) NOT NULL,
`count` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=24 ;
Third table is Devices
CREATE TABLE IF NOT EXISTS `devices` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`regid` varchar(300) NOT NULL,
`imei` varchar(50) NOT NULL,
`device_type` tinyint(2) NOT NULL,
`notification` tinyint(2) NOT NULL DEFAULT '1',
`is_active` tinyint(2) NOT NULL DEFAULT '0',
`activationcode` int(6) NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=28 ;
I Want to find the Sum(stickeruses.count) and COUNT(devices.id) for all appusers.
Here is my query.
SELECT `Appuser`.`id`, `Appuser`.`email`, `Appuser`.`country`, `Appuser`.`created`,
`Appuser`.`is_active`, SUM(`Stickeruse`.`count`) AS total, COUNT(`Device`.`id`)
AS tdevice
FROM `stickerapp`.`appusers` AS `Appuser`
LEFT JOIN `stickerapp`.`stickeruses` AS `Stickeruse`
ON (`Stickeruse`.`user_id`=`Appuser`.`id`)
INNER JOIN `stickerapp`.`devices` AS `Device`
ON (`Device`.`user_id`=`Appuser`.`id`)
WHERE `Appuser`.`is_active` = 1
GROUP BY `Appuser`.`id`
LIMIT 10
When I am applying each join separately the results are right, but I want to combine both joins. And when I am doing it then results are wrong. please help.
When mixing JOIN and LEFT JOIN it is a good idea to use parentheses to make it clear what your intent is.
I don't know what you need, but these syntaxes might give you different results:
FROM a LEFT JOIN ( b JOIN c ON b..c.. ) bc ON a..bc..
FROM ( a LEFT JOIN b ON a..b.. ) ab JOIN c ON ab..c..
Also, you can rearrange them do FROM a JOIN c LEFT JOIN b (plus parentheses) or any of several other arrangements. Granted, some pairs rearrangements are equivalent.
Also, beware; aggregates (such as SUM()) get inflated values when JOINing. Think of it this way: first the JOINs get all appropriate combinations of rows from the tables, then the SUM adds them up. With that in mind, see if this works better:
SELECT a.`id`, a.`email`, a.`country`, a.`created`, a.`is_active`,
( SELECT SUM(`count`)
FROM stickerapp.stickeruses
WHERE user_id = a.id
) AS total,
( SELECT COUNT(*)
FROM stickerapp.devices
WHERE user_id = a.id
) AS tdevice
FROM stickerapp.`appusers` AS a
WHERE a.`is_active` = 1
GROUP BY a.`id`
LIMIT 10

"my network" function with sql subquery

I need a little help for one sql query;
here is my basic user database table
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(100) NOT NULL,
`pass` varchar(255) NOT NULL,
`fname` varchar(50) NOT NULL,
`lname` varchar(40) NOT NULL,
`network` varchar(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=27 ;
and here is my basic topics database table
CREATE TABLE IF NOT EXISTS `topics` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` varchar(100) NOT NULL,
`title` varchar(255) NOT NULL,
`body` text,
`tags` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
What I'm trying to do is;
i.e. list all topics from users who joined "harvard" network
You just need a simple JOIN. Join the tables on the userID (of those who are in "harvard").
SELECT title,body
FROM topics, users
WHERE userid = users.id
AND network = 'harvard'
Or using the JOIN keyword:
SELECT title,body
FROM topics
JOIN users ON userid = users.id
WHERE network = 'harvard'
This should do the trick, I think:
SELECT
title
FROM
topics t
INNER JOIN
users u ON t.userid=u.id
WHERE
network='Harvard'
SELECT t.title
FROM users u
INNER JOIN topics t ON u.id = t.userid
WHERE u.network = 'harvard'
GROUP BY u.id

Categories