mysql select from one to many relation - mysql

I have two tables - Users and Products. User may have a few products. I need to select all products and show which user they belong.
How to solve it using mysql joins.
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`login` varchar(16) NOT NULL,
`password` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`price` decimal(10,2) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8
I've tried like this:
SELECT users.login FROM users LEFT JOIN products ON users.id=products.user_id;
But in this case it shows me only user logins, but i need to get product name, price and description as well.

SELECT p.name, p.price, p.description, group_concat(u.login) as users
FROM products p
LEFT JOIN users u ON u.id = p.user_id
GROUP BY p.name, p.price, p.description

Related

How to order by calculated column in mysql

It is very slow to order by calculated column. Like this one:
select
`users`.`id`,
`username`,
`about_me`,
(
select
count(*)
from
`interests`
inner join `users_interests` on `interests`.`id` = `users_interests`.`interest_id`
where
`users`.`id` = `users_interests`.`user_id`
and `interest_id` in (1, 2, 4) --this is ids of interests which authenticated user has chosen
) as `interests_count`
from
`users`
order by
`interests_count` desc
So in this query i am ordering users By interests which is best suiting authenticated user. And it is very slow in large data tables. Any ideas what will be alternative and much faster solution. Thanks in advance
EDIT
Users Table
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`roles_id` bigint(20) unsigned NOT NULL DEFAULT 2,
`username` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`about_me` varchar(70) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`status` tinyint(1) NOT NULL DEFAULT 0,
`email_verified_at` timestamp NULL DEFAULT NULL,
`password` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_username_unique` (`username`),
UNIQUE KEY `users_email_unique` (`email`),
KEY `users_roles_id_foreign` (`roles_id`),
CONSTRAINT `users_roles_id_foreign` FOREIGN KEY (`roles_id`) REFERENCES
`user_roles` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50102 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
Interests Table
CREATE TABLE `interests` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`interest_category_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `interests_interest_category_id_foreign` (`interest_category_id`),
CONSTRAINT `interests_interest_category_id_foreign` FOREIGN KEY
(`interest_category_id`) REFERENCES `interests_categories` (`id`) ON DELETE
CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
Pivot table between Users and Interests
CREATE TABLE `users_interests` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`interest_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `users_interests_user_id_foreign` (`user_id`),
KEY `users_interests_interest_id_foreign` (`interest_id`),
CONSTRAINT `users_interests_interest_id_foreign` FOREIGN KEY (`interest_id`) REFERENCES `interests` (`id`) ON DELETE CASCADE,
CONSTRAINT `users_interests_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=251552 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Without test data it's difficult to know if this would be faster than your current query, but you might find the use of a Common Table Expression (a.k.a. WITH clause) to be helpful here:
with cteCount AS (select ui.`user_id`,
count(*) as `interests_count`
from `interests` i
inner join `users_interests` ui
on i.`id` = ui.`interest_id`
where ui.`interest_id` in (1, 2, 4))
select u.`id`,
`username`,
`about_me`,
cc.`interests_count`
from `users` u
inner join cteCount cc
on cc.`user_id` = u.`id`
order by
cc.`interests_count` desc
The performance of this query will be affected by the presence or absence of indexes on the appropriate columns. Just glancing at it I'd say you should have the following indexes available:
interests
Index 1: id
users_interests
Index 1: interest_id
users
Index 1: id
Try to directly join and aggregate.
SELECT u.id,
u.username,
u.about_me,
count(ui.interest_id) interests_count
FROM users u
LEFT JOIN users_interests ui
ON ui.user_id = u.id
AND ui.interest_id IN (1, 2, 4)
GROUP BY u.id,
u.username,
u.about_me;
Additionally create an index supporting the aggregation.
CREATE INDEX users_id_username_about_me
ON users
(id,
username,
about_me);

Joining two tables with a LIKE statement

