88
Joins And Subqueries

Joins And Subqueries

  • Upload
    kirk

  • View
    50

  • Download
    0

Embed Size (px)

DESCRIPTION

Joins And Subqueries. Multi-table queries (JOIN) 2 tables. Retrieve the part name for all parts shipped in quantities equal to 200. SELECT DISTINCT PART.PartName FROM PART, SHIPMENT WHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;. Conjunct #1 is a PK FK comparison. - PowerPoint PPT Presentation

Citation preview

Page 1: Joins And Subqueries

JoinsAnd

Subqueries

Page 2: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesRetrieve the part name for all parts shipped in quantities equal to 200SELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

Page 3: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

So how does this work?

Conjunct #1 is a PK FK comparison

Conjunct #2 qualifies retrieval

Page 4: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

Conceptually, we can understand the execution of the query in terms of row scans.

A Scan is a sequential inspection of many rows for the purpose of returning rows that meet a criteria.

The following demonstrations are a simplified version of the Nested Loop technique (as opposed to “merge sort” and “hashed join”)

Page 5: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

PK/FK comparison requires one scan of the FK set for each PK in the parent table.Row is included in the view where PK=FK and Qty = 200

Page 6: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

(Scan 1)

.

.

.(FK Scan)

(No Matches: TT)

(P1=P1 300=200)(P1=P2 200=200)

(P1=P5 100=200)

Page 7: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

(Scan 2)

.

.

.(FK Scan)

(Two Matches: TT)

(P2=P1 300=200)(P2=P2 200=200)

(P2=P5 100=200)

This removes duplicates in results

Page 8: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

(Scan 3)

.

.

.(FK Scan)

( No Matches: TT)

(P3=P1 300=200)(P3=P2 200=200)

(P3=P5 100=200)

Page 9: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

(Scan 4)

.

.

.(FK Scan)

( Two Matches: TT)

(P4=P1 300=200)(P4=P2 200=200)

(P4=P5 100=200)

(And So On...)

Page 10: Joins And Subqueries

Multi-table queries(JOIN) 2 tablesSELECT DISTINCT PART.PartNameFROM PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SHIPMENT.quantity = 200;

(Scan 6)

How many row comparisons?

rows(PK-table) X rows(FK-table)

6 X 12 = 72

Page 11: Joins And Subqueries

Multi-table queriesJOIN Evaluation Techniques

• Three common methods used by DBMS optimizers to evaluate Joins– Nested Loop– Merge Scan– Hash Join

Page 12: Joins And Subqueries

Multi-table queriesJOIN Evaluation Techniques

• Nested Loop– Essentially the preceding demo– One table defined as external and one

table defined as internal– (External:Internal)– (1:M)– (Parent:Child)

– If there isn’t an index on the FK, the internal table has to be opened for a scan for every row of the external table

Page 13: Joins And Subqueries

Multi-table queriesJOIN Evaluation Techniques

• Merge Scan– Both tables have to be ordered by PK/FK– Parallel scans are executed on both

tables– Qualifying rows are found by merging

the order lists into groups or partitions

Page 14: Joins And Subqueries

Multi-table queriesJOIN Evaluation Techniques

• Hash Join– Both tables are stored using hash

function on join attributes (PK/FK)– Execute join on each partition

Page 15: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesRetrieve supplier name and part name for parts shipped in quantities less than 400.

SELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

Page 16: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 1)

(One Match: TT T)

.

.

.(FK Scan)

(P1=P1 S1=S1 400>300)(P1=P2 S1=S1 400>200)

(P1=P5 S1=S4 400>100)

Page 17: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 2)

(No Matches: TT T)

.

.

.(FK Scan)

(P1=P1 S2=S1 400>300)(P1=P2 S2=S1 400>200)

(P1=P5 S2=S4 400>100)

Page 18: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 2-5)

(No Matches: TT T)

.

.

.

So we finish out the “P1” Supplier scan with no matches

Page 19: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 6)

(One Match: TT T)

.

.

.(FK Scan)

(P2=P1 S1=S1 400>300)(P2=P2 S1=S1 400>200)

