How to pass one query result to another? - mysql

Hi guys, Don't focus on the title of question my main question is this. I am bit confused what exactly I should ask.
Define an SQL view Q1(courseid, code) that gives the distinct course id and subject code of any course that is taught by course Tutor (refers to the staff_roles.name). We only consider the courses with the subject code starting with ‘LAWS’, like ‘LAWS1213’. The view should return the following details about each course:
• Courseid should be taken from courses. id field.
• Code should be taken from subjects. Code field.
My Table structures as are as follows.
create table Courses (
id integer, -- PG: serial
subject integer not null references Subjects(id),
semester integer not null references Semesters(id),
homepage URLString,
primary key (id)
);
create table Subjects (
id integer, -- PG: serial
code char(8) not null,
-- PG: check (code ~ '[A-Z]{4}[0-9]{4}'),
name MediumName not null
);
create table Course_staff (
course integer references Courses(id),
staff integer references Staff(id),
role integer references Staff_roles(id),
primary key (course,staff,role)
);
create table Staff_roles (
id integer, -- PG: serial
rtype char(1) references Staff_role_types(id),
rclass char(1) references Staff_role_classes(id),
name LongString not null,
description LongString,
primary key (id)
);
Kindly tell me the query. What query I should write.
I tried this but no luck.
select Courses.id
, Subjects.code
from Courses
, Subjects
, Staff_roles
where ( Courses.subject = Subjects.id
AND Subjects.code like 'LAWS%'
AND Staff_roles.name ='Course Tutor'
);

Related

Trouble with JOINS in mysql

I was working in mySQL and made a fake database for reviews, reviewers and tv series. So I made 3 different tables, one for reviewers, one for reviews and one for the series.
CREATE TABLE reviewers
(
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(150) NOT NULL
);
CREATE TABLE series
(
id INT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(100) NOT NULL,
released_year YEAR(4),
genre VARCHAR(50)
);
CREATE TABLE reviews(
id INT AUTO_INCREMENT PRIMARY KEY,
rating DECIMAL(2,1),
series_id INT,
reviewer_id INT,
FOREIGN KEY(series_id) REFERENCES series(id),
FOREIGN KEY(reviewer_id) REFERENCES reviewers(id)
);
The thing that I wanted to ask is, how can I get the highest rating from each reviewer and in which show they gave it?
UPDATE
I came up with this code
SELECT first_name,last_name,title, a.series_id,a.rating FROM
( SELECT series_id,MAX(rating) AS max FROM reviews
GROUP BY series_id ) AS b
INNER JOIN reviews AS a
ON a.series_id=b.series_id AND a.rating=b.max
INNER JOIN reviewers
ON reviewers.id=a.reviewer_id
INNER JOIN series
ON series.id=a.series_id
GROUP BY series_id;
which gives me the max rating in each series and who gave that rating

using join to get records of a specific fk

I have a table of ParentsSchoolContact, which a parentId have foreign key to the parentId:
CREATE TABLE ParentsSchoolContact (
contactId int NOT NULL AUTO_INCREMENT,
parentId int NOT NULL,
name varchar(60) NOT NULL,
age varchar(60) NOT NULL,
PRIMARY KEY (contactId),
FOREIGN KEY (parentId) REFERENCES Parent(parentId)
);
and I have a parent and contact table that keeps the relation between a kid and a parent:
CREATE TABLE ParentAndContact (
parentId int NOT NULL,
contactId int NOT NULL,
PRIMARY KEY (contactId, parentId)
);
I want to get all the contacts related to a specific parent that i have its id, would that be the right query?
SELECT c.name, c.age
FROM ParentsSchoolContact c
INNER JOIN ParentAndKid pc ON pc.contactId = c.contactId
AND c.parentId = myParentVariable
AND pc.parentId = myParentVariable
wanted to make sure this query dosent fall in some case you could think about :)
thanks!
For me, i see that the ParentAndContact table is redundant. Usually the Parents details are in one table and ContactID/Kids details are in another table (having attributes eg. courses which the kids enrolled, details of the kids).
Assuming that you want to get all the contacts related to a specific parent that you have its id from the available tables (ParentsSchoolContact,ParentAndContact), You can just write a simple query to retrieve the information from ParentsSchoolContact table as of below:-
select contactId, parentId, name, age
from ParentsSchoolContact
where parentId = myParentVariable
Do let me know if i miss out anything.

