Queries using Multiple Tables

Most useful queries in a relational database require the use of two or more tables. For the purposes of this next exercise we are going to create two tables to use in conjunction with the inventory table. The Requisition table (RecEquip) and the Requisition Detail table (ReqDetail) which is a child table for the ReqEquip table to store the details for requisition request. For every record in ReqEquip there will be one or more records in the ReqDetail table. The ReqNumber column will be the common key for the two tables.

sqlite> CREATE TABLE requisition(ReqNumber INTEGER PRIMARY KEY,Requestor VARCHAR(30) NOT NULL,Auth VARCHAR(30) NOT NULL,ReqDate CHAR(10) NOT NULL);
sqlite> INSERT INTO requisition(ReqNumber,Requestor,Auth,ReqDate) VALUES (1000,'Carl Jones','A. Robinson Mgr','2007/10/30');
sqlite> INSERT INTO requisition(ReqNumber,Requestor,Auth,ReqDate) VALUES (1001,'Peter Smith','A. Robinson Mgr','2007/11/05');
sqlite> INSERT INTO requisition(ReqNumber,Requestor,Auth,ReqDate) VALUES (1002,'Carl Jones','A. Robinson Mgr','2007/11/06');
sqlite>

Renaming Tables

Using the ALTER TABLE command, let's rename the table to "ReqEquip" and verify it with the dot command ".tables".

sqlite> ALTER TABLE requisition RENAME TO ReqEquip;
sqlite> .tables
ReqEquip inventory
sqlite>

sqlite> CREATE TABLE ReqDetail(ReqNumber INTEGER,StockNumber INTEGER,Quantity INTEGER,ItemCost REAL);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1000,51013,2,7.52);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1000,51002,4,.75);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1000,43512,4,1.52);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1001,23155,1,9.82);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1001,43111,1,3.69);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1002,51001,1,.75);
sqlite> INSERT INTO ReqDetail(ReqNumber,StockNumber,Quantity,ItemCost) VALUES(1002,23155,1,9.82);
sqlite>

Dot Notation for Table-Column Names.

Since the primary key of ReqEquip and the foreign key of ReqDetail are both called "ReqNumber" it will be necessary to be explicit regarding the table from which the column is coming from. This can be done by using the notation "table name.column name"

sqlite> SELECT ReqEquip.ReqNumber,ReqEquip.Requestor,ReqDetail.Quantity,ReqDetail.StockNumber FROM ReqEquip,ReqDetail WHERE ReqEquip.ReqNumber = ReqDetail.ReqNumber;

ReqNumber Requestor Quantity StockNumber
----------  ------------  --------  ------------
1000 Carl Jones 2 51013
1000 Carl Jones 4 51002
1000 Carl Jones 4 43512
1001 Peter Smith 1 23155
1001 Peter Smith 1 43111
1002 Carl Jones 1 51001
1002 Carl Jones 1 23155
sqlite>

As it happens we are only interested in items on Requisition number 1000. Using an AND clause we can exclude the other records.

sqlite> SELECT ReqEquip.ReqNumber,ReqEquip.Requestor,ReqDetail.Quantity,ReqDetail.StockNumber FROM ReqEquip,ReqDetail WHERE ReqEquip.ReqNumber = ReqDetail.ReqNumber AND ReqEquip.ReqNumber = 1000;

ReqNumber Requestor Quantity StockNumber
----------  ------------  --------  ------------
1000 Carl Jones 2 51013
1000 Carl Jones 4 51002
1000 Carl Jones 4 43512

Adjust the width of the fields to make a clearer presentation. By adding the inventory table we are able to obtain the description of the items requisitioned.

sqlite> .width 10 12 8 8 20 10
sqlite> SELECT ReqEquip.ReqNumber, ReqEquip.Requestor, ReqDetail.StockNumber, ReqDetail.Quantity ,inventory.Descrip ,ReqDetail.ItemCost FROM ReqEquip ,ReqDetail, inventory WHERE ReqEquip.ReqNumber = ReqDetail.ReqNumber AND ReqEquip.ReqNumber = 1000 AND inventory.StockNumber = ReqDetail.StockNumber;