(P2=P5 S1=S4 400>100)

Page 20: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 7)

(One Match: TT T)

.

.

.(FK Scan)

(P2=P1 S2=S1 400>300)(P2=P2 S2=S1 400>200)

(P1=P5 S2=S4 400>100)

Page 21: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

(Scan 8)

(One Match: TT T)

.

.

.(FK Scan)

(P2=P1 S3=S1 400>300)(P2=P2 S3=S1 400>200)

(P1=P5 S3=S4 400>100)

(And so on...)

Page 22: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesSELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.Quantity < 400;

How many row comparisons?

6x5x12 = 360

Page 23: Joins And Subqueries

Multi-table queries(JOIN) 3 tablesRetrieve the supplier name and part name for all shipments with quantity greater than or equal to 200 for which the warehouse is located in the same city as the supplier

SELECT DISTINCT SUPPLIER.SupplierName, PART.PartNameFROM SUPPLIER, PART, SHIPMENTWHERE (PART.PartNumber = SHIPMENT.PartNumber AND SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber) AND (SHIPMENT.Quantity >= 200 AND SUPPLIER.SupplierCity = PART.PartCity);

Page 24: Joins And Subqueries

Multi-table queries(JOIN) Let’s recap...For each row in the outer table (Parent), every row in the inner table (Child) is scanned for a PK/FK match and any qualifying predicate.

In your WHERE clause, you must have a PK=FK statement for every Parent/Child relationship involved in the query.

(PK=FK Scan)

Data

Data

Data

Data

Data

FK Value

FK Value

FK Value

FK Value

FK Value

PK Value

PK Value

PK Value

Data

Data

Data

(Outer Table) (Inner Table)

OuterTable

InnerTable

Page 25: Joins And Subqueries

Sub-Queries (nested)UncorrelatedSo... Joins are really just the combination of the PRODUCT and SELECT relational operators.

But in the case where you have a qualifying predicate such as PartNumber=‘P2’, why do a PRODUCT of the outer table with the entire inner table?Why not eliminate some of the rows from the inner table first with a simple query and then do a PRODUCT of the resulting (and smaller) table?Recall, that the result of a relational operation is a table. So we can Join the outer table with the intermediate table resulting from the inner or sub-query.

Data

Data

Data

Data

Data

FK Value

FK Value

FK Value

FK Value

FK Value

PK Value

PK Value

PK Value

Data

Data

Data

(Outer Table) (Inner Table)Scan inner table

for PartNumber = ‘P2’

(Intermediate Table)

FK valueData

FK ValueData

FK ValueData

Remove non-

qualifying rows

Then Join Outer with

Intermediate

Page 26: Joins And Subqueries

Sub-Queries (nested)Introduction

• Nested queries can be either correlated or uncorrelated– correlated:inner query depends on row that is

currently being examined in the outer query– uncorrelated: inner query performed

independently of outer query

• The nested or sub-query usually appears in the WHERE clause of a query

• Sub-queries can also appear in the FROM and HAVING clause

Page 27: Joins And Subqueries

Sub-Queries (nested)Introduction

• General structure of uncorrelated sub-query

SELECT Item FROM table1 WHERE Item IN [NOT IN] (SELECT Item FROM table2 WHERE predicate);

(Inner Query)

(Outer Query)

Page 28: Joins And Subqueries

Sub-Queries (nested)UncorrelatedRetrieve supplier names for suppliers who supply part P2

SELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber = 'P2');

Page 29: Joins And Subqueries

Sub-Queries (nested)UncorrelatedSELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber = 'P2');

Intermediate

Now join outer table to intermediate result

Outer Result

Execute inner query: Scan SHIPMENT for ‘P2’

Page 30: Joins And Subqueries

Sub-Queries (nested)UncorrelatedSELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber = 'P2');

Intermediate

Now join outer table to intermediate result

Outer Result

Page 31: Joins And Subqueries

Sub-Queries (nested)UncorrelatedSELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber = 'P2');

How many row comparisons?12 + (5 x 4) = 32

Intermediate

If formulated as a join?(5 x 12) = 60

