Tải bản đầy đủ (.pdf) (10 trang)

Joe Celko s SQL for Smarties - Advanced SQL Programming P40 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (237.17 KB, 10 trang )

362 CHAPTER 17: THE SELECT STATEMENT
SELECT 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;
17.8 Dr. Codd’s T-Join 363
This 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);
364 CHAPTER 17: THE SELECT STATEMENT
We 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:
17.8 Dr. Codd’s T-Join 365
DELETE 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:

366 CHAPTER 17: THE SELECT STATEMENT
'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'
17.8 Dr. Codd’s T-Join 367
'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,
368 CHAPTER 17: THE SELECT STATEMENT
room_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.

CHAPTER

18

VIEWs, Derived Tables, Materialized
Tables, and Temporary Tables

V


IEWS, 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


VIEW

s or

TEMPORARY TABLE

s 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.

370

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.

18.1 VIEWs in Queries

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

VIEW

s;
the nesting of

VIEW

s must eventually resolve to underlying base tables.
This only makes sense if no base tables were involved, what would you
be viewing?

18.2 Updatable and Read-Only VIEWs 371

18.2 Updatable and Read-Only VIEWs

Unlike base tables,

VIEW

s are either updatable or read-only, but not
both.

INSERT

,

UPDATE


, and

DELETE

operations are allowed on
updatable

VIEW

s and base tables, subject to any other constraints.

INSERT

,

UPDATE

, and

DELETE

are not allowed on read-only

VIEW

s, 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

VIEW

s 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


VIEW

s. 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

VIEW

s,
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

VIEW

s
are logically identical:

×