MySql SELECT with Joins and conditions statement - mysql

I have three tables
TABLE `courses` (
id int NOT NULL UNIQUE AUTO_INCREMENT,
title varchar(50) NOT NULL UNIQUE,
duration int NOT NULL,
theme varchar(50) NOT NULL,
students_quantity int NOT NULL,
PRIMARY KEY (id)
);
TABLE `users` (
id int NOT NULL UNIQUE AUTO_INCREMENT,
name varchar(50) NOT NULL,
email varchar(50) NOT NULL UNIQUE,
password varchar(50) NOT NULL,
status varchar(20) NOT NULL,
role_id int NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (role_id) REFERENCES `roles` (id)
);
TABLE `teachers_courses` (
teacher_id int NOT NULL,
course_id int NOT NULL,
PRIMARY KEY (teacher_id, course_id),
FOREIGN KEY (teacher_id) REFERENCES `users` (id),
FOREIGN KEY (course_id) REFERENCES `courses` (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
How can I get get courses.* and users.name AS teacher for this course, and if I have not course_id and teacher_id for this course in teachers_courses I'll get 'none' in teacher?

Use JOIN to combine your data following primary key - foreign key path.
Function coalesce() would return the second argument, if the first one evaluates to NULL.
select c.*, coalesce(u.name, 'none') as teacher
from courses c
left join teachers_courses tc on c.id = tc.course_id
left join users u on tc.teacher_id = u.id
order by c.id
Since there can be multiple teachers for each course, the only case in which you would get 'none' as teacher value would be if there is no teacher assigned for a course (not even one). If there is more than one teacher, there will be as many rows in the output as there are teachers for each course, thus I included ORDER BY to sort the result properly.
If you need to view the data for only one course, include a WHERE condition like this:
-- ... Above SQL here ...
WHERE c.id = ?

Related

SQL Joining 4 tables, only selecting columns from 2

CREATE TABLE user (
userID INT AUTO_INCREMENT PRIMARY KEY,
accountTypeID INT NOT NULL,
userEmail VARCHAR(320) NOT NULL,
userPassword VARCHAR(32) NOT NULL,
userFirst VARCHAR(20) NOT NULL,
userLast VARCHAR(20) NOT NULL,
userPhone VARCHAR(10) NOT NULL,
lastAccess TIMESTAMP NOT NULL,
userRegistry DATE NOT NULL,
FOREIGN KEY (accountTypeID) REFERENCES accountType(accountTypeID));
CREATE TABLE participant (
participantID INT AUTO_INCREMENT PRIMARY KEY,
vehicleID INT NOT NULL,
userID INT NOT NULL,
eventID INT NOT NULL,
participantRegistry DATE NOT NULL,
paymentMethodID INT NOT NULL,
FOREIGN KEY (vehicleID) REFERENCES vehicle(vehicleID),
FOREIGN KEY (userID) REFERENCES user(userID),
FOREIGN KEY (eventID) REFERENCES event(eventID),
FOREIGN KEY (paymentMethodID) REFERENCES paymentMethod(paymentMethodID));
CREATE TABLE vehicle (
vehicleID INT AUTO_INCREMENT PRIMARY KEY,
makeID INT NOT NULL,
vehicleModel VARCHAR(20) NOT NULL,
vehicleYear VARCHAR(4) NOT NULL,
tshirtID INT NOT NULL,
clubID INT NOT NULL,
FOREIGN KEY (makeID) REFERENCES make(makeID),
FOREIGN KEY (tshirtID) REFERENCES tshirt(tshirtID),
FOREIGN KEY (clubID) REFERENCES club(clubID));
CREATE TABLE club (
clubID INT AUTO_INCREMENT PRIMARY KEY,
clubName VARCHAR(20) NOT NULL,
clubLogo BLOB);
$sql="SELECT U.userFirst, U.userLast, C.clubName FROM user AS U, club AS C
INNER JOIN participant AS P
on P.userID = U.userID
INNER JOIN vehicle AS V
on V.vehicleID = P.vehicleID
INNER JOIN club AS C
on C.clubID = V.clubID
ORDER BY C.clubName ASC";
We are trying to get all the clubs and all the members (first and last name) in each club.
The participant and vehicle tables are just needed to link the users table to the club table.
I know it is something simple the server we are using doesn't display sql errors and does not have phpmyadmin.
Thanks to maSTAShuFu, I came to the working result of.
SELECT U.userFirst, U.userLast, C.clubName FROM club AS C
INNER JOIN vehicle AS V
on C.clubID = V.clubID
INNER JOIN participant AS P
on V.vehicleID = P.vehicleID
INNER JOIN user AS U
on P.userID = U.userID
ORDER BY C.clubName ASC

JOIN FOUR TABLES in mysql. Error in syntax

I need to join four tables in mysql.
My database structure:
DROP DATABASE IF EXISTS db_applicant;
CREATE DATABASE db_applicant
DEFAULT CHARACTER SET 'utf8'
DEFAULT COLLATE 'utf8_unicode_ci';
USE db_applicant;
--
-- TABLE: PROFESSION
--
CREATE TABLE PROFESSION (
PROFESSION_ID INT NOT NULL AUTO_INCREMENT,
PROFESSION_NAME VARCHAR(50) NOT NULL,
PRIMARY KEY (PROFESSION_ID)
);
--
-- TABLE: SUBJECT
--
CREATE TABLE SUBJECT (
SUBJECT_ID INT NOT NULL AUTO_INCREMENT,
SUBJECT_NAME VARCHAR(50) NOT NULL,
PRIMARY KEY (SUBJECT_ID)
);
--
-- TABLE: APPLICANT
--
CREATE TABLE APPLICANT (
APPLICANT_ID INT NOT NULL AUTO_INCREMENT,
PROFESSION_ID INT NOT NULL,
LAST_NAME VARCHAR(30) NOT NULL,
FIRST_NAME VARCHAR(30) NOT NULL,
ENTRANCE_YEAR INT NOT NULL,
PRIMARY KEY (APPLICANT_ID),
FOREIGN KEY (PROFESSION_ID) REFERENCES PROFESSION (PROFESSION_ID)
);
--
-- TABLE: APPLICANT_RESULT
--
CREATE TABLE APPLICANT_RESULT (
APPLICANT_RESULT_ID INT NOT NULL AUTO_INCREMENT,
APPLICANT_ID INT NOT NULL,
SUBJECT_ID INT NOT NULL,
MARK INT,
PRIMARY KEY (APPLICANT_RESULT_ID),
FOREIGN KEY (SUBJECT_ID)
REFERENCES SUBJECT (SUBJECT_ID),
FOREIGN KEY (APPLICANT_ID)
REFERENCES APPLICANT (APPLICANT_ID)
);
--
-- TABLE: SPECIALITY_SUBJECT
--
CREATE TABLE SPECIALITY_SUBJECT (
SP_SB_ID INT NOT NULL AUTO_INCREMENT,
PROFESSION_ID INT NOT NULL,
SUBJECT_ID INT NOT NULL,
PRIMARY KEY (SP_SB_ID),
FOREIGN KEY (PROFESSION_ID)
REFERENCES PROFESSION (PROFESSION_ID),
FOREIGN KEY (PROFESSION_ID)
REFERENCES PROFESSION (PROFESSION_ID),
FOREIGN KEY (SUBJECT_ID)
REFERENCES SUBJECT (SUBJECT_ID)
);
I need that output would be something like:
first_name (this column from table applicant), last_name (this column from table applicant), entrance_year (this column from table applicant), profession_name (this column from table profession), subject_name (this column from table subject), mark (this column from table applicant_result).
You can see, that i have related fields. But i need strong INNER QUERY.
For that, i create new table with structure:
CREATE TABLE APP(
ALL_ID INT NOT NULL AUTO_INCREMENT,
APPLICANT_ID INT NOT NULL,
SUBJECT_ID INT NOT NULL,
PROFESSION_ID INT NOT NULL,
APPLICANT_RESULT_ID INT NOT NULL,
PRIMARY KEY (ALL_ID),
FOREIGN KEY (SUBJECT_ID)
REFERENCES SUBJECT (SUBJECT_ID),
FOREIGN KEY (APPLICANT_ID)
REFERENCES APPLICANT (APPLICANT_ID),
FOREIGN KEY (PROFESSION_ID)
REFERENCES PROFESSION (PROFESSION_ID),
FOREIGN KEY (APPLICANT_RESULT_ID)
REFERENCES APPLICANT_RESULT (APPLICANT_RESULT_ID)
);
And my inner:
SELECT ap.ALL_ID, a.FIRST_NAME, a.LAST_NAME,
a.ENTRANCE_YEAR, p.PROFESSION_NAME s.SUBJECT_NAME, ar.MARK
FROM app ap
JOIN (applicant a, profession p, subject s, applicant_result ar)
ON ap.APPLICANT_ID = a.APPLICANT_ID
AND ap.SUBJECT_ID = s.SUBJECT_ID
AND ap.PROFESSION_ID = p.PROFESSION_ID
AND ap.APPLICANT_RESULT_ID = ar.APPLICANT_RESULT_ID;
But i have error:
[2015-09-19 10:08:52] [42000][1064] 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 '.SUBJECT_NAME, ar.MARK FROM app ap
JOIN (applicant a, profession p, subject s, a' at line 1
Don't you think, a comma ',' is missing here in select statement before s.SUBJECT_NAME?
SELECT ap.ALL_ID, a.FIRST_NAME, a.LAST_NAME,
a.ENTRANCE_YEAR, p.PROFESSION_NAME s.SUBJECT_NAME, ar.MARK

SELECT query from one table linked with foreign key to multiple tables

My database consists of these tables
products(
id INT(10) AUTO_INCREMENT,
name VARCHAR(16) NOT NULL,
PRIMARY KEY (id)
);
/* ^
One |
To
| Many
v
*/
versions(
id INT(10) AUTO_INCREMENT,
product_id INT(10)
name VARCHAR(16) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
/* ^
One |
To
| Many
v
*/
subversions(
id INT(10) AUTO_INCREMENT,
version_id INT(10)
name VARCHAR(16) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (version_id) REFERENCES versions(id)
);
/* ^
Many|
To
| Many
v
*/
users(
id INT(10) AUTO_INCREMENT,
name VARCHAR(16) NOT NULL,
password VARCHAR(32) NOT NULL,
PRIMARY KEY (id),
);
And then i have
subversions_users_conjuction(
id INT(10) AUTO_INCREMENT,
subversion_id VARCHAR(16) NOT NULL,
user_id VARCHAR(32) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (subversion_id) REFERENCES subversions(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
What i'm struggling with is a query to get products.name (and id..or whichever filed) based on the current user.
So, if i have a user with id = 1, i need to search table subversions_users to get all the subversions matching, then from that all the versions matching and then all the products matching and all that without duplicates, so DISTINCT. And i really have no idea where to start
Something such as the following, perhaps?
SELECT DISTINCT p.name
FROM products AS p
INNER JOIN versions AS v ON p.id = v.product_id
INNER JOIN subversions AS s ON v.id = s.version_id
INNER JOIN subversions_users_conjuction AS c ON s.id = c.subversion_id
WHERE c.user_id = <<<ID>>>;

sum of column returning double the value

I have the following SQL query:
SELECT s.name, s.learner_tag, s.guild_id, s.id, ifnull(sum(t.xp),0) as xp, ifnull(sum(a.ap),0) as ap, (ifnull(sum(t.xp),0)/1000+ifnull(sum(a.ap),0)/100) as level, g.name
FROM student s
INNER JOIN guild g ON g.id = s.guild_id
LEFT JOIN student_task t ON s.id = t.student_id
LEFT JOIN student_achievement a ON s.id = a.student_id
WHERE s.class_id = ".$realm_id."
GROUP BY s.name, s.learner_tag, s.guild_id, s.id, g.name
ORDER BY level DESC LIMIT 10";
However the query returns double the expected value for the ap column. There is only 1 record in the student_achievement table and the value is 25. However my query returns 50 as the value of sum(a.ap). If I edit the value, it still doubles. sum(t.xp) is working fine. Can anyone spot my mistake?
Table Structure:
CREATE TABLE student
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
guild_id INT,
class_id INT NOT NULL,
time_updated INT,
ap INT NOT NULL,
learner_tag VARCHAR(64) NOT NULL,
schoology_id INT NOT NULL,
enrollment_id INT NOT NULL,
FOREIGN KEY (guild_id) REFERENCES guild (id),
FOREIGN KEY (class_id) REFERENCES class (id)
);
CREATE TABLE student_achievement
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
student_id INT NOT NULL,
achievement_id INT NOT NULL,
time_added INT,
ap INT NOT NULL,
FOREIGN KEY (student_id) REFERENCES student (id),
FOREIGN KEY (achievement_id) REFERENCES achievement (id)
);
CREATE TABLE achievement
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
value INT NOT NULL,
repeatable TINYINT NOT NULL,
image_url VARCHAR(200) NOT NULL,
description VARCHAR(240) NOT NULL
);
CREATE TABLE task
(
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
name VARCHAR(64) NOT NULL,
max_xp INT,
schoology_id INT,
class_id INT NOT NULL,
processed TINYINT,
type VARCHAR(15) NOT NULL,
FOREIGN KEY (class_id) REFERENCES class (id)
);

Can I do it with one query?

SELECT `invites`.`id`, `invites`.`from`, `invites`.`to`, `invites`.`group_id`
FROM `invites`
WHERE `invites`.`to` = '33'
It gets ID of user that sent invite and ID of user that is invited. And, of course, ID of group they invited each other. I need to display usernames of them, but they are stored in another table. The same goes for groups. Info about them is stored in another table.
I could make new queries to get that info from IDs, but is it worth it? Can I do it with only one query?
Edit:
Structure:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`surname` varchar(50) NOT NULL,
PRIMARY KEY (`id`),
);
CREATE TABLE `invites` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group_id` int(10) unsigned NOT NULL,
`from` int(10) unsigned NOT NULL,
`to` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
A join is always worst it:
SELECT `invites`.`id`,
`invites`.`from`,
`invites`.`to`,
`invites`.`group_id`,
`toUsers`.`name` as toUserName,
`fromUsers`.`name` as fromUserName,
`groups`.`name` as groupName
FROM `invites`
INNER JOIN `users` AS toUsers
ON `invites`.`to` = toUsers.id
INNER JOIN `users` AS fromUsers
ON `invites`.`from` = fromUsers.id
INNER JOIN `groups`
ON `invites`.`group_id` = `groups`.`id`
WHERE `invites`.`to` = '33'
The only thing you have to keep in mind is to have foreign keys on from, to and group_id, and have primary keys on Id in tables Users and Groups. Then your query will be as fast as you need.
So I advise to run this :
ALTER TABLE `invites`
ADD CONSTRAINT FK_invites_to FOREIGN KEY (`to`) REFERENCES users(id),
ADD CONSTRAINT FK_invites_from FOREIGN KEY (`from`) REFERENCES users(id),
ADD CONSTRAINT FK_invites_group FOREIGN KEY (`group_id`) REFERENCES groups(id)
See some doc : http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
You can use a JOIN:
SELECT invites.id, invites.from, invites.to, invites.group_id, group.name, u1.name, u2.name
FROM invites, user as u1, user as u2, group
WHERE invites.from = u1.id
AND invites.to = u2.id
AND group.id = invites.group_id
AND invites.to = '33'
Assuming your tables are called user and group and your fields name. You may have to put the backticks back on the field names because FROM is a reserved keyword.
I'd use a join too, but I'd create a view first that joins invites to users, then join two of those together - it means not having to repeat the join between invite and user.