Page 32: Joins And Subqueries

Sub-Queries (nested)UncorrelatedSELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber = 'P2');

Formulated as a Join

SELECT DISTINCT SUPPLIER.SupplierNameFROM SUPPLIER, SHIPMENTWHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber=‘P2’;

Use a join if you need columns from multiple tables. If, as in the example above, you need columns from only one table, use either a join or a subquery.

A subquery may include the GROUP BY and HAVING clauses, but not the ORDER BY and UNION.

Page 33: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)Retrieve supplier name and city for all suppliers who supply at least one galvanized part.SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

Page 34: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

PART is scanned for Metal=‘GALV’

Inner-most query first

Inner-most Intermediate

result

Page 35: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

Join SHIPMENT with Intermediate result of inner query

Inner-most Intermediate

result

Join

Intermediate SHIPMENT Result

Page 36: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

Join SUPPLIER with Intermediate result of inner query

Intermediate SHIPMENT Result

Join

Page 37: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

In Summary...(Join)

(Join)

Page 38: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIER, SHIPMENT, PARTWHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = PART.PartNumber AND PART.METAL = 'GALV';

SUPPLIER

SHIPMENT

PART

Written as a Join

Page 39: Joins And Subqueries

Sub-Queries (nested)Uncorrelated (3 tables)SELECT DISTINCTROW SUPPLIER.SupplierName, SUPPLIER.SupplierCityFROM SUPPLIERWHERE SUPPLIER.SupplierNumber IN (SELECT SHIPMENT.SupplierNumber FROM SHIPMENT WHERE SHIPMENT.PartNumber IN (SELECT PART.PartNumber FROM PART WHERE METAL = 'GALV'));

How many row comparisons for subquery?

(Join)

6 + (2*12) + (3*5) = 45

As a Join?

6*5*12 = 360

(Join)

Page 40: Joins And Subqueries

Sub-Queries (nested)An alternative formulation

SELECT T1.Item …, T2.Item… FROM table1 T1, (SELECT Item FROM table2 WHERE predicate) As T2 WHERE T1.PK = T2.FK;

In this case, the inner table is filtered by the predicate and then joined to the outer table using the alias T2. This overcomes the shortcoming of the IN method by allowing attributes from the inner table to be included in the outer SELECT. See handout for examples from class.

Page 41: Joins And Subqueries

Sub-Queries (nested)Introduction

• General structure of correlated sub-query• Using Exists

SELECT Item FROM table1 WHERE EXISTS [NOT EXISTS] (SELECT Item FROM table2 WHERE PK = FK AND predicate);

(Inner Query)

(Outer Query)

Page 42: Joins And Subqueries

Sub-Queries (nested)Introduction

• General structure of correlated sub-query• Using IN

SELECT Item FROM table1 WHERE predicate IN (SELECT Item FROM table2 WHERE PK = FK);

(Inner Query)

(Outer Query)

Page 43: Joins And Subqueries

Sub-Queries (nested)CorrelatedRetrieve supplier names for suppliers who supply part P1

SELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

Page 44: Joins And Subqueries

Sub-Queries (nested)CorrelatedRetrieve supplier names for suppliers who supply part P1

SELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

This is what makes it correlated.

The inner query is executed once for every row in the SUPPLIER table. That is, the value for SupplierNumber is passed by value into the sub-query.

Page 45: Joins And Subqueries

Sub-Queries (nested)CorrelatedRetrieve supplier names for suppliers who supply part P1

SELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

Tests if intermediate result is nonempty (empty set)

For each nonempty intermediate result, the SupplierName is selected.The EXISTS test will be performed for each row in the SUPPLIER table.

Page 46: Joins And Subqueries

Sub-Queries (nested)CorrelatedSELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

Intermediate

EXISTS?

Yes

Execute nested query

Page 47: Joins And Subqueries

Sub-Queries (nested)CorrelatedSELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

EXISTS?

Yes

Execute nested query

Intermediate

Page 48: Joins And Subqueries

Sub-Queries (nested)CorrelatedSELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

EXISTS?

No

Execute nested query

Intermediate