I am trying to join my tables with a LIKE STATEMENT and my current query is this :
SELECT
COUNT(comment_id) AS nb,
produit.nom
FROM
comments
INNER JOIN produit ON comments.comment_location like (select '%'+produit.id+'%')
GROUP BY
comment_location
and the SQL FOR THE TABLES is this :
table comments:
CREATE TABLE `comments` (
`comment_id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`comment_date` datetime NOT NULL,
`comment_content` varchar(255) NOT NULL,
`comment_location` varchar(255) NOT NULL,
PRIMARY KEY (`comment_id`),
KEY `user_id` (`user_id`),
CONSTRAINT `comments_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8
table produit :
CREATE TABLE `produit` (
`id` int(11) NOT NULL,
`nom` varchar(25) NOT NULL,
`description` varchar(200) NOT NULL,
`categorie` varchar(25) NOT NULL,
`image` varchar(200) NOT NULL,
`prix` float NOT NULL,
`quantite` int(11) NOT NULL,
`prix_initiale` float NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_CATEGORIE` (`categorie`),
CONSTRAINT `FK_CATEGORIE` FOREIGN KEY (`categorie`) REFERENCES `categorie` (`nom`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
my query does execute but doesn't return the table i was looking for
but if i try replacing produit.id in (select '%'+produit.id+'%') with a constant the table shows the corresponding rows .
What am i doing wrong
You need to modify query as below. You dont need SELECT again in the LIKE clause.
SELECT
COUNT(comment_id) AS nb,
produit.nom
FROM
comments
INNER JOIN produit ON comments.comment_location like CONCAT('%',produit.id,'%')
GROUP BY
comment_location
SELECT COUNT(comment_id) AS nb, produit.nom AS nom FROM comments INNER JOIN produit ON comments.comment_location LIKE CONCAT('%', produit.id, '%')
GROUP BY comment_location
by #Phil

How to use JOIN in advance MySQL query

So I have been struggling with this question for a while, and trying to figure out the best way to use JOIN to get the answer of finding the "CertCount" per planet. I know that it wants to have it GROUP BY planets, but I have no clue where planets comes from. Here is the question and code below:
Find the number of certifications held by people grouped by planet. This should have two columns the first, "name" will be the names of planets that have at least one certification. The second column should be "CertCount" and will be the number of certifications held by people from that planet for example if Lee is certified in "Viper" and "Mechanic" and Kara is certified in "Viper" and they are both from Caprica, then the "CertCount" for caprica should be 3:
CREATE TABLE `bsg_cert` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
CREATE TABLE `bsg_cert_people` (
`cid` int(11) NOT NULL DEFAULT '0',
`pid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`cid`,`pid`),
KEY `pid` (`pid`),
CONSTRAINT `bsg_cert_people_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `bsg_cert` (`id`),
CONSTRAINT `bsg_cert_people_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `bsg_people` (`id`)
) ENGINE=InnoDB
CREATE TABLE `bsg_people` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fname` varchar(255) NOT NULL,
`lname` varchar(255) DEFAULT NULL,
`homeworld` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `homeworld` (`homeworld`),
CONSTRAINT `bsg_people_ibfk_1` FOREIGN KEY (`homeworld`) REFERENCES `bsg_planets` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB
CREATE TABLE `bsg_planets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`population` bigint(20) DEFAULT NULL,
`language` varchar(255) DEFAULT NULL,
`capital` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB
So for the moment: I have the following:
SELECT bsg_planets.name ,
COUNT(*) AS CertCount
FROM bsg_cert_people people_cert
I know that I am missing some code, but I'm not sure where to go from here, and could use a little nudge in the right direction.
You need to join the table according to their primary and foreign key and then do the GROUP BY
SELECT ps.id,
ps.name ,
COUNT(distinct *) AS CertCount
FROM bsg_cert_people cp
JOIN bsg_people pe ON cp.pid = pe.id
JOIN bsg_planets ps ON pe.homeworld = ps.id
GROUP BY ps.id, ps.name
All you need is to do inner join among all 3 tables based on common ids of tables and then group by with Planet id.
Following query should work:
SELECT ps.name ,
count(cert.cid) AS CertCount
FROM bsg_cert_people cert
JOIN bsg_people people ON cert.pid = people.id
JOIN bsg_planets planet ON people.homeworld = planet.id
GROUP BY plsnet.id
having count(distinct *) > 0;
Hope it helps!

