How do I query multiple tables using inner join? - mysql

Given the table creation SQL and insertion SQL, How will I generate a query to display the information in a a particular way?
CREATE TABLE cities (
id serial NOT NULL UNIQUE PRIMARY KEY,
iname varchar(100) NOT NULL UNIQUE
)
CREATE TABLE suburbs (
id serial NOT NULL UNIQUE PRIMARY KEY,
icity integer REFERENCES cities (id),
iname varchar(100) NOT NULL UNIQUE
)
CREATE TABLE type (
id serial NOT NULL UNIQUE PRIMARY KEY,
iname varchar(100) NOT NULL UNIQUE
)
CREATE TABLE sale (
id serial NOT NULL UNIQUE PRIMARY KEY,
iname varchar(100) NOT NULL UNIQUE
)
CREATE TABLE estate (
id serial NOT NULL UNIQUE PRIMARY KEY,
icity integer REFERENCES cities (id),
isuburb integer REFERENCES suburbs (id),
itype integer REFERENCES type (id),
isale integer REFERENCES sale (id),
idescription text,
itimestamp timestamp DEFAULT CURRENT_TIMESTAMP
)
INSERT INTO cities (iname) VALUES ('Johannesburg');
INSERT INTO suburbs (icity, iname) VALUES (1, 'Westbury');
INSERT INTO type (iname) VALUES ('Room');
INSERT INTO sale (iname) VALUES ('Rent');
INSERT INTO estate (icity, isuburb, itype, isale, idescription) VALUES (1, 1, 1, 1, 'A Nice place in a real bad neighbor hood');
Now I want the numerical values that are in the table estate to be displayed by the string values that they represent.
E.G
1 Johannesburg, Westbury, Room, Rent, Description
What will the SQL Query be for this, I am more concerned in using postgreSQL.

you cany try like
select * from table1
inner join table2 on tabl1.pk = table2.FK
inner join table3 on tabl1.pk = table.FK
Final
select table2.iname,table3.iname,table4.iname,table1.idescription
from estate as table1
inner join sale as table2 on table1.isale = table2.id
inner join type as table3 on table1.itype = table3.id
inner join suburbs as table3 on table1.isuburb = table3.id
inner join cities as table4 on table1.icity = table4.id
If you want to get info about joins have look to below image
Ans at : How do I decide when to use right joins/left joins or inner joins Or how to determine which table is on which side?

First, they must have some sort of common field. Let's assume the common field between them is called <tablename>_ID; the way you do it is as follows:
select A.colx, A.coly, A.colz, B.colx, B.colw, c.cold
from A inner join B on A.ID=B.A_ID
inner join C on C.A_ID=A.ID

select suburbs.icity
, cities.iname
, suburbs.iname
, type.iname
, sale.iname
, estate.idescription
from estate
inner join suburbs on suburbs.id = estate.isuburb
inner join cities on cities.id = estate.icity
inner join type on type.id = estate.itype
inner join sale on sale.id = estate.isale

In general, you are looking for a join..
select ct.iname as CityName,sb.name as SuburbName,et.*
from estate et
join cities ct on ct.id=et.icity
join suburbs sb on sb.id=et.isuburb
etc...

You could do it this way :
SELECT *
FROM A
INNER JOIN B
ON B.id = A.b
INNER JOIN C
ON C.id = A.c

Check this example as per ur ques.
SELECT A.*,B.*,C.*
FROM A , B, C
WHERE C.c = B.b
AND B.b = A.a

-> select * from estate
-> inner join cities on estate.icity=cities.id
-> inner join suburbs on estate.isuburb=suburbs.id
-> inner join type on estate.itype=type.id
-> inner join sale on estate.isale=sale.id;

Related

How would you create a sql query that uses a merge join?

Write a SQL query that could produce this query plan.
CREATE TABLE Slot(
sid int PRIMARY KEY,
wall VARCHAR(30),
x float,
y float
)
CREATE TABLE Placement(
rid int REFERENCES Route(rid),
hid int REFERENCES Hold(hid),
sid int REFERENCES Slot(sid),
PRIMARY KEY(rid, hid, sid)
)
Would this sql query be able to produce this plan?
Select *
FROM Placement P, Slot S
WHERE P.sid = S.sid
Do a FROM table then JOIN anotherTable and then the condition after ON
Select *
FROM Placement P
INNER JOIN Slot S
ON P.sid = S.sid

Select three different things from three diffrent tables

