Select all possible children with parent in mysql - php

I have a users table.
I have a certifications table.
Each user can have multiple certifications. Certifications has a user_id foreign key.
How may I select a user as well as all of their certifications in one query?
How may I select users that have certifications?
users table:
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL auto_increment,
`username` varchar(24) default NULL,
`displayname` varchar(24) default NULL,
`email` varchar(64) default NULL,
`password` text,
`signup_date` int(11) default NULL,
`signup_ip` varchar(15) default NULL,
`hash` text,
`verified` tinyint(1) default '0',
`last_login` int(11) default NULL,
`logins` int(11) default NULL,
`status` text,
`recovery_hash` text,
`recovery_initiated` int(11) default NULL,
`last_updated` int(11) default NULL,
`signup_method` text,
`signup_question` int(11) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
certifications table:
CREATE TABLE `certifications` (
`id` int(11) unsigned NOT NULL auto_increment,
`user_id` int(11) unsigned NOT NULL,
`number` varchar(128) default NULL,
`board` varchar(128) default NULL,
`company` varchar(128) default NULL,
`website` varchar(128) default NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `certifications_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
Thank you for reading.

How may I select a user as well as all of their certifications in one query?
SELECT *
FROM certifivations C
LEFT JOIN users U
ON C.user_id = U.id
WHERE U.id=USERID
How may I select users that have certifications?
SELECT *
FROM certifivations C
JOIN users U
ON C.user_id = U.id
GROUP BY U.id

Get all the certifications of user with id of 1 by using a join.
SELECT b.id as certification_id
FROM users AS a
LEFT JOIN certifications AS b
ON a.id = b.user_id
WHERE a.id = 1;
Get all the users that have certifications using an inner join. All users without certs will drop out.
SELECT a.id as users_with_certifications
FROM users as a
JOIN certifications AS b
ON a.id = b.user_id;

Related

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

MySQL - GROUP BY slow down the page

GROUP BY clause in the query below slow down the page, please help to resolve this issue
SELECT
`a`.*,
CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
CONCAT(f.`firstname`, " ", f.`lastname`) AS `created_by`
FROM
`contacts` AS `a`
LEFT JOIN `users` AS `f` ON f.id = a.user_id
LEFT JOIN `user_centres` AS `b` ON a.user_id = b.user_id
WHERE b.centre_id IN (23, 24, 25, 26, 20, 21, 22, 27, 28)
GROUP BY `a`.`id`
ORDER BY `a`.`created` desc
Here the join with user_centres table is for centre wise filtering of data. EXPLAIN gives the result as:
- 1 SIMPLE a index PRIMARY,user_id,area_id,industry_id,country PRIMARY 4 NULL 20145 Using temporary; Using filesort
Our requirement is as below
Listing of all contacts in admin login
Centre wise listing of contacts in manager/clerk login
Total records in contact table is > 20K.
There will be multiple entry for users in user_centres table, ie: a user is assigned to more than one centre.
While executing the query in server by excluding GROUP BY is nearly 300k data which makes the problem.
Db stucture
Table structure for table contacts
CREATE TABLE IF NOT EXISTS `contacts` (
`id` int(11) NOT NULL,
`user_id` int(11) DEFAULT NULL,
`imported` tinyint(4) NOT NULL DEFAULT '0',
`situation` char(10) DEFAULT NULL,
`firstname` varchar(150) DEFAULT NULL,
`lastname` varchar(150) DEFAULT NULL,
`position` varchar(150) DEFAULT NULL,
`dob` datetime DEFAULT NULL,
`office_contact` varchar(100) DEFAULT NULL,
`mobile_contact` varchar(100) DEFAULT NULL,
`email` varchar(255) NOT NULL,
`company` varchar(150) DEFAULT NULL,
`industry_id` int(11) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`city` varchar(150) DEFAULT NULL,
`country` int(11) DEFAULT NULL,
`isclient` tinyint(4) NOT NULL DEFAULT '0',
`classification` varchar(100) DEFAULT NULL,
`created` datetime NOT NULL,
`updated` datetime NOT NULL,
`unsubscribe` enum('Y','N') NOT NULL DEFAULT 'N'
) ENGINE=InnoDB AUTO_INCREMENT=25203 DEFAULT CHARSET=latin1;
Indexes for table contacts
ALTER TABLE `contacts`
ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
ADD KEY `industry_id` (`industry_id`), ADD KEY `country` (`country`);
Constraints for table contacts
ALTER TABLE `contacts`
ADD CONSTRAINT `contacts_ibfk_4` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
ADD CONSTRAINT `contacts_ibfk_6` FOREIGN KEY (`industry_id`)
REFERENCES `industries` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION,
ADD CONSTRAINT `contacts_ibfk_7` FOREIGN KEY (`country`)
REFERENCES `country` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
Table structure for table users
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
`email` varchar(250) NOT NULL,
`password` varchar(45) NOT NULL,
`salt` varchar(45) DEFAULT NULL,
`status_id` int(11) DEFAULT NULL,
`status` tinyint(1) DEFAULT '1',
`firstname` varchar(255) NOT NULL,
`lastname` varchar(255) NOT NULL,
`created` datetime DEFAULT NULL,
`updated` datetime DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1;
Indexes for table users
ALTER TABLE `users`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `email_UNIQUE` (`email`),
ADD KEY `type_id_idx` (`role_id`), ADD KEY `status_id_idx` (`status_id`);
Constraints for table users
ALTER TABLE `users`
ADD CONSTRAINT `role_id` FOREIGN KEY (`role_id`)
REFERENCES `users_roles` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `status_id` FOREIGN KEY (`status_id`)
REFERENCES `users_status` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
ADD CONSTRAINT `users_ibfk_1` FOREIGN KEY (`area`)
REFERENCES `area` (`id`) ON DELETE SET NULL ON UPDATE NO ACTION;
Table structure for table user_centres
CREATE TABLE IF NOT EXISTS `user_centres` (
`id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`area_id` int(11) NOT NULL,
`centre_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=72 DEFAULT CHARSET=utf8;
Indexes for table user_centres
ALTER TABLE `user_centres`
ADD PRIMARY KEY (`id`), ADD KEY `user_id` (`user_id`),
ADD KEY `centre_id` (`centre_id`), ADD KEY `area_id` (`area_id`);
Constraints for table user_centres
ALTER TABLE `user_centres`
ADD CONSTRAINT `user_centres_ibfk_1` FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
ADD CONSTRAINT `user_centres_ibfk_2` FOREIGN KEY (`centre_id`)
REFERENCES `centre` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
Also please refer EXPLAIN screens - http://prntscr.com/6o5h8s
Index were not used because of the different ORDER BY a GROUP BY clauses.
http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
You are spending a lot of time checking user_centres, but not needing anything from it. Remove it from the query.
users can be made into a correlates subquery:
SELECT `a`.*,
CONCAT(a.`firstname`, " ", a.`lastname`) AS `cont_name`,
CONCAT(a.`position`, " / ", a.`company`) AS `comp_pos`,
( SELECT CONCAT(f.`firstname`, " ", f.`lastname`)
FROM `users` AS `f` ON f.id = a.user_id
) AS `created_by`
FROM `contacts` AS `a`
GROUP BY `a`.`id`
ORDER BY `a`.`created` desc
Do you really need all 20K rows?? The sheer bulk of the result is part of the sluggishness.
Thanks all, based on the feedback got from all of you I have tried the query below now and give me the speed improvement from 30 secs to 15 secs
SELECT `a`.`id`, `a`.`user_id`, `a`.`imported`, `a`.`created`,
`a`.`unsubscribe`, CONCAT(a.firstname, " ", a.lastname) AS `cont_name`,
CONCAT(a.position, " / ", a.company) AS `comp_pos`,
( SELECT COUNT(uc.id)
FROM `user_centres` AS `uc`
WHERE (uc.user_id = a.user_id)
AND (uc.centre_id IN (29))
GROUP BY `uc`.`user_id`
) AS `centre_cnt`,
( SELECT GROUP_CONCAT(DISTINCT g.group_name
ORDER BY g.group_name ASC SEPARATOR ", ")
FROM `groups` AS `g`
INNER JOIN `group_contacts` AS `gc` ON g.id = gc.group_id
WHERE (gc.contact_id = a.id)
GROUP BY `gc`.`contact_id`
) AS `group_name`,
( SELECT CONCAT(u.`firstname`, " ", u.`lastname`)
FROM `users` AS `u`
WHERE (u.id = a.user_id)
) AS `created_by`, `e`.`name` AS `industry_name`
FROM `contacts` AS `a`
LEFT JOIN `industries` AS `e` ON e.id = a.industry_id
WHERE (1)
HAVING (centre_cnt is NOT NULL)
ORDER BY `a`.`id` desc
Let me know Is there a way to improve the speed and make the page loading below 5 secs.
Please see the interface (noted the filtering and sorting fields) - http://prntscr.com/6q6q70

"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

MySQL JOIN query more tables and return more result in one select

I would question, sorry my bad english :(
I have multiple tables
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8_slovak_ci NOT NULL,
`password` varchar(200) COLLATE utf8_slovak_ci NOT NULL,
`status` tinyint(1) NOT NULL,
PRIMARY KEY (`id`,`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;
CREATE TABLE `user_acl` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_user` int(11) unsigned NOT NULL,
`group` smallint(5) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;
CREATE TABLE `user_profil` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(100) COLLATE utf8_slovak_ci NOT NULL,
`fullname` varchar(100) COLLATE utf8_slovak_ci NOT NULL,
`profil` text COLLATE utf8_slovak_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;
Query:
SELECT user.*, prf.*, acl.*
FROM (SELECT * FROM user LIMIT 1) AS user
LEFT JOIN user_acl AS acl ON (acl.id_user = user.id)
INNER JOIN user_profil AS prf ON (user.id = prf.id)
I have table user, user_acl, user_profil
table user and user_profil are indexed under id what is the common key
Table user_acl have id_usercommon key with table user (id) in the table but user_acl There are more rows for the table user and I need all rows from a table user_acl in one query.
You can get MySQL to combine values from multiple rows into one row with GROUP_CONCAT:
SELECT user.*, prf.*, GROUP_CONCAT(acl.id), GROUP_CONCAT(acl.group)
FROM user
LEFT JOIN user_acl AS acl ON (acl.id_user = user.id)
INNER JOIN user_profil AS prf ON (user.id = prf.id)
GROUP BY user.id;
You can't. You have to separate query, if you need more than one acl row to one user row.
[EDIT]: But if you need to to it with one query then you should use somekindof bitwise operations. http://codingrecipes.com/how-to-write-a-permission-system-using-bits-and-bitwise-operations-in-php

Categories