Get what areas have more than three qualified employees

I have this tables from the MySql database i'm working with:
create table employees (
num_pass int(5) not null,
name varchar(40),
primary key (num_pass)
)engine=innodb;
create table laboratories (
code int(10) not null,
name varchar(40),
primary key (codi),
)engine=innodb;
create table areas (
code int(5) not null,
codeLab int(10) not null,
level enum('H','M','L'),
primary key (code, codeLab),
foreign key (codeLab) references laboratories(code)
)engine=innodb;
create table qualifieds (
num_pass int(5) not null,
area_assigned int(5),
lab int(5),
primary key (num_pass),
foreign key (num_pass) references employees(num_pass),
foreign key (area_assigned, lab) references areas (code, codeLab)
)engine=innodb;
Now i want to get what areas have more than three qualified employees. Specifically, i want to get area code along with the name of the laboratory, laboratory and ordered by region.
I tried to use this command in order to get the code of the area
select b.code
from employees e, areas b, qualifieds q
where e.num_pass=q.num_pass
and 3 < (select count(b1.code)
from areas b1, qualifieds q1, employers e1
where e1.num_pass=q1.num_pass
and q1.area_assigned=b1.code
and q1.lab=b1.codeLab);
But all what i get is a list of all the area codes repeated as many times as the number of employees (i have areas with code 1,2,3,4 and 6 employees, what i get is the sequence 1,2,3,4 repeated 6 times).Any idea about how to get the information i need?
You can use GROUP BY and HAVING to find a group with more than 3 records...
select areas_assigned, lab, count(num_pass)
from qualifieds
group by areas_assigned, lab
having count(num_pass)>3;
If you then need to expand on this, then add joins...
select q.areas_assigned, l.name, count(q.num_pass)
join laboratories l on l.lab = q.lab
from qualifieds q
group by q.areas_assigned, l.name
having count(q.num_pass)>3;

SQL: How to update from 'tableA pointing to tableB' to 'tableA poiting to tableC pointing to tableB' without losing existing element relation?