I wanna a query to get first_name of students and first_name of teachers which have the most courses with each other with the number of these courses.
Table Student:
CREATE TABLE Student(
id INT AUTO_INCREMENT,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255),
email VARCHAR(255) UNIQUE,
PRIMARY KEY (id)
);
Table Teacher:
CREATE TABLE Teacher(
id INT AUTO_INCREMENT,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255),
email VARCHAR(255) UNIQUE,
degree VARCHAR(10) NUT NULL,
PRIMARY KEY (id)
);
Table Course:
CREATE TABLE Course(
id INT AUTO_INCREMENT,
code INT NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
st_id INT,
teach_id INT,
PRIMARY KEY (id),
FOREIGN KEY st_id REFERENCES Student (id),
FOREIGN KEY teach_id REFERENCES Teacher (id)
);
Is the below query correct? i.e. Can I use 3 SELECT in a query?
query1:
SELECT S.first_name
FROM Student AS S
INNER JOIN Course AS C
ON C.st_id = S.id
SELECT T.first_name
FROM Teacher AS T
INNER JOIN Course AS CC
ON CC.teach_id = T.id
SELECT COUNT(*)
FROM Course
WHERE Course.st_id = S.id
AND Course.teach_id = T.id
GROUP BY COUNT(*)
ORDER BY DESC;
query2:
SELECT S.first_name, T.first_name, COUNT(*)
FROM Student AS S, Teacher AS T, Course
WHERE Course.st_id = S.id
AND Course.teach_id = T.id
GROUP BY COUNT(*)
ORDER BY DESC;
If the above queries are not correct(probably the first one is wrong) guide me to correct answer, please.
NOTE: If the ordering isn't unique, order by the name of teachers first, then order by the name of the students(for clarity but not important so much to me).
Your second query is closer to being right but it has some issues. I would recommend using JOIN statements rather than implied joins. This makes the query easier to read.
Something like this should work:
SELECT t.first_name,
t.id,
s.first_name,
s.id,
COUNT(*) AS course_count
FROM Course c
JOIN Student s ON c.st_id = s.id
JOIN Teacher t ON c.teach_id = t.id
GROUP BY t.id, s.id
ORDER BY course_count DESC, t.first_name, s.first_name;
You need to add a group by in order to get your count on a per student basis. Putting the group by on the id columns rather than the name makes sure you get counts on unique students and teachers in case you have multiple records in your table with the same first name. I am also adding the id columns to the select for the same reason, but these are not necessary and can be removed without affecting the accuracy of the query.
SELECT t.first_name, t.id, s.first_name, s.id, COUNT(c.id) AS course_count
FROM course c
JOIN student s ON c.st_id = s.id
JOIN teacher t ON c.teach_id = t.id
GROUP BY t.id, s.id
ORDER BY t.first_name, s.first_name
The essential data is contained in the Courses table, with the Student and Teacher tables only required for gathering the names. This query joins the 3 tables in question, computing the count of courses shared by teachers and students.

Using LIKE %% in query clause with multiple values from different tables

I have a basic query that fetches values from three tables. The three tables : company, classes_by_company, and person. I have a foreign key in all tables with the name company_id. In the where clause I am using LIKE to compare with a random value the values fetched for any results that may have a match. But I am having no success in doing so. I get an error in the sql line WHERE a.id LIKE %1% OR a.company_id LIKE %3% OR c.count LIKE %1% OR p.count LIKE %1%. How can I compare all the values fetched from these three tables against a random value to see if there is a match? SQLFIDDLE
SELECT a.id, a.company_id, a.status,
c.count AS classes_per_company,
p.count AS employees_per_company
FROM company a
LEFT JOIN (SELECT company_id, COUNT(*) as count
FROM classes_by_company
GROUP BY company_id) c
ON a.company_id = c.company_id
LEFT JOIN (SELECT company_id, COUNT(*) as count
FROM person
GROUP BY company_id) p
ON a.company_id = p.company_id
WHERE a.id LIKE %1% OR a.company_id LIKE %3% OR c.count LIKE %1% OR p.count LIKE %1%
Table Schema:
CREATE TABLE company
(
id int auto_increment primary key,
company_id int,
status varchar(20)
);
CREATE TABLE classes_by_company
(
id int auto_increment primary key,
company_id int,
class_name varchar(20)
);
CREATE TABLE person
(
id int auto_increment primary key,
employee_id int,
company_id int,
person_name varchar(20)
);
LIKE has to be followed by a string, so it should be:
WHERE a.id LIKE '%1%'
OR a.company_id LIKE '%3%'
OR c.count LIKE '%1%'
OR p.count LIKE '%1%'
id is an integer column; the LIKE operator relies on a text data type e.g. nvarchar.
You could convert the id to a string e.g. WHERE CAST(a.id AS VARCHAR(10)) LIKE '%1%' ...
Please also note the single quotes around the %1%.

Use of double left join in a query returns different values

