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

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

Related

MySQL Row Position Using ORDER BY

I'm trying to get this to work. When I run the SELECT on the whole dataset I know that the record with cust_number shows up in position 6 (When Using ORDER BY) but this code returns position 37327 which is it's non ordered by position.
SELECT
x.position,
x.cust_number,
x.company,
x.surname,
x.first_name,
x.title
FROM
(SELECT
#rownum:=#rownum + 1 AS position,
c.cust_number,
company,
surname,
first_name,
title
FROM
1_customer_records c
LEFT JOIN addresses a ON c.fk_addresses_id = a.id
JOIN (SELECT #rownum:=0) r
ORDER BY a.company , c.surname , c.first_name , c.title) x
WHERE
x.cust_number = 43246;
Here is another approach using a temp table
CREATE TEMPORARY TABLE row_calc (id INT AUTO_INCREMENT, fk INT NULL, PRIMARY KEY (id)) ENGINE=MEMORY;
INSERT INTO row_calc(fk)
SELECT
cust_number
FROM
1_customer_records c
LEFT JOIN
addresses a ON c.fk_addresses_id = a.id
ORDER BY company,surname,first_name,title;
SELECT
id
FROM
row_calc
WHERE
fk = 43246 LIMIT 1;
DROP TABLE row_calc;

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.

Mysql View vs Query performance

I have a base query which uses a view which uses another view, like this.
SELECT a,b,c,DEBIT_AMOUNT, CREDIT_AMOUNT FROM MAIN_VIEW WHERE a='foo' AND c='bar';
Here's the schema
create table BASE_TABLE (
id int not null auto_increment,
a varchar(20),
b varchar(20),
c varchar(20),
primary key (id));
create table OTHER_TABLE (
oid int not null auto_increment,
id int not null,
mtype varchar(10),
amount varchar(20),
primary key (oid));
create or replace view `MAIN_VIEW` AS
SELECT BT.a, BT.b, BT.c,SUB_VIEW.DEBIT_AMOUNT, SUB_VIEW.CREDIT_AMOUNT
FROM BASE_TABLE BT
LEFT JOIN SUB_VIEW ON SUB_VIEW.id = BT.id
create or replace view `SUB_VIEW` AS
SELECT BT.id,
( SELECT SUM(O.amount)
FROM OTHER_TABLE O
WHERE O.mtype = 'DR'
AND O.id = BT.id
) AS DEBIT_AMOUNT,
( SELECT SUM(O.amount)
FROM OTHER_TABLE O
WHERE O.mtype = 'CR'
AND O.id = BT.id
) AS CREDIT_AMOUNT
FROM BASE_TABLE BT
My query is permformance is very slow, to speed up query execution, i've modified the MAIN_VIEW like this
since the BASE_TABLE is already available on MAIN_VIEW, i thought fetching DEBIT_AMOUNT and CREDIT_AMOUNT from then and there rather than going into the SUB_VIEW
-- MAIN_VIEW ---
create or replace view `MAIN_VIEW` AS
SELECT BT.a, BT.b, BT.c,
( SELECT SUM(O.amount)
FROM OTHER_TABLE O
WHERE O.mtype = 'DR'
AND O.id = BT.id
) AS DEBIT_AMOUNT,
( SELECT SUM(O.amount)
FROM OTHER_TABLE O
WHERE O.mtype = 'CR'
AND O.id = BT.id
) AS CREDIT_AMOUNT
FROM BASE_TABLE BT
But after this modification, query performance is even worse.. can any one help? I thought subviews are be bad for performance...
You need INDEX(id, mtype) (in either order). This should make the subqueries faster, hence the entire query faster.

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');

How do I query multiple tables using inner join?

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;