my SQL SELECT Columns From Multiple Tables Without Repeating Data - mysql

create table Student (
St_ID int not null,
St_Name varchar (100),
St_tel int,
St_ADD varchar (100) not null,
St_city varchar (100)not null,
St_type varchar (20) not null,
St_nationality varchar (20) not null,
Dep_ID int,
C_ID int,
primary key (St_ID),
foreign key (Dep_ID) references Department(Dep_ID),
foreign key (C_ID) references Course(C_ID),
)
create table Course (
C_ID int not null,
C_Name varchar (30) not null,
C_Duration varchar (10) not null,
DegreeType varchar (20),
Dep_ID int,
primary key (C_ID),
foreign key (Dep_ID) references Department (Dep_ID),
)
insert into Course Values (4040,'Software Engineering','18months','HND',001)
insert into Course Values (1454,'Business IT','6months','Diploma',001)
insert into Course Values (1534,'Business management ','18months','HND',002)
insert into Course Values (1245,'Digital Media','6months','Diploma',001)
insert into Course Values (1243,'Business Development','10months','Diploma',001)
INSERT INTO Student VALUES (1212,'jerome jacobs',0774750407,'no 66/7 senananyake lane ','nawala','fulltime','HND','SL',001,4040);
INSERT INTO Student VALUES (1713,'john paul',0773435646,'no 77/9 alvatigala lane','colombo ','parttime','Diploma','SL',001,1454);
INSERT INTO Student VALUES (1614,'Angelo mathews',0773436777,'no 88 rose lane colombo ','colombo 2','fulltime','HND','SL',002,1534);
INSERT INTO Student VALUES (1514,'jean paul',0713556688,'no 100/1 4th lane nawala','nawala','fulltime','Diploma','SL',002,1245);
INSERT INTO Student VALUES (1316,'Mark francis',0755657665,'no 54 1st lane ','kotte','parttime','HND','SL',003,4040);
INSERT INTO Student VALUES (1117,'Kevin steffan',0757667687,'no 99/5 railway lane ','nugegoda','parttime','Diploma','SL',004,1243);
SELECT DISTINCT Student.St_ID,St_Name,St_tel,St_ADD,St_type,DegreeType,C_Name from Student,Course where Student.St_type='parttime' and Course.DegreeType='HND';
this is my query to get information from two tables but it repeat values how can i fix that im really curious about sql im a beginner sorry for the way i ask questions i will be reall great full if it is answered

You have to JOIN the tables using the common field:
SELECT DISTINCT Student.St_ID,St_Name,St_tel,St_ADD,St_type,DegreeType,C_Name
from Student JOIN
Course ON Student.C_ID =Course.C_ID
where Student.St_type='parttime' and Course.DegreeType='HND';
An SQL JOIN clause is used to combine rows from two or more tables, based on a common field between them.
Read more about joins here.

You have to use MySql Join , if you need to understand it more : http://dev.mysql.com/doc/refman/5.0/en/join.html

You have to join the student and course tables together by specifying their common column (key). Instead of this:
from Student,Course
do this:
from Student
join Course on student.C_ID= Course.C_ID
If you don't connect the two tables properly you'll get the cartesian product set.

Click for Information JOIN
SELECT S.St_ID, St_Name, St_tel, St_ADD, St_type, DegreeType, C_Name
FROM Student s
INNER JOIN Course C ON S.C_ID = C.C_ID
WHERE S.St_type='parttime' and C.DegreeType='HND'
GROUP BY S.St_ID;

Related

Find people who have the same day of birth