Below are the tables
TABLE 1
CREATE TABLE table1 (
id smallint(5) NOT NULL AUTO_INCREMENT primary key,
name varchar(30) NOT NULL
)
ENGINE=InnoDB;
TABLE 2
create table table2(
no int auto_increment primary key,
Reg_no varchar(2),
debit decimal(19,2)
)
engine=innodb;
TABLE 3
create table table3(
no int auto_increment primary key,
Reg_no varchar(2),
Paid decimal(19,2)
)
engine=innodb;
Please below is my query code.
SELECT id, sum(Paid) AS AMOUNT,sum(debit) AS DEBIT
from table1 LEFT JOIN table2 ON table1.id=table2.Reg_no
LEFT JOIN table3 ON table1.id=table3.Reg_no
GROUP BY table1.id
Please I am finding it very difficult in using double left join in a query,the problem in this code is that,the sum used in the query above give more than the expected figure,for instance the sum(10+10) will output 40 instead of 20. Please where am I going wrong with my code.I would be grateful if anybody could help me.Thanks in advance
The problem is that each join is 1-many so you are multiplying the number of rows for each id.
The solution is to pre-aggregate the results. However, you don't provide enough information in the question to give a correct answer. The query probably looks something like:
SELECT id, Paid, Debit
from table1 LEFT JOIN
(select Reg_no, sum(Debit) as Debit
from table2
group by Reg_no
) table2
ON table1.id = table2.Reg_no left outer join
(select Reg_no, sum(Paid) as Paid
from table3
group by Reg_no
) table3
ON table1.id = table3.Reg_no
order BY table1.id

joining tables with not exists query [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Mysql: Perform of NOT EXISTS. Is it possible to improve permofance?
Is there a better/optimal way to do it. Should I use exists instead of join? Or two separate queries? And what about temporary tables, as I was reading about those but uncertain.
Getting members email from a group. Checking that they have not received a item yet.
SELECT m.email,g.id
FROM group g
LEFT JOIN members m
ON g.mid = m.id
AND g.gid='1'
WHERE NOT EXISTS
( SELECT id
FROM items AS i
WHERE i.mid=m.id
AND i.item_id='5'
)
Here's the same thing written as a JOIN:
SELECT m.email, g.id
From members m
JOIN group g ON g.mid = m.id AND g.gid = '1'
LEFT JOIN items i ON i.mid = m.id AND i.item_id = '5'
WHERE i.id IS NULL
Use the following compound indexes:
group (mid, gid)
items (mid, item_id)
I reversed the LEFT JOIN on members and group because it seems like you're returning members, not groups, and I changed the LEFT JOIN into an INNER JOIN since you only want members from that group.
I think this one might read better:
SELECT m.email, g.id
From members m
JOIN group g ON g.mid = m.id
LEFT JOIN items i ON i.mid = m.id AND i.item_id = 5
WHERE g.gid = 1
AND i.id IS NULL
You might be wondering if we can move the i.item_id = 5 part to the WHERE clause also. You can't because there are no rows where i.id IS NULL and i.item_id = 5. You must do the join first and then eliminate the NULL rows in the WHERE clause.
I don't believe a temporary table is necessary. We'd really only go that route if we can't get acceptable performance.
From your query, we gather your schema looks like this:
group (id INT PK, gid INT, mid INT)
items (id INT PK, item_id INT, mid INT)
members (id INT PK, email VARCHAR)
It looks like your group table is really a "membership" table, which resolves/implements a many-to-many relationship between a group and a person. (That is, a person can be a member of zero, one or more groups; a group can have zero, or or more persons as members.)
You are using a LEFT JOIN between group and members. This will return a row for group (returning group.id) when there are no matching members, with a NULL for members.email (which may be what you want). But if you only want to return email addresses, then this can be changed to an INNER JOIN.
The NOT EXISTS predicate can be replaced with an OUTER JOIN and a test for a NULL value returned from the JOINED table. If the group.gid and/or items.item_id columns are numeric datatype, then you can remove the quotes from around the integer literals in the predicates.
Here is an alternative which will return an equivalent resultset, and may perform better:
SELECT m.email
, g.id
FROM members m
JOIN group g ON g.mid = m.id AND g.gid = 1
LEFT
JOIN items i ON i.mid = m.id AND i.item_id = 5
WHERE i.id IS NULL
ADDENDUM:
TEST CASE (provided in comment on selected answer) demonstrates difference in result set between queries with the predicate items.item_id = 5 in the ON clause and in the WHERE clause. (Moving this predicate to the WHERE clause messes with the anti-join.)
CREATE TABLE `group` (`id` INT PRIMARY KEY, `gid` INT, `mid` INT);
CREATE TABLE `items` (`id` INT PRIMARY KEY, `item_id` INT, `mid` INT);
CREATE TABLE `members` (`id` INT PRIMARY KEY, `email` VARCHAR(40));
INSERT INTO `group` VALUES (1,1,1), (2,1,2);
INSERT INTO `items` VALUES (1,5,1);
INSERT INTO `members` VALUES (1,'one#m.com'),(2,'two#m.com');