Page 49: Joins And Subqueries

Sub-Queries (nested)CorrelatedSELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

EXISTS isFalse for S4 and S5

Intermediate

Page 50: Joins And Subqueries

Sub-Queries (nested)CorrelatedRetrieve supplier names for suppliers who DO NOT supply part P1

SELECT SUPPLIER.SupplierNameFROM SUPPLIERWHERE NOT EXISTS (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber = SHIPMENT.SupplierNumber AND SHIPMENT.PartNumber = 'P1');

Page 51: Joins And Subqueries

Sub-Queries (nested)CorrelatedUsing “IN”

SELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE 'P1' IN (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber =SHIPMENT.SupplierNumber);

It’s still correlated.

But now, the intermediate result will be a list of PartNumbers for the current Supplier.If ‘P1’ is IN that resulting set, the SupplierName is selected.

Page 52: Joins And Subqueries

Sub-Queries (nested)CorrelatedSELECT DISTINCTROW SUPPLIER.SupplierNameFROM SUPPLIERWHERE 'P1' IN (SELECT SHIPMENT.PartNumber FROM SHIPMENT WHERE SUPPLIER.SupplierNumber =SHIPMENT.SupplierNumber);

S5

S3 S4S1 S2

Page 53: Joins And Subqueries

Sub-Queries (nested)Correlated (in HAVING clause)Find the average Weight of PARTs for each City that has at least two parts.SELECT P1.PartCity, AVG (Weight) AS AverageFROM PART P1GROUP BY P1.PartCityHAVING 1 < (SELECT COUNT(*) FROM PART P2 WHERE P1.PartCity=P2.PartCity);

Only has 1

Page 54: Joins And Subqueries

Sub-Queries (nested)Correlated (in HAVING clause)Find the average Weight of PARTs for each City that has at least two parts.SELECT P1.PartCity, AVG (Weight) AS AverageFROM PART P1GROUP BY P1.PartCityHAVING 1 < (SELECT COUNT(*) FROM PART P2 WHERE P1.PartCity=P2.PartCity);

A sub-query on the same table

Correlated with P1 cursor in the PART table

Page 55: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

• As stated in the definition of the DIVISION operator, this is a general operation for any case where you want to know if a particular instance in one table corresponds to every instance in another table.

• For example– List employees that have passed all the exams

for MS certification– List students that have taken all courses for

graduation

Page 56: Joins And Subqueries

Division

Page 206

Page 57: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

• How would you do it procedurally?

Page 58: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

An outer loop that scrolls through Suppliers

Supplier Loop

End Loop

An inner loop that scrolls through Parts for every row in Suppliers

End Loop

Part Loop An inner-most loop that scrolls through Shipment for every row in Part looking for PK=FK matchesEnd Loop

Shipment Loop

PK=FK?

Page 59: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Priming read (Supplier)While NOT EOF Supplier

Initialize exit condition to TRUEPriming read (Part)While (NOT EOF Part) AND (PK=FK found)

Set exit condition to FALSEPriming read (Shipment)While (NOT EOF Shipment) AND (NOT PK=FK found)

Evaluate PK=FKSet found booleanMove cursor (Shipment)

End While Move cursor (Part)

End WhileIf supply all parts, print Supplier Info Move cursor (Supplier)

End While

Pseudo-code

Page 60: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)

rstSupplier.MoveFirstDo While Not rstSupplier.EOF FoundPart = True rstParts.MoveFirst Do While (Not rstParts.EOF) And FoundPart FoundPart = False rstShipment.MoveFirst Do While Not rstShipment.EOF And (Not FoundPart) FoundPart = (rstShipment.Fields("PartNumber") = rstParts.Fields("PartNumber")) _ And (rstShipment.Fields("SupplierNumber") = rstSupplier.Fields("SupplierNumber")) rstShipment.MoveNext Loop rstParts.MoveNext Loop If FoundPart Then With rstSupplier picBox.Print .Fields("SupplierNumber"), .Fields("SupplierName"), .Fields("SupplierCity") End With End IfLoop

Visual BasicCourtesy Dr. Landry*