Basically I want an intermediary Book, between what was a direct link from Line to User. Line elements already exist and can't lose the relation to corresponding already existing User element, so a default Book element needs to be created which handles already existing data.
Tables were created like this:
User (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL
);
Line (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(300),
id_user INT UNSIGNED NOT NULL,
FOREIGN KEY (id_user) REFERENCES User(id)
);
Now I need to create some SQL code that would produce tables like this:
User (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL
);
Book (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(300),
id_user INT UNSIGNED NOT NULL,
FOREIGN KEY (id_user) REFERENCES User(id)
);
Line (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(300),
id_book INT UNSIGNED NOT NULL,
FOREIGN KEY (id_book) REFERENCES Book(id)
);
... except that data already exists. so I have Line elements pointing to User elements and I can't create new tables from scratch. So I need the SQL code to modify the existing structure.
Basically I just want users to have books and books to have lines, instead of users have lines. And already existing lines to get a connection with the owner users. What would be the best approach?
///////////////////////////////////////////////////////
Some sample data representing what my database looks like currently:
Table user(id,username)
- 1, user1
- 2, user2
- 3, user3
Table line(id,title,id_user)
- 1, line1, 1
- 2, line2, 1
- 3, linex, 1
- 4, line1, 2
- 5, liney, 2
The output should be the following database:
Table user(id,username)
- 1, user1
- 2, user2
- 3, user3
Table book(id,title,id_user)
- 1, 'default', 1
- 2, 'default', 2
- 3, 'default', 3
Table line(id,title,id_book)
- 1, line1, 1
- 2, line2, 1
- 3, linex, 1
- 4, line1, 2
- 5, liney, 2
////////////////////////////////
What my pipeline currently looks like, my main problem is producing the final query:
create table book
$sql = "CREATE TABLE IF NOT EXISTS book(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(300),
id_user INT UNSIGNED NOT NULL,
FOREIGN KEY (id_user) REFERENCES User(id)
); ";
$conn->exec($sql);
//insert default book corresponding to every user
$sql = "INSERT INTO Book(title, id_user) SELECT DISTINCT 'default', id FROM User;";
$conn->exec($sql);
//insert id_book foreign key into Line table pointing to Book table
$sql = "ALTER TABLE Line ADD id_book INT;"
$conn->exec($sql);
//make Line.id_book foreign key pointing to Line.id
$sql="ALTER TABLE Line ADD FOREIGN KEY (id_book) REFERENCES User(id);"
$conn->exec($sql);
//unfinished
$sql = "UPDATE
Line
SET
Line.id_book = Book.id
WHERE
Line.id_user = Book.id_user"
Create table book (like you already did):
CREATE TABLE IF NOT EXISTS book(
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(300),
id_user INT UNSIGNED NOT NULL,
FOREIGN KEY (id_user) REFERENCES User(id)
);
Populate the new table:
INSERT INTO Book(title, id_user) SELECT 'default', id FROM User;
I removed DISTINCT from your code because id is primary/unique and thus every selected row is guaranteed to be unique.
Add column id_book to the line table:
ALTER TABLE Line ADD id_book INT UNSIGNED;
It must be INT UNSIGNED to match the referenced data type.
Add foreign key:
ALTER TABLE Line ADD FOREIGN KEY (id_book) REFERENCES book(id);
It should reference a book, not a user like in your code.
Update data (Relate the line with the users (first) book):
UPDATE Line
SET Line.id_book = (
SELECT book.id
FROM book
WHERE book.id_user = Line.id_user
ORDER BY book.id
LIMIT 1
);
Drop line.id_user column:
-- use "SHOW CREATE TABLE line" to find out the foreign key name
ALTER TABLE Line DROP FOREIGN KEY line_ibfk_1;
ALTER TABLE Line DROP id_user;
http://sqlfiddle.com/#!9/3faa13/1
Note: If a user has two or more books, you don't know wich one to link with a line. In your question you didn't define how to handle this case. So i decided to take the first book by id (ORDER BY book.id LIMIT 1).
The UPDATE statement could also be:
UPDATE Line
SET Line.id_book = (
SELECT MIN(book.id)
FROM book
WHERE book.id_user = Line.id_user
);

advice on database design