I'm looking for a way to create a query that gives me the list of people who were born on the same day (the data is in two different tables).
All ideas are welcome. ( I use MySQL)
SQL code :
https://pastebin.com/StNggaYg
CREATE TABLE Professeurs(
ID_Professeur Int Auto_increment NOT NULL ,
Nom_Professeur Varchar (50) NOT NULL ,
Prenom_Professeur Varchar (50) NOT NULL ,
Ville_de_naissance_P Varchar (50) NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
Professeur_Principal Bool NOT NULL
,CONSTRAINT Professeurs_PK PRIMARY KEY (ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Classes
#------------------------------------------------------------
CREATE TABLE Classes(
ID_Classes Int Auto_increment NOT NULL ,
Lettre_classe Char (5) NOT NULL ,
ID_Professeur Int NOT NULL
,CONSTRAINT Classes_PK PRIMARY KEY (ID_Classes)
,CONSTRAINT Classes_Professeurs_FK FOREIGN KEY (ID_Professeur) REFERENCES Professeurs(ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Elèves
#------------------------------------------------------------
CREATE TABLE Eleves(
ID_Eleve Int Auto_increment NOT NULL ,
Nom_eleve Varchar (50) NOT NULL ,
Prenom_eleve Varchar (50) NOT NULL ,
Ville_de_naissance_E Varchar (50) NOT NULL ,
Date_de_naissance_E Date NOT NULL ,
ID_Classes Int NOT NULL
,CONSTRAINT Eleves_PK PRIMARY KEY (ID_Eleve)
,CONSTRAINT Eleves_Classes_FK FOREIGN KEY (ID_Classes) REFERENCES Classes(ID_Classes)
)ENGINE=InnoDB;
The column :
Date_de_naissance_E Date NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
First, you would have to get the results of BOTH tables dates via a UNION to find what dates have more than one instance. Its possible to have two teachers with same date, two students with same date, OR a teacher AND student have same date. Once that is done, then you can join back to the respective original source to grab the names.
To simplify the query from rewriting it twice nested within itself, I will use CTE (common table expression). It allows you to write a query that will be used multiple times allowing simple alias name to be used in a subsequent query.
Below is the CTE via "With AllPeople as". This select is the query used in the second half. Notice I am getting ID, name, birth date and also a type "P" as Professeur and "E" as Eleves for the person type. First time through I am getting a count where a given birthdate occurs more than once. THEN, re-join to the same AllPeople again that had that date found as a common birth date.
with AllPeople as
( select
'P' personType,
p.ID_Professeur personID,
p.Nom_Professeur personName,
Date_Format( p.Date_de_naissance_P, "%M %d" ) commonDate
from
Professeurs p
union all
select
'E' personType,
e.ID_Eleve personID,
e.nom_eleve personName,
Date_Format( e.Date_de_naissance_E, "%M %d" ) commonDate
from
Eleves e
)
select
who.PersonType,
who.PersonID,
who.PersonName,
BornOnSameDay.commonDate
from
(select
commonDate
from
AllPeople
group by
commonDate
having
count(*) > 1 ) BornOnSameDay
JOIN
AllPeople Who
on BornOnSameDay.commonDate = Who.commonDate
order by
BornOnSameDay.commonDate,
who.PersonName
Now, you also provided a class table of which teachers were teaching what class, and if a student was in a particular class. If your intention was to find out which classes has a student with the same birthdate as the professor teaching it, that would be a different query.
Please advise on which you meant. The one I have provided is ANY teacher having a same birthday as ANY other teacher OR student. And likewise could be two students having the same birth date.
You can use the GROUP_CONCAT function:
SELECT date_format(birthdate,"%d %b") AS birthday, GROUP_CONCAT(person_name) AS people
FROM persons
GROUP BY MONTH(birthdate), DATE(birthdate)

Primary / foreign key; joining multiple tables using subqueries

I have a question for an assignment with 5 tables as shown below. I need to write a query with the minimum cost for each sport:
2nd column is equipment_name:
I think I need to do a bunch of joins in subqueries with the primary keys being the id columns and the foreign keys the name_id columns. Is this the right approach?
You don't need a bunch of joins; minimally this question can be solved by one join between the store_equipment_price and the sports_equipment tables - if these two are joined on equipment id then you'll effectively get rows that can give the cost of starting up in each sport per store. You'll need to group by the sport id and the store id; don't forget that it might be cheaper to start soccer by getting all the gear from store A but it might be cheaper to start golf by going to tore B - tho I how I read the question. If however you're prepared to get your gloves from store A and your bat from store B etc then we don't even group by the store when summing, instead we work out which store is cheapest for each component rather than which store is cheapest for each sport overall.
If you're after producing named stores/sports on your result rows then you'll need more joins but try getting the results right based on the fewest number of joins possible to start with
Both these queries will ultimately be made a lot easier by the use of an analytic/windowing function but these are database dependent; never post an sql question up without stating what your db vendor is, as there are few questions that are pure ISO SQL
You question is not completely clear, I assume you need to find stores from which to buy each equipment for all sports so as to incur minimum expense. Following query will achieve this
select s.sports, e.equipment_name, min(sep.price),
(select store_name from stores st where st.id = sep.store_id) store_name
from sports s
join sports_equipment se on s.id = se.sport_id
join equipment e on e.id = se.equipment_id
join sports_equipment_prices sep on sep.equipment_id = se.equipment_id
group by s.sports, e.equipment_name
order by s.sports, e.equipment_name
;
Following 'create table' and 'insert data' script are based on your screen images
create table sports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sports varchar(50)
);
insert into sports(sports) values('golf');
insert into sports(sports) values('baseball');
insert into sports(sports) values('soccer');
create table stores (
id INTEGER PRIMARY KEY AUTOINCREMENT,
store_name varchar(50)
);
insert into stores(store_name) values('A');
insert into stores(store_name) values('B');
insert into stores(store_name) values('C');
create table equipment (
id INTEGER PRIMARY KEY AUTOINCREMENT,
equipment_name varchar(50)
);
insert into equipment(equipment_name) values('shoes');
insert into equipment(equipment_name) values('ball');
insert into equipment(equipment_name) values('clubs');
insert into equipment(equipment_name) values('glove');
insert into equipment(equipment_name) values('bat');
create table sports_equipment (
sport_id INTEGER not null,
equipment_id INTEGER not null,
FOREIGN KEY(sport_id) REFERENCES sports(id),
FOREIGN KEY(equipment_id) REFERENCES equipment(id)
);
insert into sports_equipment values(1, 1);
insert into sports_equipment values(1, 2);
insert into sports_equipment values(1, 3);
insert into sports_equipment values(2, 2);
insert into sports_equipment values(2, 4);
insert into sports_equipment values(2, 5);
insert into sports_equipment values(3, 1);
insert into sports_equipment values(3, 2);
create table sports_equipment_prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
store_id INTEGER not null,
equipment_id INTEGER not null,
price INTEGER not null,
FOREIGN KEY(store_id) REFERENCES stores(id),
FOREIGN KEY(equipment_id) REFERENCES equipment(id)
);

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;

How do i concatenate information from a foreign key?

i just realised i've worded this very poorly
i'm trying to find out if i can do this within an insert statement, not when trying to output the data
This might sound very confusing but hopefully i can explain it.
I have two tables, expertise (parent) and department (child)
In expertise I have :
exp_id int(2) primary key
exp_name varchar(30)
In department I have:
dep_id int(2) primary key
dep_name varchar(30)
exp_id int(2) foreign key
I DO NOT want the outcome for the department rows to look like this:
dep_id dep_name exp_id
1 accounting 32
1 accounting 27
1 accounting 29
I WANT IT to look like this
dep_id dep_name exp_id
1 accounting 32, 27, 29
So there is multiple rows within a row, if that makes any sense.
I believe its concatenation i have to work with, but I've never used this before and was looking for some help
i just realised i've worded this very poorly
i'm trying to find out if i can do this within an insert statement, not when trying to output the data
you should be able to use group_concat, ie:
select dep_id, dep_name, group_concat(exp_id) exp_id
from department
group by dep_id, dep_name
You should also consider normalisation your department table, it is currently violating first normal form due to the repeating groups of dep_id, dep_name. reference here
edit
I see you updated your question to say you want the data stored in this way in the table, not displayed.
The answer to that is: you really don't.
delimited fields are all but impossible to deal with, and are just all around horrible in an rdbms. If you absolutely must have it this way, you could use the above query to create a view, and at least store the real data in a proper, normalised fashion.
To re-iterate. Please don't do this. Kittens will die.
In the spirit of normalized data
-- drop table expertise
create table expertise
( expId int not null,
expName varchar(100) not null
);
insert expertise (expId,expName) values (32,'number massaging');
insert expertise (expId,expName) values (27,'misrepresentation');
insert expertise (expId,expName) values (29,'embezzlement');
-- select * from expertise
-- drop table department;
create table department
( deptId int not null,
deptName varchar(100) not null
);
insert into department (deptId,deptName) values (1,'Accounting');
insert into department (deptId,deptName) values (2,'Executive');
insert into department (deptId,deptName) values (3,'Food Service');
-- select * from department
-- drop table expDeptIntersect;
create table expDeptIntersect
( expId int not null,
deptId int not null
);
insert expDeptIntersect (expId,deptId) values (27,1);
insert expDeptIntersect (expId,deptId) values (32,1);
insert expDeptIntersect (expId,deptId) values (29,1);
--select * from expdeptintersect
select d.deptId,d.deptName,group_concat(i.expId) expId
from department d
join expDeptIntersect i
on i.deptId=d.deptId
group by d.deptId,d.deptName

Oracle table with only current records; reduce duplicates using max(date)

I need to create a new table in oracle with only the most current date for each record (step 1), and calculate days between (step 2).
Your suggestions are greatly appreciated:)))
Step 1: First I need to find the max (Mod_date) for each record from table USERS.
TABLE: USERS
Name................Mod_Date
Jason Martin....... 25-JUL-89
Al Mathews......... 21-MAR-89
James Smith........ 12-DEC-88
Robert Black....... 15-JAN-84
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........ 12-DEC-98
Robert Black....... 15-JAN-94
*TABLE_DESIRED_RESULTS_step1
Name............... Max(Mod_Date)
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........12-DEC-98
Robert Black.......15-JAN-94
Step 2: Calculate “Number of Days Between Regist_Date and Mod_Date” & add it to the table.
TABLE: REGISTRATION
Name................Regist_Date
Jason Martin.........20-JUL-99
Al Mathews...........23-MAR-96
Robert Black.........20-JAN-94
*TABLE_DESIRED_RESULTS_step2
Name...............Max(Mod_Date).....Number of Days Between Regist_Date and Mod_Date
Jason Martin...... 25-JUL-99..........5
Al Mathews........ 21-MAR-96.........-2
James Smith....... 12-DEC-98..........null
Robert Black...... 15-JAN-94..........-5
*Please note, this data is made up and I already have existing unions and joins to which I have to add this logic. Thanks and have a nice day!
here is my updated answer with a sample.
The important thing is that your date column have the DATE type.
Here is the tables and data following your specification.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
MOD_DATE DATE NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
INSERT INTO USERS VALUES (1,'Jason Martin',TO_DATE('25-07-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (2,'Al Mathews',TO_DATE('21-03-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (3,'James Smith',TO_DATE('12-12-1988','DD-MM-YYYY'));
INSERT INTO USERS VALUES (4,'Robert Black',TO_DATE('15-01-1984','DD-MM-YYYY'));
INSERT INTO USERS VALUES (5,'Jason Martin',TO_DATE('25-07-1999','DD-MM-YYYY'));
INSERT INTO USERS VALUES (6,'Al Mathews',TO_DATE('21-03-1996','DD-MM-YYYY'));
INSERT INTO USERS VALUES (7,'James Smith',TO_DATE('12-12-1998','DD-MM-YYYY'));
INSERT INTO USERS VALUES (8,'Robert Black',TO_DATE('15-01-1994','DD-MM-YYYY'));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
INSERT INTO REGISTRATION VALUES (1,'Jason Martin',TO_DATE('20-07-1999','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (2,'Al Mathews',TO_DATE('23-03-1996','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (3,'Robert Black',TO_DATE('20-01-1994','DD-MM-YYYY'));
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u
GROUP BY u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.NAME = r.NAME);
The trick here is that LEFT OUTER JOIN allows null value if there is no match with the join.
But there is a database design concern for me.
If you have 2 users with the exact same name , you will merge 2 persons in one.
Here a solution using IDs and doing the join on the IDs.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
CREATE TABLE MOD_USERS
(
ID_MOD NUMBER(6) NOT NULL,
ID_USER NUMBER(6) NOT NULL,
CONSTRAINT PK_usermod PRIMARY KEY (ID_MOD)
) ;
ALTER TABLE MOD_USERS ADD (
CONSTRAINT FK_user_mod
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
ID_USER VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
ALTER TABLE REGISTRATION ADD (
CONSTRAINT FK_user_reg
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER))
;
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
m.ID_USER , u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u INNER JOIN MOD_USERS m
ON u.ID_USER = m.ID_USER
GROUP BY m.ID_USER , u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.ID_USER , t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.ID_USER = r.ID_USER);