* His original code was well documented...

Page 61: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber, SUPPLIER.SupplierName

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

Starting from the inner most query and working up...

SHIPMENT, using cursor ‘S2’, ...

is scanned once for every row in PART.

SQL

Page 62: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber, SUPPLIER.SupplierName

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

PART is scanned once, ...

For every row in SHIPMENT, ...

using cursor ‘S1’.

Page 63: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber, SUPPLIER.SupplierName

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

The resulting set of SupplierNumbers from SHIPMENT using ‘S1’, ...

is joined with SUPPLIERto retrieve SupplierName

Page 64: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

Uses two cursors into SHIPMENT

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

Page 65: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(TRUE)(S1=S1) AND (P1=P1)

P1

Intermediate result

Page 66: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P2=P1)

P1

Intermediate result

Page 67: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P3=P1)

P1

Intermediate result

and so on...

Page 68: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

P1

Intermediate result

(FALSE)(S1=S1) AND (P5=P1)

Is Intermediate result empty?

NOT(True) = False

Page 69: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P5=P1)

So we don’t retrieve the PartNumber from PART

Page 70: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P1=P2)

and so on...

Now we re-run the inner-most query for the next value in PART

Page 71: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

P2

Intermediate result

(FALSE)(S1=S1) AND (P5=P2)

Is Intermediate result empty?

NOT(True) = False

Page 72: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P5=P2)

So we don’t retrieve the PartNumber from PART And this

cycle gets repeated for every row in

PART

Page 73: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P5=P6)

So we don’t retrieve the PartNumber from PART And this

cycle gets repeated for every row in

PART

Page 74: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

(FALSE)(S1=S1) AND (P5=P6)

Once we’ve searched every row in PART,

Page 75: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2for the first row in SHIPMENT, we evaluate the WHERE clause

Page 76: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2Did the inner query return an empty set?

Yes. So retrieve the SupplierNumber

S1

Intermediate result

Page 77: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2Now we move to the next row in SHIPMENT

And repeat the entire sub-query

again.

(TRUE)(S1=S1) AND (P1=P1)

Page 78: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2However... when we get to this point in the execution

(FALSE)(S1=S2) AND (P1=P3)

Page 79: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2there will be no instances of (S2=S2) AND (P3=P3)

Intermediate result

So the innermost query does not return a PartNumber

Page 80: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

Intermediate result

Yes, so...

Is Intermediate result empty?

NOT(False) = True

Page 81: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2the PART sub-query will return the PartNumber that S2 doesn’t supply

P3

Intermediate result

Page 82: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2At this point, the PART sub-query will have returned the set of Parts not supplied by S2.

P3

Intermediate result

P4

P5

P6

Page 83: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2Once we’ve searched every row in PART,

P3

Intermediate result

P4

P5

P6

Page 84: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

P3

Intermediate result

P4

P5

P6

for the Supplier ‘S2’, we evaluate the WHERE clause

Page 85: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

P3

Intermediate result

P4

P5

P6

Did the PART sub-query return an empty set?

No. So don’t retrieve the SupplierNumber ‘S2’

Page 86: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE NOT EXISTS

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber AND

S2.PartNumber = PART.PartNumber)));

S1 S2

S1

And so finally... the SupplierNumber result is joined with SUPPLIER

to get SupplierName

Page 87: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)Retrieve all the suppliers that have shipped all parts in the PART table.

SELECT SUPPLIER.SupplierNumber, SUPPLIER.SupplierName

FROM SUPPLIER

WHERE SUPPLIER.SupplierNumber IN

(SELECT SupplierNumber

FROM SHIPMENT S1

WHERE NOT EXISTS

(SELECT PART.PartNumber

FROM PART

WHERE PART.PartNumber NOT IN

(SELECT PartNumber

FROM SHIPMENT S2

WHERE S2.SupplierNumber = S1.SupplierNumber)));

An alternative formulation using IN

Page 88: Joins And Subqueries

Sub-Queries (nested)Correlated (DIVISION)List the companyname from the Suppliers table in the NorthWind database for those suppliers who supply ALL products in Category 7.