ReqNumber Requestor StockNum Quantity Descrip ItemCost
----------  ----------  ------------  --------  ----------------------  ----------
1000 Carl Jones 51013 2 D Dry Cells 8 Pack 7.52
1000 Carl Jones 51002 4 AA Dry Cells 4 Pack 0.75
1000 Carl Jones 43512 4 10W-30 Motor Oil, Qu 1.52
sqlite>

Using an alias for a table name in a Query

When writing complex queries with dot notation it is sometimes helpful to reference each table with a short alias particularly if the table names are long and similar in spelling.

SELECT column_1,column_2 FROM table_name_1 AS alias_1, table_name_2 AS alias_2 ;

sqlite> SELECT a.ReqNumber, a.Requestor, b.StockNumber, b.Quantity ,c.Descrip , b.ItemCost FROM ReqEquip AS a ,ReqDetail AS b , inventory AS c WHERE a.ReqNumber = b.ReqNumber AND a.ReqNumber = 1000 AND c.StockNumber = b.StockNumber;

ReqNumber Requestor StockNum Quantity Descrip ItemCost
----------  ----------  ------------  --------  ----------------------  ----------
1000 Carl Jones 51013 2 D Dry Cells 8 Pack 7.52
1000 Carl Jones 51002 4 AA Dry Cells 4 Pack 0.75
1000 Carl Jones 43512 4 10W-30 Motor Oil, Qu 1.52
sqlite>

Cartesian Products

Cartesian Product - What happens if tables in a select query are not related properly.
The following example has two tables. One, the "managerlist" table listing store managers, their assigned store (store_assn) along with other information about the employee and the "storelist" table listing information about the store's location with the primary key, "store_number" which relates to the to "store_assn"" column in the "managerlist". The objective is to produce a list of Managers and the City and State where their assigned store is located.

sqlite> SELECT employee_id,last_name,first_name,start_date,store_assn FROM managerlist;

employee_id last_name first_name start_date store_assn
------------ ----------------  ----------------  ----------  ----------
456 Walters Joanna 2006-06-14 23
532 Niels Matthew 2007-02-09 35
637 Simpson Robert 2008-01-21 27
sqlite> SELECT store_number,city,state FROM storelist;
store_number city state
------------  ----------------  ----------------
23 Bowie MD
27 Scranton PA
35 Allentown PA
sqlite>

When dealing with two or more tables it is very important to join or relate the tables properly, if you fail to do so you will likely create what is known as a cartesian product as shown below. Notice that the records in each table have been the matched against each other resulting in nine rows. Two thirds of the result list an incorrect location for specified store number.

sqlite> .width 20 10 12 20 sqlite> SELECT (last_name||', '||first_name) AS 'Manager', employee_id AS 'Manager ID', store_assn AS 'Store Number', city||', '||state AS 'Location' FROM managerlist, storelist;

Manager Manager ID Store Number Location
--------------------  ----------  ------------  --------------------
Walters, Joanna 456 23 Bowie, MD
Walters, Joanna 456 23 Scranton, PA
Walters, Joanna 456 23 Allentown, PA
Niels, Matthew 532 35 Bowie, MD
Niels, Matthew 532 35 Scranton, PA
Niels, Matthew 532 35 Allentown, PA
Simpson, Robert 637 27 Bowie, MD
Simpson, Robert 637 27 Scranton, PA
Simpson, Robert 637 27 Allentown, PA
sqlite>

The following is the correct query with a proper WHERE clause.

sqlite> SELECT (last_name||', '||first_name) AS 'Manager', employee_id AS 'Manager ID', store_assn AS 'Store Number', city||', '||state AS 'Location' FROM managerlist, storelist WHERE store_assn = store_number;

Manager Manager ID Store Number Location
--------------------  ----------  ------------  --------------------
Walters, Joanna 456 23 Bowie, MD
Niels, Matthew 532 35 Allentown, PA
Simpson, Robert 637 27 Scranton, PA
sqlite>


Colin Riley -- May 2011 --