SELECT class_nbr, class_size, MINroom_size FROM Rooms, Classes WHERE Classes.class_size < Rooms.room_size GROUP BY class_nbr, class_size; This will give a result table with the desired
Trang 1SELECT class_nbr, class_size, MIN(room_size) FROM Rooms, Classes
WHERE Classes.class_size < Rooms.room_size GROUP BY class_nbr, class_size;
This will give a result table with the desired room sizes, but not the room numbers You cannot put the other columns in the SELECT list, since it would conflict with the GROUP BY clause But also note that the classroom with 85 seats (‘r4’) is used twice, once by class ‘c1’ and then by class ‘c2’:
Result class_nbr class_size MIN(room_size) ====================================
'c1' 80 85 <== room r4 'c2' 70 85 <== room r4
'c3' 65 70
'c4' 55 65
'c5' 50 55
'c6' 40 50
Your best bet after this is to use the query in an EXISTS clause
SELECT * FROM Rooms, Classes WHERE EXISTS (SELECT class_nbr, class_size, MIN(room_size) FROM Rooms, Classes
WHERE Classes.class_size < Rooms.room_size GROUP BY class_nbr, class_size);
However, some versions of SQL will not allow a grouped subquery, and others will balk at an aggregate function in an EXISTS predicate The only way I have found to rectify this is to save the results to a temporary table, then JOIN it back to the Cartesian product of Rooms and Classes Putting the columns for Rooms into the SELECT list of the same query schema can do the second T-Join:
SELECT room_nbr, room_size, MAX(class_size) FROM Rooms, Classes
WHERE Classes.class_size < Rooms.room_size GROUP BY room_nbr, room_size;
Trang 2This time, the results are the same as those Dr Codd got with his procedural algorithm:
Result
room_nbr room_size MAX(class_size)
======================================
'r4' 85 80
'r1' 70 65
'r6' 65 55
'r7' 55 50
'r3' 50 40
If you do a little arithmetic on the data, you find that we have 360 students and 395 seats, 6 classes and 7 rooms This solution uses the fewest rooms, but note that the 70 students in class ‘c2’ are left out completely Room ‘r2’ is left over, but it has only 40 seats
As it works out, the best fit of rooms to classes is given by changing the matching rule to “less than or equal.” This will leave the smallest room empty and pack the other rooms to capacity, thus:
SELECT class_nbr, class_size, MIN(room_size)
FROM Rooms, Classes
WHERE Classes.class_size <= Rooms.room_size
GROUP BY class_nbr, class_size;
17.8.1 The Croatian Solution
I published this same problem in an article in DBMS magazine (Celko
1992a) and got an answer in QUEL from Miljenko Martinis of Croatia in our Letters column (Miljenko 1992) He then translated it from QUEL into SQL with two views, thus:
CREATE VIEW Classrooms all possible legal pairs
AS SELECT *
FROM Classes, Rooms
WHERE class_size < room_size;
CREATE VIEW Classrooms1 smallest room for the class
AS SELECT *
FROM Classrooms AS CR1
WHERE room_size = (SELECT MIN(room_size)
FROM Classrooms
WHERE class_nbr = CR1.class_nbr);
Trang 3We find the answer with the simple query:
SELECT class_nbr, class_size, room_size, room_nbr FROM Classrooms1 AS CR1
WHERE class_size = (SELECT MAX(class_size) FROM Classrooms1 WHERE room_nbr = CR1.room_nbr);
class_nbr class_size room_size room_nbr ==========================================
'c6' 40 50 'r3' 'c5' 50 55 'r7' 'c4' 55 65 'r6' 'c3' 65 70 'r1' 'c1' 80 85 'r4'
17.8.2 The Swedish Solution
I got another solution from Anders Karlsson of Mr K Software AB in Stockholm, Sweden Here is a version of that query:
SELECT C1.class_nbr, C1.class_size, R1.room_size, R1.room_nbr FROM Classes AS C1, Rooms AS R1
WHERE C1.class_size = (SELECT MAX(C2.class_size) FROM Classes AS C2 WHERE R1.room_size > C2.class_size) AND NOT EXISTS (SELECT *
FROM Rooms AS R2 WHERE R2.room_size > C1.class_size AND R2.room_size < R1.room_size);
The first predicate says we have the largest class that will go into this room The second predicate says there is no other room that would fit this class better (i.e., a room that is smaller than the candidate room and still larger than the class at which we are looking)
17.8.3 The Colombian Solution
Francisco Moreno of the Department of Systems Engineering at the University of Antioquia in Colombia came up with another approach and data to demonstrate the problems in the T-Join
Clean out the existing tables and insert this data:
Trang 4DELETE FROM Classes;
INSERT INTO Classes
VALUES ('c1', 106),
('c2', 105),
('c3', 104),
('c4', 100),
('c5', 99),
('c6', 90),
('c7', 89),
('c8', 88),
('c9', 83),
('c10', 82),
('c11', 81),
('c12', 65),
('c13', 50),
('c14', 49),
('c15', 30),
('c16', 29),
('c17', 28),
('c18', 20),
('c19', 19);
DELETE FROM Rooms;
INSERT INTO Rooms
VALUES ('r1', 102),
('r2', 101),
('r3', 95),
('r4', 94),
('r5', 85),
('r6', 70),
('r7', 55),
('r8', 54),
('r9', 35),
('r10', 34),
('r11', 25),
('r12', 18);
Using Codd’s T-Join algorithm for descending lists, you would have this mapping:
Trang 5
'c1' 106 'c2' 105 'c3' 104 'c4' 100 < -> 'r1' 102 'c5' 99 < -> 'r2' 101 'c6' 90 < -> 'r3' 95 'c7' 89 < -> 'r4' 94 'c8' 88
'c9' 83 < -> 'r5' 85 'c10' 82
'c11' 81 'c12' 65 < -> 'r6' 70 'c13' 50 < -> 'r7' 55 'c14' 49 < -> 'r8' 54 'c15' 30 < -> 'r9' 35 'c16' 29 < -> 'r10' 34 'c17' 28
'c18' 20 < -> 'r11' 25 'c19' 19
'r12' 18
There are 1,317 students in classes, and 768 seats for them You can see by inspection that some classes are too large for any room we have If you started in ascending order, class ‘c19’ pairs with room ‘r11’ and you get another result set
This algorithm is not a best-fit answer, but a first fit answer This is an important difference To explain further, the first fit to class ‘c4’ is room
‘r1’, which has 102 seats; however, the best fit is room ‘r2, which has 101 seats The algorithm would give us this result table:’
Results class_nbr class_size room_size room_nbr
==========================================
'c4' 100 102 'r1' 'c5' 99 101 'r2' 'c6' 90 95 'r3' 'c7' 89 94 'r4' 'c9' 83 85 'r5' 'c12' 65 70 'r6' 'c13' 50 55 'r7' 'c14' 49 54 'r8'
Trang 6'c15' 30 35 'r9'
'c16' 29 34 'r10'
'c18' 20 25 'r11'
704 students served.
If you use Swedish or Croatian solution on this data, the answer is: Swedish Result
class_nbr class_size room_size room_nbr
============================================
'c4' 100 101 'r2'
'c6' 90 94 'r4'
'c9' 83 85 'r5'
'c12' 65 70 'r6'
'c13' 50 54 'r8'
'c15' 30 34 'r10'
'c18' 20 25 'r11'
438 students served.
At this point you have a result that is not complete but has the tightest mapping of each class into a room There is another problem that was not mentioned: we have not had two classes or two rooms of the same size in the data This will cause some other problems
Instead of trying to use a single static SQL query, we can use SQL to generate SQL code, then execute it dynamically This solution is right but, of course, is horrible from a performance viewpoint
build a table of possible T-Join pairings
DROP TABLE T-Join;
CREATE TABLE T-Join AS
SELECT *
FROM Classes, Rooms
WHERE room_size > class_size;
create a temporary working table
DROP TABLE Ins;
CREATE TABLE Ins
(class_nbr CHAR(3) NOT NULL,
class_size INTEGER NOT NULL,
Trang 7room_nbr CHAR(3) NOT NULL, room_size INTEGER NOT NULL);
create a table with the insertion code for each row SELECT
'INSERT INTO Ins SELECT class_nbr, class_size, room_nbr, room_size FROM T-Join AS T1
WHERE room_size = (SELECT MAX(room_size) FROM T-Join
WHERE room_size NOT IN (SELECT room_size FROM Ins)) AND class_size
= (SELECT MAX(class_size) FROM T-Join AS T2 WHERE class_size NOT IN (SELECT class_size FROM Ins) AND T2.class_size < T1.room_size);'
FROM Rooms WHERE room_size > (SELECT MIN(class_size) FROM c);
COMMIT;
Now use "SELECT a, b, c FROM Ins;" query in a host program with dynamic SQL and execute each statement in the temporary table in order This will give us the first answer at the start of Section 17.8.3, and
it also works for the original data
Moreno’s second solution, which handles duplicates, is more complex, and I will not give it here It uses the keys of the tables to make rows with duplicate values unique
Trang 8C H A P T E R
18
VIEWs, Derived Tables, Materialized
Tables, and Temporary Tables
VIEWS, DERIVED TABLES, MATERIALIZED tables and temporary tables are ways of putting a query into a named schema object By that, I mean they hold the query, rather than the results of the query
A VIEW is also called a virtual table, to distinguish it from temporary and base tables The definition of a VIEW requires that it act
as if an actual physical table is created when its name is invoked Whether or not the database system actually materializes the results or uses other mechanisms to get the same effect is implementation-defined The definition of a VIEW is kept in the schema tables to be invoked by name wherever a table could be used If the VIEW is updatable, then additional rules apply
The SQL Standard separates administrative (DBA) privileges from user privileges Table creation is administrative and query execution is
a user privilege, so users cannot create their own VIEWs or TEMPORARY TABLEs without having Administrative privileges granted
to them
In the Standard SQL model, a temporary table acts very much like a base table It is persistent in the schema, but it “cleans itself up” automatically so users do not have to bother, and it can be shared among several users The temporary table has the same user privileges model as a base table
Trang 9370 CHAPTER 18: VIEWS, DERIVED TABLES, MATERIALIZED TABLES, AND TEMPORARY TABLES
However, a user can build a derived table inside a query This is like building a VIEW on the fly With the AS operator, we can give names to the results of subquery expressions and use them The syntax is very simple, but the scoping rules often confuse new users
(<query expression>)
AS <table name> [(<column list>)]
You can think of a VIEW’s name being replaced by a derived table expression when it is invoked in a query
The Standard SQL syntax for the VIEW definition is CREATE VIEW <table name> [(<view column list>)]
AS <query expression>
[WITH [<levels clause>] CHECK OPTION]
<levels clause> ::= CASCADED | LOCAL
The <levels clause> option in the WITH CHECK OPTION did not exist in SQL-89, and it is still not widely implemented Section 18.5
of this chapter will discuss this clause in detail This clause has no effect
on queries, but only on UPDATE, INSERT INTO, and DELETE FROM statements
A VIEW is different from a TEMPORARY TABLE, a derived table, or a base table You cannot put constraints on a VIEW, as you can with base and TEMPORARY tables A VIEW has no existence in the database until it
is invoked, while a TEMPORARY TABLE is persistent A derived table exists only in the query in which it is created
The name of the VIEW must be unique within the database schema, like a table name The VIEW definition cannot reference itself, since it does not exist yet Nor can the definition reference only other VIEWs; the nesting of VIEWs must eventually resolve to underlying base tables This only makes sense if no base tables were involved, what would you
be viewing?
Trang 1018.2 Updatable and Read-Only VIEWs 371
Unlike base tables, VIEWs are either updatable or read-only, but not
both INSERT, UPDATE, and DELETE operations are allowed on
updatable VIEWs and base tables, subject to any other constraints
INSERT, UPDATE, and DELETE are not allowed on read-only VIEWs, but
you can change their base tables, as you would expect
An updatable VIEW is one that can have each of its rows associated
with exactly one row in an underlying base table When the VIEW is
changed, the changes pass unambiguously through the VIEW to that
underlying base table Updatable VIEWs in Standard SQL are defined
only for queries that meet these criteria:
1 Built on only one table
2 No GROUP BY clause
3 No HAVING clause
4 No aggregate functions
5 No calculated columns
6 No UNION, INTERSECT, or EXCEPT
7 No SELECT DISTINCT clause
8 Any columns excluded from the VIEW must be NULL-able or
have a DEFAULT in the base table, so that a whole row can be constructed for insertion
By implication, the VIEW must also contain a key of the table In
short, we are absolutely sure that each row in the VIEW maps back to
one and only one row in the base table
Some updating is handled by the CASCADE option in the referential
integrity constraints on the base tables, not by the VIEW declaration
The definition of updatability in Standard SQL is actually fairly
limited, but very safe The database system could look at information it
has in the referential integrity constraints to widen the set of allowed
updatable VIEWs You will find that some implementations are now
doing just that, but it is not common yet The SQL Standard definition of
an updatable VIEW is actually a subset of the possible updatable VIEWs,
and a very small subset at that The major advantage of this definition is
that it is based on syntax and not semantics For example, these VIEWs
are logically identical: