MySQL find results based on two different values of the same column - mysql

list employees names (Ename) who have both 49008 zip code customers and 49009 zip code customers.
I am struggling to answer the above query based on the above tables.
If the names match between tables assume constraint.
I can filter down to name and zip easily by left joins and group by but struggle after that, I don't know the proper where or having statement. I am assuming it could be done better by a sub query but not sure. Ideally, a single query.
Please and thank you.
1) Create and insert statements for example data:
Create table Employees (EM_Eno INT NOT NULL, EM_Ename VARCHAR(50), EM_Hire_Date DATE, PRIMARY KEY(EM_Eno));
Create table Customers (Customers_Cno INT NOT NULL, Customers_Cname VARCHAR(50), Customers_Street VARCHAR(50), Customers_Zip INT, Customers_Phone INT, primary key(Customers_Cno));
Create table Orders (Orders_Ono INT NOT NULL, Orders_Cno INT, Orders_Eno INT, Orders_Received DATE, Orders_Shipped DATE, primary key(Orders_Ono));
insert into Orders values
( 1,301,501,20161010,20161011);
( 2,302,501,20161011,20161012);
( 3,303,502,20161110,20161111);
( 4,304,502,20161110,20161112);
( 5,305,502,20161110,20161113);
( 6,306,503,20161112,20161114);
( 7,307,501,20161112,20161113);
( 8,308,503,20161112,20161115);
( 9,309,503,20161115,20161120);
(10,300,501,20161112,20161113);
insert into Customers values
(300,'Bryan','100 street',49009,1234567890),
(301,'Ryan','101 street',49008,1234567890),
(302,'Nick','102 street',49009,1234567890),
(303,'Nicholas','103 street',49009,1234567890),
(304,'Alexa','104 street',49009,1234567890),
(305,'Tori','105 street',49008,1234567890),
(306,'Scarlet','106 street',49008,1234567890),
(307,'Heather','100 street',49009,1234567890),
(308,'Amanda','107 street',49008,1234567890),
(309,'James','108 street',49008,1234567890);
insert into Employees values
(501,'Robert',20041010),
(502,'Sam',20050110),
(503,'Brandy',20050710);
2) Ideal end result is answering the query "list employees (names) who have both 49008-zipcode customers and 49009-zipcode customers."
3) Best Attempt thus far:
select Employees.EM_Ename
, Customers.Customers_Zip
from Employees
left
join Orders
on Employees.EM_Eno = Orders.Orders_Eno
left
join Customers
on Orders.Orders_Cno = Customers.Customers_Cno
group
by Employees.EM_Ename
, Customers.Customers_Zip;

The table names are altered slightly in the rextest, because other tables already exist there with the same name...
SELECT e.*
FROM tbl_employees e
JOIN tbl_orders o
ON o.orders_eno = e.em_eno
JOIN tbl_customers c
ON c.Customers_Cno = o.Orders_Cno
WHERE c.Customers_Zip IN(49008,49009)
GROUP
BY e.em_eno
HAVING COUNT(DISTINCT customers_zip) = 2;
http://rextester.com/HCNLU51847

This should be what you want:
select Min(e.Ename)
from #Employees e
join #Orders o on o.Eno = e.Eno
join #Customers c on c.Cno = o.Cno
join #Orders o2 on o2.Eno = e.Eno
join #Customers c2 on c2.Cno = o2.Cno
where o.Ono !=o2.Ono--c.Cno != c2.Cno and
and c.Zip = 49008 and c2.Zip = 49009
group by e.Ename,c.Zip
order by e.Ename
As you can see if you wanted more than those two the self joins become longer.

Related

Join unrelated tables in summarized manner

I am finding a hard time to summarize the SQL table.
Objective: from the given tables I have to join and summarize the table.
col1 = Name_of_student,
col2 = Name_of_subject(where she/he scored highest),
col3= highest_number,
col4 = faculty_Name(where she/he scored highest),
col5 = Name_of_subject(where she/he scored lowest),
col6 = lowest marks,
col7 = faculty_Name(where she/he scored lowest)
Note - I have to write only one query for the given output.
There four tables:
Students.
Students_subject.
Faculty.
Marks.
You can copy the code in my SQL script for understanding the tables.
create database university ;
use university ;
create table students (id int auto_increment primary key,
student_name varchar(250) NOT NULL,
dob DATE NOT NULL) ;
create table faculty ( id int auto_increment primary key,
faculty_name varchar(250) NOT NULL,
date_of_update datetime default NOW()) ;
create table Students_subject ( id int auto_increment primary key,
subject_name varchar(250) default 'unknown' NOT NULL,
subject_faculty int not null,
foreign key(subject_faculty) references faculty(id));
create table marks (id int auto_increment primary key,
student_id int NOT NULL,
subject_id int NOT NULL,
marks int NOT NULL,
date_of_update datetime default now() ON UPDATE NOW(),
foreign key(student_id) references students(id),
foreign key(subject_id) references students_subject(id));
insert into students ( student_name, dob) values
('rob', '2001-03-06'),
('bbb', '2001-09-06'),
('rab', '1991-03-06'),
('root', '2001-03-16') ;
insert into faculty(faculty_name) values
('kaka'),
('dope'),
('kallie'),
('kim');
insert into students_subject (subject_name, subject_faculty) values
('maths', 2),
('physics', 3),
('english', 4),
('biology', 1),
('statistics', 2),
('french', 4),
('economics',3);
insert into marks ( student_id, subject_id, marks) values
(1,1,70),
(1,2,60),
(1,3,98),
(1,4,75),
(1,5,90),
(1,6,30),
(1,7,40),
(2,1,70),
(2,2,60),
(2,3,70),
(2,4,105),
(2,5,95),
(2,6,30),
(2,7,10),
(3,1,70),
(3,2,60),
(3,3,70),
(3,4,75),
(3,5,99),
(3,6,30),
(3,7,10),
(4,1,70),
(4,2,60),
(4,3,70),
(4,4,89),
(4,5,99),
(4,6,30),
(4,7,19);
I had written Query myself to work out on this but cannot break it though.
select students.id, table_high.marks, table_high.faculty_name as high_faculty, table_high.subject_name as sub_high,
student_low.marks , student_low.faculty_name as faculty_low, student_low.subject_name as sub_low from students
inner join
(select students.id, students.student_name ,marks.marks, subject_joined.faculty_name, students_subject.subject_name from marks
inner join (select students_subject.id,students_subject.subject_name, faculty.faculty_name, students_subject.subject_faculty
from students_subject left join faculty on students_subject.subject_faculty = faculty.id)
as subject_joined on subject_joined.id = marks.subject_id
inner join faculty on subject_joined.subject_faculty = faculty.id
inner join students_subject on students_subject.id = marks.subject_id
inner join students on students.id = marks.student_id
order by 1, 3 desc) as table_high on table_high.id = students.id
inner join
(select students.id, students.student_name ,marks.marks, subject_joined.faculty_name, students_subject.subject_name from marks
inner join (select students_subject.id,students_subject.subject_name, faculty.faculty_name, students_subject.subject_faculty
from students_subject left join faculty on students_subject.subject_faculty = faculty.id)
as subject_joined on subject_joined.id = marks.subject_id
inner join faculty on subject_joined.subject_faculty = faculty.id
inner join students_subject on students_subject.id = marks.subject_id
inner join students on students.id = marks.student_id
order by 1, 3 ) as student_low on student_low.id = students.id
group by 1 ;
attaching screen of output :
Finally resolved this question!
The basic tweak that was required in summarizing this table is that the sub-table had to be joined with a combination of two columns as group by command just reflects the first row value in the summarized table for non-summarized cols, so reflecting values of max and min was not possible at the same time, to which I created sub tables filtering rows through double column joins and finally joined the table to the main student table.
The main table which was joined is Students.
Sub-Table 1 - hw (which summarized the data for highest)
sub-table 1.2 - high for highest marks tagging.
sub-table 2 - lw ( which summarized the table for the lowest)
sub-table 2.1 - low for minimum marks tagging.
Query >>
select students.id, students.student_name, lw.min_marks, lw.lower_subject, lw.lower_faculty,
hw.high_marks, hw.subject_name as high_subject, hw.faculty_name as higher_faculty
from students inner join
(select high.student_id, high.high_marks, high.subject_id, high.subject_name, high.faculty_name
from
(select marks.student_id, marks.marks as high_marks, sub_with_faculty.subject_id, sub_with_faculty.subject_name,
sub_with_faculty.faculty_name from marks
left join
(select students_subject.id as subject_id, students_subject.subject_name, faculty.faculty_name
from students_subject
left join faculty on students_subject.subject_faculty = faculty.id) as sub_with_faculty
on sub_with_faculty.subject_id = marks.subject_id) as high
inner join (select marks.student_id, max(marks) as marks from marks group by 1) as maximum on
maximum.student_id = high.student_id and maximum.marks = high.high_marks) as hw on
hw.student_id = students.id
inner join
(select low.student_id, low.low_marks as min_marks, low.subject_id as lower_subjectID, low.subject_name as lower_subject, low.faculty_name as lower_faculty
from
(select marks.student_id, marks.marks as low_marks, sub_with_faculty.subject_id, sub_with_faculty.subject_name,
sub_with_faculty.faculty_name from marks
left join
(select students_subject.id as subject_id, students_subject.subject_name, faculty.faculty_name
from students_subject
left join faculty on students_subject.subject_faculty = faculty.id) as sub_with_faculty
on sub_with_faculty.subject_id = marks.subject_id) as low
inner join (select marks.student_id, min(marks) as marks from marks group by 1) as minimum on
minimum.student_id = low.student_id and minimum.marks = low.low_marks) as lw on
lw.student_id = students.id;
This could be a good exercise for someone who's new to MySQL like me.

Database get rid of repeated attribute

So basically I have 3 tables: student, class, and enrollment.
CREATE TABLE class
(`class_name` varchar(13), `class_id` int primary key)
;
INSERT INTO class
(`class_name`, `class_id`)
VALUES
('math', 5697),
('science', 5768),
('computer', 6315),
('physical-ed', 6422),
('music', 7528),
('art', 7604),
('jrotc', 8797),
('culinary-arts', 8069)
;
CREATE TABLE student
(`student_fname` varchar(8), `student_id` varchar(11) primary key)
;
INSERT INTO student
(`student_fname`, `student_id`)
VALUES
('james', 'Vre94b3JpXO'),
('jim', 'JzqQ2zRVNm1'),
('jenny', 'xgqv9P42eYL'),
('kyle', 'QLNM0Wbyqk0'),
('kimberly', 'P2egAddWN0Q'),
('kayla', 'EGNDjWAreAy'),
('noah', 'bPeOyMMONGr'),
('nataly', '9Op53GGmqk5')
;
create table enrollment (
`no` int(10),
`student_id` varchar(11),
`class_id` int,
`semester` varchar(20),
primary key (`student_id`, `class_id`, `semester`),
foreign key (`student_id`) references student (`student_id`),
foreign key (`class_id`) references class (`class_id`)
);
insert into enrollment values
(1, 'Vre94b3JpXO', 5697, 'Fall 2015'),
(2,'JzqQ2zRVNm1', 5697, 'Fall 2015'),
(3, 'xgqv9P42eYL', 5697, 'Fall 2015'),
(4, 'JzqQ2zRVNm1', 8069, 'Fall 2014'),
(5, 'xgqv9P42eYL', 8069, 'Fall 2014');
If I follow the query:
select * from student s
join enrollment e on s.student_id = e.student_id
join class c on c.class_id = e.class_id
I would get something like this:
How could I remove the redundant column like student_id and class_id?
This question is extended from the page:
Table structure - Link one student with multiple classes id
and demo
I have been using the joining method but I couldn't get what I wanted, thanks for your help.
To answer this question, it might be nice to review some basics :
SELECT *
This * is to display all the columns from the table(s) you have selected
If you want to display only some columns, you have to specificly name it :
SELECT class_name, ...
But if you have some tables with the same column name, you have to specify the table name or alias :
SELECT c.class_name
FROM mytable t
INNER JOIN class c ON c.id_table = t.id
Just specify the columns you want to see.
select s.student_fname, s.student_id,
e.no, e.class_id, e.semester,
c.class_name,
from
student s join enrollment e
on s.student_id = e.student_id
join class c
on c.class_id = e.class_id ;
Something like this:
SELECT s.*
,e.no
,e.class_id
,e.semester
,c.class_name
FROM student s
INNER JOIN enrollment e ON s.student_id = e.student_id
INNER JOIN class c ON c.class_id = e.class_id
In your select you can specify each column you'd like and thus what order.
SELECT e.no
,e.class_id
If you want all columns from a table you can do that table dot star like:
SELECT s.*
As you already have in the existing query you can simply do star to get all the columns:
SELECT *
Here is a good place to start for some basic SELECT tricks: https://www.techrepublic.com/article/sql-basics-select-statement-options/
On an aside, it can be helpful to use a site like: http://poorsql.com/ to help with your SQL formatting.

Reuse joined tabled in a sub query

Is there any way we can reuse the reference of table we joined in a sub query?
I have three tables:
task_categories, information about task categories
task_priorities, priorities associated with task categories
task_links, url links for each individual tasks.
Please check this SQL Fiddle.
CREATE TABLE task_categories (
task_category_id int,
code varchar(255),
name varchar(255)
);
CREATE TABLE task_priorities (
priority_id int,
task_category_id int,
priority int
);
CREATE TABLE task_links (
task_links_id int,
task_category_id int,
title varchar(255),
link varchar(255),
position int
);
We'd need to join all these tables if we need links of tasks that has high priority. Something like this
select * from task_links t_links
inner join task t on t_links.task_id = t.task_id
inner join task_priorities t_priorities on t.task_id = t_priorities.task_id
where t.code in ('TASK_P2', 'TASK_P3') and
t_priorities.priority = (select min(priority) from task_priorities tp
inner join task t on tp.task_id = t.task_id
where t.code in('TASK_P2', 'TASK_P3'))
order by t_links.position;
Is there any way to optimize this query? This query has joined table twice, I think there should be a better way to write this query.
The logic for your subquery is incorrect. It is not selecting the minimum priority for each task.
I am guessing that you really want:
where t.code in ('TASK_P2', 'TASK_P3') and
tp.priority = (select min(tp2.priority)
from task_priorities tp2
where tp2.task_id = t.task_id
)
This doesn't need much more optimization than an index on task_priorities(task_id, priority).

SQL transfer data to another table using join

I have old tables
Items(vendorId-FK, ManufacturerId (IS NOT FK)),
Vendors(PK- VendorId int),
Manufacturer(PK-ManufacturerId int)
Need to transfer data to new DB and it works on transferring data from vendor, but from Manufacturer it transfer only 30000 (where oldManufacturerId is not null), and other 5000 is not transferred. Any ideas what I'm doing wrong?
New Table Manufacturer
( OldManufacturerID int,
newManufacturerId Uniqueidentifier default newid(),
ManufacturerName varchar (100),
)
New Table Items
( ...
ItemDescription,
ManufacturerId uniqueidentifier,
VendorId uniqueidentifier
)
INSERT INTO dbo.Item
( ...
ItemDescription,
ManufacturerId ,
VendorId
)
SELECT
...
itemDescription,
m.ManufacturerId ,
v.VendorId
FROM OldSqlDatabase.dbo.tbl_Items i
JOIN NewSqlDatabase.dbo.Vendor v ON ISNULL(i.vendor_id, '') = ISNULL(v.SourceVendorID, '')
JOIN NewSqlDatabase.dbo.Manufacturer m ON ISNULL(i.manufacturer_id, '') = ISNULL(m.SourceManufacturerID, '')
I just transfered a data since this table didn't have any relationships, new manufactureId has default newid(), and this new id i want to use in the new item table
INSERT INTO dbo.Manufacturer
( OldManufacturerID ,
ManufacturerName ,
)
SELECT
manufacturer_id ,
manufacturer_name ,
FROM oldManufacture
You likely need to use a LEFT JOIN the get records where there a no values (null values) on which to join. The LEFT JOIN will allow you to select all records from the first table being specified in the join, even if there are no matching records available in the second table in the join.
This would also allow you to get rid of that ISNULL() stuff in the join definitions as well. Those would perform very poorly, as they would not be able to use indexes.
I would suggest something like:
INSERT INTO dbo.Item
( ...
ItemDescription,
ManufacturerId ,
VendorId
)
SELECT
...
itemDescription,
m.ManufacturerId ,
v.VendorId
FROM OldSqlDatabase.dbo.tbl_Items i
LEFT JOIN NewSqlDatabase.dbo.Vendor v
ON i.vendor_id = v.SourceVendorID
LEFT JOIN NewSqlDatabase.dbo.Manufacturer m
ON i.manufacturer_id = m.SourceManufacturerID

SQL: How to join a view with a table?

UPDATED:
I am using MySQL statement to create a view:
I need to show Editors First Name, Last Name and the City if they shipped more than 50 books. The three tables I have are:
create table editors (
ed_id char(11),
ed_lname varchar(20),
ed_fname varchar(20),
ed_pos varchar(12),
phone varchar(10),
address varchar(30),
city varchar(20),
state char(2),
zip char(5),
ed_boss char(11));
create table titleditors (
ed_id char(11),
title_id char(6),
ed_ord integer);
create table salesdetails (
sonum integer,
qty_ordered integer,
qty_shipped integer,
title_id char(6),
date_shipped date);
Can anyone tell me what code would be to create this result?
I didn't make the tables, I just have to work with what I was given.
Antiquated syntax (note the intermixing of join conditions and filter conditions):
CREATE VIEW qtyorderedview AS
SELECT
salesdetails.title_id, salesdetails.qty_shipped,
editors.ed_id, editors.ed_lname, editors.ed_fname, editors.city
FROM
titleditors, salesdetails, editors
WHERE
titleditors.title_id = salesdetails.title_id
AND editors.ed_id = titleditors.ed_id
AND salesdetails.qty_ordered > 50
Modern syntax (join conditions and filter conditions are separate):
CREATE VIEW qtyorderedview AS
SELECT
salesdetails.title_id, salesdetails.qty_shipped,
editors.ed_id, editors.ed_lname, editors.ed_fname, editors.city
FROM
titleditors
INNER JOIN salesdetails ON titleditors.title_id = salesdetails.title_id
INNER JOIN editors ON editors.ed_id = titleditors.ed_id
WHERE
salesdetails.qty_ordered > 50
Joins against views work exactly like joins against tables. Just use the view name in place of a regular table name.
SELECT e.*
FROM (
SELECT DISTINCT te.ed_id
FROM (
SELECT title_id
FROM sales_details
GROUP BY
title_id
HAVING SUM(qty_shipped) > 50
) t
JOIN titleditors te
ON te.title_id = t.title_id
) te
JOIN editors e
ON e.ed_id = te.ed_id