1. Trang chủ
  2. » Công Nghệ Thông Tin

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

10 142 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 237,17 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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 1

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;

Trang 2

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

Trang 3

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:

Trang 4

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:

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 7

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

Trang 8

C 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 9

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

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 10

18.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:

Ngày đăng: 06/07/2014, 09:20

TỪ KHÓA LIÊN QUAN