I am building a database for my website. I have a schema here : enrolin.in/download.png
Introduction to website:
It collects data from students on behalf of colleges.
Now what I have done in database is that I have created a UDT-where data that is fixed to a student is stored. and CST-where data that can change with every new course is stored.
I am very new to database design, so please have a look at the database design and advice me where i can improve. I want it to be perfect so that there are no complications/limitations with database in future
NOTES:
There is not just for one college. It is like a platform where different colleges can add their courses. Every college has different courses with different subjects etc. There can be many CST's, may be a separate CST for every new course. Plus I am not sure about the way I am storing course data , I mean CST and UDT. Every college will have access to the data of students which have applied for a course under that college and every student will have access to data to his previously filled form data,status etc.
Thanks in advance. If anything is unclear, please ask in comments.
Update : -- tables
-- Table CST
CREATE TABLE CST (
cst_id int NOT NULL ,
rollno int NOT NULL ,
semester int NOT NULL ,
CONSTRAINT CST_pk PRIMARY KEY (cst_id)
);
-- Table UDT
CREATE TABLE UDT (
udt_id int NOT NULL ,
id int NOT NULL ,
name varchar(255) NOT NULL ,
gender varchar(255) NOT NULL ,
fatherame varchar(255) NOT NULL ,
mothername varchar(255) NOT NULL ,
dob date NOT NULL ,
signature binary(255) NOT NULL ,
CONSTRAINT UDT_pk PRIMARY KEY (udt_id)
);
-- Table address
CREATE TABLE address (
address_id int NOT NULL ,
id int NOT NULL ,
add_name varchar(255) NOT NULL ,
add_street varchar(255) NOT NULL ,
city varchar(255) NOT NULL ,
state varchar(255) NOT NULL ,
country varchar(255) NOT NULL ,
pin int NOT NULL ,
CONSTRAINT address_pk PRIMARY KEY (address_id)
);
-- Table courses
CREATE TABLE courses (
course_id int NOT NULL ,
course_name varchar(255) NOT NULL ,
CONSTRAINT courses_pk PRIMARY KEY (course_id)
);
-- Table phones
CREATE TABLE phones (
phone_id int NOT NULL ,
id int NOT NULL ,
phone int NOT NULL ,
CONSTRAINT phones_pk PRIMARY KEY (phone_id)
);
-- Table photos
CREATE TABLE photos (
photo_id int NOT NULL ,
id int NOT NULL ,
photo binary(255) NOT NULL ,
CONSTRAINT photos_pk PRIMARY KEY (photo_id)
);
-- Table sub_trans
CREATE TABLE sub_trans (
sub_trans_id int NOT NULL ,
transactions_t_id int NOT NULL ,
subjects_sub_id int NOT NULL ,
CONSTRAINT sub_trans_pk PRIMARY KEY (sub_trans_id)
);
-- Table subjects
CREATE TABLE subjects (
sub_id int NOT NULL ,
course_id int NOT NULL ,
subjectname varchar(255) NOT NULL ,
CONSTRAINT subjects_pk PRIMARY KEY (sub_id)
);
-- Table transactions
CREATE TABLE transactions (
t_id int NOT NULL ,
id int NOT NULL ,
course_id int NOT NULL ,
p_status int NOT NULL DEFAULT 0 ,
phones_phone_id int NOT NULL ,
UDT_udt_id int NOT NULL ,
photos_photo_id int NOT NULL ,
address_address_id int NOT NULL ,
CST_cst_id int NOT NULL ,
CONSTRAINT transactions_pk PRIMARY KEY (t_id)
);
-- Table users
CREATE TABLE users (
id int NOT NULL ,
name varchar(255) NOT NULL ,
email varchar(255) NOT NULL ,
password int NOT NULL ,
CONSTRAINT users_pk PRIMARY KEY (id)
);
`
UDT:
Typo fathername. UDT has an FK to what? Users? Slim down the varchar size in UDT. Sure you want a single column for name? Ok, at least document that you chose to not have more than 2 parents. Otherwise you need another table.
Users:
Passwords run thru a hash function won't be ints and user needs a Salt for optimal security. Imho.
awaiting more clarification below
There is zero purpose of UDT and users both existing. Pick one, pickup lost fields from one you are ditching.
Even hypothetically if it wasn't 1:1 name would denomalize the database.
phones:
Your columns for phones need to be described. Also can a user have more than 1 phone (if so, phoneType varchar(10) or int code? )
Also I would go like varchar(30) on phone value not an int.
Addresses:
Same deal as phones. Can a user have more than one? PostalCode pin should be varchar
Transactions:
This seems to be the hub of your schema. All of your transactions hinge on FKs to data that may have subsequently changed. I see RISK in that. Older transaction could get skewed results for lookups. There are easy ways to fix this issue if you even see it as one. Same goes for courses. What if History 101's id stays the same but next semester that id is Early Roman Empire? Just things to think about.
Lastly the documented tables have no FK relationships shown.