SQL - Get total certification count from people on a planet (3 separate tables)

I honestly have no idea how to approach this problem. I've gotten up to SELECT name and then I'm lost (kind of embarrassing).
The problem: Find the number of certifications held by people grouped by planet. This should have two columns the first, "name" will be the names of planets that have at least one certification. The second column should be "CertCount" and will be the number of certifications held by people from that planet for example if Lee is certified in "Viper" and "Mechanic" and Kara is certified in "Viper" and they are both from Caprica, then the "CertCount" for caprica should be 3:
CREATE TABLE `bsg_cert` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB
CREATE TABLE `bsg_cert_people` (
`cid` int(11) NOT NULL DEFAULT '0',
`pid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`cid`,`pid`),
KEY `pid` (`pid`),
CONSTRAINT `bsg_cert_people_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `bsg_cert` (`id`),
CONSTRAINT `bsg_cert_people_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `bsg_people` (`id`)
) ENGINE=InnoDB
CREATE TABLE `bsg_people` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fname` varchar(255) NOT NULL,
`lname` varchar(255) DEFAULT NULL,
`homeworld` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `homeworld` (`homeworld`),
CONSTRAINT `bsg_people_ibfk_1` FOREIGN KEY (`homeworld`) REFERENCES `bsg_planets` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB
CREATE TABLE `bsg_planets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`population` bigint(20) DEFAULT NULL,
`language` varchar(255) DEFAULT NULL,
`capital` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB
Joining them all up doing a count with a group by should do the trick:
SELECT planet.name ,
COUNT(*) AS cert_count
FROM bsg_cert_people people_cert
JOIN bsg_people people ON people.id = people_cert.pid
JOIN bsg_planet planet ON people.homeworld = planet.id
GROUP BY planet.name
SELECT pl.name, count(cert) AS "CertCount"
FROM bsg_planets pl
JOIN bsg_people pe ON pl.id = pe.homeworld
JOIN bsg_cert_people cp ON cp.pid = pe.id
GROUP BY pl.id
I think this is it.

Joining 3+ tables using SQL displaying too many results

im trying to create a query to join these tables together using this method below. However it is repeating results and they are not linking up correctly. as in the same rating comment would be on about 4/5 different results etc. its producing 18ish results when im expecting 3. would anyone be willing to help me with this problem?
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a,
Users b,
Ratings c,
UserCompJobRating d,
Company_Job e,
Jobs f
WHERE d.Comp_job_ID = e.Comp_Job_ID
AND b.users_ID = d.users_ID
AND c.Rating_ID = d.Rating_ID;
Many Thanks,
Andrew
ok i tried this and it is saying e.Users_ID is an unknown column in 'on clause'
SELECT a.Company_name,
b.Job_ID,
b.Job_Name,
c.User_Name,
d.Comments,
d.Reliability,
d.Rating
FROM Company a, UserCompJobRating e, Jobs b
INNER JOIN Users c
ON c.Users_ID = e.Users_ID
inner join Company_Job f
on e.Comp_Job_ID = f.Comp_Job_ID
inner join Ratings d
on d.Rating_ID = e.Rating_ID;
I'm assuming im close, however way off at the same time?
Ill try to give you some more information:
UserCompJobRating has a primary key UCJR_ID and 3 foreign keys of Comp_Job_ID, Users_ID and Rating_ID
Company_Job table as a primary key Comp_Job_ID, and 2 foreign keys Job_ID, Company_ID
Ratings Table has just the Rating_ID as a primary key and the rest just to do with the rating information
Users Table has a Users_ID as a primary key and basic user information address etc etc
Jobs Table has a Job_ID primary key and basic information about the job, such as name, price, etc.
Company Table has Company_ID as a primary key and the basic company information, similar to the Users table.
Here are the definations:
CREATE TABLE `company` (
`Company_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_Name` varchar(45) NOT NULL,
`CAddress` varchar(45) NOT NULL,
`CTown` varchar(45) NOT NULL,
`CPostcode` varchar(12) NOT NULL,
`CTelephone` varchar(45) NOT NULL,
PRIMARY KEY (`Company_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
CREATE TABLE `company_job` (
`Comp_Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_ID` int(11) NOT NULL,
`Job_ID` int(11) NOT NULL,
PRIMARY KEY (`Comp_Job_ID`),
KEY `Company_ID_idx` (`Company_ID`),
KEY `Job_ID_idx` (`Job_ID`),
CONSTRAINT `Company_ID` FOREIGN KEY (`Company_ID`) REFERENCES `company` (`Company_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Job_ID` FOREIGN KEY (`Job_ID`) REFERENCES `jobs` (`Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
CREATE TABLE `jobs` (
`Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Job_Name` varchar(45) NOT NULL,
`Job_Cost` varchar(45) DEFAULT NULL,
`Job_Avg_Time` varchar(45) DEFAULT NULL,
`Job_Avg_Cost` varchar(45) DEFAULT NULL,
`Job_Description` varchar(45) NOT NULL,
`Company_ID` int(11) NOT NULL,
PRIMARY KEY (`Job_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `ratings` (
`Rating_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comments` varchar(200) DEFAULT NULL,
`Cost` varchar(45) DEFAULT NULL,
`Reliability` varchar(45) DEFAULT NULL,
`Rating` int(11) DEFAULT NULL,
PRIMARY KEY (`Rating_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `usercompjobrating` (
`UCJR_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comp_Job_ID` int(11) DEFAULT NULL,
`Rating_ID` int(11) DEFAULT NULL,
`Users_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`UCJR_ID`),
KEY `Comp_Job_ID_idx` (`Comp_Job_ID`),
KEY `Rating_ID_idx` (`Rating_ID`),
KEY `User_ID_idx` (`Users_ID`),
CONSTRAINT `Comp_Job_ID` FOREIGN KEY (`Comp_Job_ID`) REFERENCES `company_job` (`Comp_Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Rating_ID` FOREIGN KEY (`Rating_ID`) REFERENCES `ratings` (`Rating_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Users_ID` FOREIGN KEY (`Users_ID`) REFERENCES `users` (`Users_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `users` (
`Users_id` int(11) NOT NULL AUTO_INCREMENT,
`User_Name` varchar(45) NOT NULL,
`UAddress` varchar(45) NOT NULL,
`UTown` varchar(45) NOT NULL,
`UPostcode` varchar(45) NOT NULL,
`UTelephone` varchar(45) NOT NULL,
`UDOB` varchar(45) NOT NULL,
PRIMARY KEY (`Users_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
The query needs to look something like this i.e. use this form
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a
INNER JOIN Users b
ON a.???? = b.???
Since I dont have your table definitions I cant help you with the JOIN conditions. Show us the tables definition and we would be able to help.
UPDATE:
So based on your table structures you will be looking for something like this:
SELECT *
FROM company cmp
INNER JOIN company_job cmpjb
ON cmp.Company_ID = cmpjb.Company_ID
INNER JOIN jobs jb
ON cmpjb.Job_ID = jb.Job_ID
INNER JOIN usercompjobrating ucmpjbr
ON ucmpjbr.Comp_Job_ID = ucmpjbr.Comp_Job_ID
INNER JOIN users usr
ON usr.Users_id = ucmpjbr.Users_ID
INNER JOIN ratings rat
ON rat.Rating_ID = ucmpjbr.Rating_ID
Note you cannot use the folder table in this join as there are no primary/foreign key relationships to any of the other tables from the folder table.
I would suggest that you carefully dissect this query and let me know if you need to understand the details.
One thing to clarify, what is company_id in table jobs?
select ... (necessary fields to select)
from company c
join company_job cj using (company_id)
join jobs j using (job_id)
join usercompjobrating ucjr using (comp_job_id)
join ratings using (rating_Id)
join users using (users_id)