laborator baze date

537
1 DATABASES LAB NOTES Christian Mancas Assoc. Prof. Dr., Mathematics and Computer Science Dept., Ovidius University Constanta and Engineering in Foreign Languages Dept., Bucharest Polytechnic University Database Architect, Asentinel Intl. srl, Bucharest Alina Iuliana Dicu Drd., Engineering in Foreign Languages Dept., Bucharest Polytechnic University Business Intelligence Consultant, VIEW srl, Bucharest Bucharest Polytechnic University Press 2014

Upload: eancrimicri

Post on 22-Apr-2017

313 views

Category:

Documents


28 download

TRANSCRIPT

Page 1: Laborator Baze date

1

DATABASES LAB NOTES

Christian Mancas

Assoc. Prof. Dr., Mathematics and Computer Science Dept., Ovidius

University Constanta and

Engineering in Foreign Languages Dept., Bucharest Polytechnic

University

Database Architect, Asentinel Intl. srl, Bucharest

Alina Iuliana Dicu

Drd., Engineering in Foreign Languages Dept., Bucharest Polytechnic

University

Business Intelligence Consultant, VIEW srl, Bucharest

Bucharest Polytechnic University Press

2014

Page 2: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

2

Contents Volume I: Data definition and manipulation in SQL ....................................... 12

Chapter 1. 1st Lab: DDL statements in SQL and GUI ........................................... 13

1.1 Introduction .............................................................................................. 13

1.2 Exercises ................................................................................................... 13

1.2.1 Creating and opening an Access database ........................................ 15

1.2.2 Creating tables in Access with Design View (QBE) ............................ 15

1.2.3 Creating tables in Access with SQL DDL statements ......................... 37

1.2.4 Creating and opening an Oracle database ........................................ 39

1.2.5 Creating tables in Oracle with the SQL Developer GUI ...................... 51

1.2.6 Creating tables in Oracle with SQL DDL statements.......................... 68

1.3 Best practice rules .............................................................................. 74

1.4 Homework .......................................................................................... 75

Chapter 2. 2nd Lab: Transactional DML statements in SQL and GUI ................... 76

2.1 Transactional SQL DML statements.......................................................... 76

2.2 Exercises ............................................................................................. 77

2.2.1 Prerequisites in Access ...................................................................... 77

2.2.2 Exercises in Access ............................................................................. 84

2.2.3 Prerequisites in Oracle ...................................................................... 95

2.2.4 Exercises in Oracle ........................................................................... 102

2.3 Best practice rules .................................................................................. 117

2.4 Homework ........................................................................................ 118

Chapter 3. 3rd Lab: INNER JOIN, GROUP BY, and HAVING clauses ................... 119

3.1 Introduction ...................................................................................... 119

3.2 The algorithm for assisting DML statements design ........................ 120

3.3 Exercises in Access ............................................................................ 122

3.4 Exercises in Oracle ............................................................................ 135

3.5 Best practice rules ............................................................................ 156

Page 3: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

3

3.5 Homework ........................................................................................ 157

Chapter 4. 4th Lab: Outer Joins, the Is Null predicate, and UNIONs ................. 158

4.1 Prerequisites in Access ........................................................................... 158

4.1.1 Adding needed countries to the COUNTRIES table ......................... 158

4.1.2 Adding the NEIGHBORS table and populating its instance ............. 158

4.2 Exercises in Access .................................................................................. 160

4.3 Prerequisites in Oracle ........................................................................... 170

4.1.1 Adding needed countries to the COUNTRIES table ......................... 170

4.1.2 Adding the NEIGHBORS table and populating its instance ............. 171

4.4 Exercises in Oracle .................................................................................. 173

4.5 Best practice rules .................................................................................. 187

4.6 Homework .............................................................................................. 187

Chapter 5. 5th Lab: Self-Joins and Transitive Closures ...................................... 189

5.1 Exercises in Access .................................................................................. 189

5.2 Exercises in Oracle .................................................................................. 206

5.3 Best practice rules .................................................................................. 225

5.4 Homework .............................................................................................. 225

Chapter 6. 6th Lab: First test (SQL) .................................................................... 228

6.1 Number 1 ................................................................................................ 228

6.1.1 Access solution ................................................................................ 229

6.1.2 Oracle solution ................................................................................ 232

6.2 Number 2 ................................................................................................ 236

6.2.1 Access solution ................................................................................ 238

6.2.2 Oracle solution ................................................................................ 241

6.3 Best practice rules .................................................................................. 244

6.4 Homework .............................................................................................. 244

Page 4: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

4

Volume II: Database design ....................................................................... 246

Chapter 7. 7th Lab: Business Analysis ............................................................... 247

7.1 Exercises ................................................................................................. 247

7.2 Best practice rules .................................................................................. 267

7.3 Homework .............................................................................................. 267

Chapter 8. 8th Lab: Elementary mathematic db schemes ................................ 269

8.1 Exercises ................................................................................................. 269

8.2 Best practice rules .................................................................................. 281

8.3 Homework .............................................................................................. 281

Chapter 9. 9th Lab: Analyzing E-RD cycles ......................................................... 282

9.1 Exercises ................................................................................................. 282

9.2 Best practice rules .................................................................................. 290

9.3 Homework .............................................................................................. 291

Chapter 10. 10th Lab: Enforcing non-relational constraints ............................. 292

10.1 Prerequisites in Access: Forms and Event-Driven Methods ................. 292

10.1.1 Forms/reports GUI: controls and properties ................................. 295

10.1.2 Forms/reports VBA classes: event-driven and ordinary methods 303

10.1.3 VBA programming techniques and tips ......................................... 304

10.1.4 VBA and SQL Functions .................................................................. 312

10.2 Exercises in Access ................................................................................ 316

10.3 Prerequisites in Oracle: Triggers .......................................................... 321

10.4 Exercises in Oracle ................................................................................ 321

10.5 Best practice rules ................................................................................ 321

10.6 Homework ............................................................................................ 321

Chapter 11. 11th Lab: Reporting in Access & 2nd DB test training ..................... 322

11.1 Reporting in Access............................................................................... 322

11.1.1 Prerequisites .................................................................................. 322

11.1.2 Exercises ........................................................................................ 338

Page 5: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

5

11.2 2nd DB test training ............................................................................... 346

11.2.1 Access implementation ..................................................................... 354

11.2.2 Oracle implementation ..................................................................... 362

11.3 Best practice rules ................................................................................ 362

11.4 Homework ............................................................................................ 362

Chapter 12. 12th Lab: Second Test (DB Design & Implementation) ................. 364

12.1 Subject 1 ............................................................................................... 364

12.2.1 Access implementation ..................................................................... 369

12.1.2 Oracle implementation ..................................................................... 373

12.2 Subject 2 ............................................................................................... 373

12.2.1 Access implementation ..................................................................... 373

12.2.2 Oracle implementation ..................................................................... 373

Chapter 13. 13th Lab: Test Redoing (SQL or DB Design & Implementation) ..... 374

13.1 SQL test redoing ................................................................................... 374

6.1.1 Access solution ................................................................................ 375

6.1.2 Oracle solution ................................................................................ 377

13.2 DB design and implementation test redoing ....................................... 382

13.2.1 Access implementation ..................................................................... 387

13.2.2 Oracle implementation ..................................................................... 391

Chapter 14. 14th Lab: Projects Defense ............................................................ 392

Conclusion ........................................................................................................ 393

References ........................................................................................................ 394

Page 6: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

6

Appendix 1: DB Project Example ...................................................................... 395

Design, implementation, and usage of a Library db......................................... 395

Table of Contents ............................................................................................. 396

1. Business Analysis ...................................................................................... 397

1.0 Description of the sub-universe of discourse ................................... 397

1.1 Entity-Relationship Diagrams ........................................................... 398

1.2 Associated Restrictions List .............................................................. 399

2. Mathematical Scheme .............................................................................. 403

2.0 Initial Mathematical Scheme ............................................................ 403

2.1 First refinement algorithm: Sets, Functions, and Constraints Design

Assistance ..................................................................................................... 404

2.1.1 Sets .................................................................................................. 404

2.1.2 Functions ......................................................................................... 405

2.1.3 Constraints....................................................................................... 409

2.2 Second refinement algorithm: Keys Discovery Assistance ............... 410

2.3 Third refinement algorithm: E-RD Cycles Analysis ........................... 413

2.3.1 First commutative-type cycle .......................................................... 414

2.3.2 First generalized commutative-type cycle ....................................... 414

2.3.3 Second generalized commutative-type cycle .................................. 416

2.3.4 Second commutative-type cycle ...................................................... 417

2.3.5 Third generalized commutative-type cycle .............................. 417

2.3.6 Third commutative-type cycle ......................................................... 418

2.4 Final Mathematical Scheme ............................................................. 419

3. Relational Scheme and Associated Non-relational Constraints List ......... 422

3.0 Relational db scheme ....................................................................... 422

3.1 Non-relational constraints list .......................................................... 425

4. Database Implementation ........................................................................ 426

4.0 Technology choice ............................................................................ 426

Page 7: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

7

4.1 Access db .......................................................................................... 427

4.1.0 DDL statements for creating and populating the db ................ 427

4.1.1 Tables Relationships ................................................................. 429

4.1.2 Table Lookups SQL statements ................................................. 429

4.1.3 Validation rules, Comments, and Default values .................... 432

4.2 Oracle db .......................................................................................... 437

5. Non-relational constraints enforcement .................................................. 437

5.1 Access solutions ................................................................................ 437

5.1.1 Edition : VOLUMES EDITIONS, onto ............................................ 437

5.1.2 CP6 ................................................................................................... 444

5.1.3 CVC4 ................................................................................................ 444

5.1.4 CVC5 ................................................................................................ 444

5.1.5 CBL5 ................................................................................................. 444

5.1.6 CBL6 ................................................................................................. 445

5.1.7 CBL7 ................................................................................................. 447

5.1.8 ACC1 ................................................................................................ 448

5.2 Oracle solutions ...................................................................................... 449

6. Database Usage ........................................................................................ 449

6.1 Access Queries and Reports ............................................................. 449

6.1.1 Queries ............................................................................................ 449

6.1.2 Reports ............................................................................................ 453

6.2 Oracle Views and Stored Procedures ............................................... 456

7. Conclusion ................................................................................................ 456

8. Bibliography .............................................................................................. 457

Page 8: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

8

Appendix 2: VBA and SQL functions by categories .......................................... 458

A2.1 String processing functions .................................................................. 458

A2.1.1 LCase ............................................................................................. 458

A2.1.2 UCase ............................................................................................ 458

A2.1.3 Len ................................................................................................. 458

A2.1.4 Left and Right ................................................................................ 458

A2.1.5 LTrim, RTrim, and Trim .................................................................. 459

A2.1.6 StrReverse ..................................................................................... 459

A2.1.7 InStr ............................................................................................... 459

A2.1.8 InStrB ............................................................................................. 460

A2.1.9 InstrRev ......................................................................................... 460

A2.1.10 Replace ........................................................................................ 461

A2.1.11 StrComp ....................................................................................... 462

A2.1.12 Space ........................................................................................... 462

A2.1.13 String ........................................................................................... 462

A2.1.14 StrConv ........................................................................................ 463

A2.1.15 Join .............................................................................................. 464

A2.1.16 Split.............................................................................................. 465

A2.2 Data types associated functions .......................................................... 465

A2.2.1 IsNull .............................................................................................. 465

A2.2.2 IsEmpty .......................................................................................... 466

A2.2.3 TypeName ..................................................................................... 466

A2.2.4 VarType ......................................................................................... 467

A2.2.5 IsDate ............................................................................................ 468

A2.2.6 IsNumeric ...................................................................................... 468

A2.2.7 IsArray ........................................................................................... 468

A2.2.8 IsMissing ........................................................................................ 468

A2.2.9 IsObject ......................................................................................... 469

Page 9: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

9

A2.2.10 IsError .......................................................................................... 469

A2.3 Date functions ...................................................................................... 469

A2.3.1 Date and Date$ ............................................................................. 469

A2.3.2 Time and Time$ ............................................................................. 469

A2.3.3 Now ............................................................................................... 469

A2.3.4 DatePart ........................................................................................ 470

A2.3.5 DateSerial ...................................................................................... 472

A2.3.6 TimeSerial ...................................................................................... 473

A2.3.7 DateValue ...................................................................................... 473

A2.3.8 TimeValue ..................................................................................... 474

A2.3.9 DateAdd ........................................................................................ 474

A2.3.10 DateDiff ....................................................................................... 475

A2.3.11 Day .............................................................................................. 476

A2.3.12 Weekday ..................................................................................... 477

A2.3.13 WeekdayName ............................................................................ 477

A2.3.14 Month .......................................................................................... 477

A2.3.15 MonthName ................................................................................ 478

A2.3.16 Year ............................................................................................. 478

A2.3.17 Hour ............................................................................................. 478

A2.3.18 Minute ......................................................................................... 478

A2.3.19 Second ......................................................................................... 478

A2.4 Numeric functions ................................................................................ 479

A2.4.1 Abs ................................................................................................. 479

A2.4.2 Int and Fix ...................................................................................... 479

A2.4.3 Partition ......................................................................................... 479

A2.4.4 Round ............................................................................................ 480

A2.4.5 Sgn ................................................................................................. 480

A2.4.6 Rnd ................................................................................................ 481

Page 10: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

10

A2.4.7 Trigonometric and other algebraic functions ............................... 482

A2.4.8 Derived Math Functions ................................................................ 482

A2.5 Conversion functions ........................................................................... 484

A2.5.1 Str .................................................................................................. 486

A2.5.2 Val .................................................................................................. 486

A2.5.3 Format ........................................................................................... 487

A2.5.4 FormatCurrency ............................................................................ 497

A2.5.5 FormatDateTime ........................................................................... 498

A2.5.6 FormatNumber .............................................................................. 499

A2.5.7 FormatPercent .............................................................................. 499

A2.5.8 Asc, AscB, and AscW ...................................................................... 500

A2.5.9 Chr, ChrB, and ChrW ...................................................................... 500

A2.5.10 Hex .............................................................................................. 500

A2.5.11 Oct ............................................................................................... 501

A2.5.12 CVErr............................................................................................ 501

A2.6 Program flow control functions ........................................................... 502

A2.6.1 IIf ................................................................................................... 502

A2.6.2 Switch ............................................................................................ 502

A2.6.3 Choose ........................................................................................... 503

A2.6.4 CallByName ................................................................................... 503

A2.6.5 DoEvents ....................................................................................... 504

A2.7 File functions ........................................................................................ 505

A2.7.1 FileAttr ........................................................................................... 505

A2.7.2 FileDateTime ................................................................................. 505

A2.7.3 FileLen ........................................................................................... 505

A2.7.4 LOF ................................................................................................ 506

A2.7.5 FreeFile .......................................................................................... 506

A2.7.6 Input .............................................................................................. 506

Page 11: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

11

A2.7.7 Loc ................................................................................................. 507

A2.7.8 Seek ............................................................................................... 507

A2.7.9 EOF ................................................................................................ 507

A2.8 Other operating system functions ....................................................... 508

A2.8.1 Shell ............................................................................................... 508

A2.8.2 CurDir ............................................................................................ 509

A2.8.3 Dir .................................................................................................. 509

A2.8.4 GetAttr .......................................................................................... 511

A2.8.5 Environ .......................................................................................... 511

A2.8.6 GetAllSettings ................................................................................ 512

A2.8.7 GetSetting ..................................................................................... 512

A2.8.8 Spc ................................................................................................. 513

A2.8.9 Tab ................................................................................................. 513

A2.9 Array functions ..................................................................................... 514

A2.9.1 Array .............................................................................................. 514

A2.9.2 Filter .............................................................................................. 515

A2.9.3 LBound .......................................................................................... 516

A2.9.4 UBound.......................................................................................... 516

A2.10 Miscellanea functions ........................................................................ 517

A2.10.1 Error ............................................................................................ 517

A2.10.2 QBColor ....................................................................................... 517

A2.10.3 RGB .............................................................................................. 518

A2.10.4 CreateObject ............................................................................... 519

A2.10.5 GetObject .................................................................................... 520

A2.10.6 Financial functions ...................................................................... 522

Subject Index .................................................................................................... 523

Page 12: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

12

Volume I: Data

definition and

manipulation in SQL

Page 13: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

13

Chapter 1. 1st Lab: DDL statements in SQL and GUI

1.1 Introduction SQL stands for Structured Query Language.

There are 2 SQL standards:

1. The pure one (based on first order logic and union), called ANSI

92

2. The extended one, including recursiveness and object-oriented

(nested tables), called ANSI 99

This semester we will study only pure SQL.

SQL is divided into 2 sublanguages:

1. DDL (Data Definition Language) – it is including all the state-

ments for modifying db structure (e.g. Create, Alter, Drop db/table

/constraint/index/user/group/etc., Grant/Revoke rights, etc.);

Note that, except for DROP (which is, trivially, also deleting cor-

responding data) no other DDL statement is affecting data instan-

ces.

2. DML (Data Manipulation Language) – used to retrieve and

manipulate data, without affecting the database structure (see fol-

lowing labs).

1.2 Exercises P1.1 Create a database (db) for storing data about countries (x, Country

(Name), Capital, Nationality, Population) and cities (x, City (Name),

Country).

Moreover, note that (at this level of refinement) City Country : CITIES

ASCII(128) COUNTRIES is minimally one-to-one (as there may not

be two cities having same name in a same country, which is, by the way,

true for very big cities).

Page 14: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

14

Solution:

Please first note that neither cities, nor countries are character strings, but

objects! Then, note that between these 2 distinct sets there are 2 functions

(see figure 1.0):

Country : CITIES COUNTRIES (whose graph is storing, for each city,

the country to which it belongs) and

Capital : COUNTRIES CITIES (whose graph is storing, for each coun-

try, the city which is its capital; note that this function is one-to-one, as no

city may simultaneously be the capital of more than one country).

Figure 1.0 Functions between sets COUNTRIES and CITIES

As you will see in your db lectures, sets are implemented via tables and

functions via columns (with structural functions –that is functions taking

values from object sets– via foreign keys).

Obviously, the rest of the functions (one-to-one, when is replaced by

) to be implemented are the following:

x : COUNTRIES NAT(3)

Country : COUNTRIES ASCII(255)

Nationality : COUNTRIES ASCII(255) NULLS

Population : COUNTRIES [100, 2000000000] NULLS

x : CITIES NAT(8)

City : CITIES ASCII(128)

where NAT(n) = {x NAT | x < 10,0000,000 } and ASCII(l) = {x

ASCII* | Length(x) l} are finite subsets of the naturals and, respec-

tively, the freely generated monoid over the ASCII alphabet.

Country

Capital COUNTRIES CITIES

Page 15: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

15

1.2.1 Creating and opening an Access database

Let start’s now create these tables in MS Access, by using its GUI:

First, please create on D: (the students’ logical drive on the lab’s PCs) a

folder with your group name and your name -> right click in that folder ->

create new Microsoft Access database-> re-name it -> double-click on it

to open it -> click on Enable Content.

1.2.2 Creating tables in Access with Design View (QBE)

QBE stands for Query-by-Example; MS Design View (both in Access and

SQL Server) is just a QBE implementation.

Click on Create -> Table ->Design View.

Type x in the first row of Field Name and choose AutoNumber1 for Data

Type:

Figure 1.0 Defining a surrogate key in Access

1 Note that, in Access, autonumber is a Long (integer), whose values cannot be restricted

to any of its subsets, as, besides its Increment default value (starting by default with 1),

there is also a Random value (which uses both negative and positive integers).

Page 16: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

16

In the Description column (whose values are displayed by Access in the

task bar when the table instance is opened) type “Primary surrogate

COUNTRIES key” and then click on the Primary Key icon:

Figure 1.1 Defining the surrogate key to be the primary one in Access

Page 17: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

17

In the second row, type Country, leave the Text default Data Type, type

“Country name” in Description, toggle Required to Yes (for not accepting

nulls) and Allow zero length to No (to also ban dirty nulls – that is not

empty strings only containing non-printable characters), and choose for

Unique Yes (No Duplicates) in order to declare it as a key (as there may

not be two countries having same names):

Figure 1.2 Defining not null texts and single keys constraints in Access

Page 18: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

18

In the third row, type Nationality, leave the Text default Data Type, type

“Main country's people nationality” in Description, toggle Allow zero

length to No (note that you should always do it for any character strings

stored in any db, even if they are not required), and change Field size to

32:

Figure 1.3 Defining non-dirty null texts in Access

Page 19: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

19

In the fourth row, type Population, choose the Number Data Type, type

“Country population” in Description, choose Standard for Format and 0

for Decimal Places, type “Between 100 And 2000000000” for Validation

rule and “Country population should be a natural between 100 and

2,000,000,000!” for Validation Text (to implement the corresponding (co)

domain constraint):

Figure 1.4 Defining (co-)domain constraints in Access

Page 20: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

20

As Capital cannot be fully implemented for the time being (because there

is no table CITIES yet), save and close this table scheme, by giving it the

name COUNTRIES:

Figure 1.5 Saving table schemes in Access

Figure 1.6 Naming table schemes in Access

Right-click the table’s name, click on Table Properties and type “World

countries of interest.” in the Description text box, and then click OK:

Figure 1.7 Associating a description to an Access table

Page 21: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

21

For entering data into it, just double-click the table name and start typing

corresponding data into its instance:

Figure 1.8 Entering data in Access

Continue entering data at least on Moldavia, U.S.A., and U.K., by

consulting the Internet for their corresponding populations and then close

table. Note that you can enter any ASCII characters (not only the first 128

standard ones), like, for example, the Romanian’s ‘â’, ‘ș’, ‘ț’, etc.

Page 22: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

22

Similarly, create table CITIES with x as primary surrogate key and City;

for Country, chose as Data Type the last option (Lookup Wizard):

Figure 1.9 Implementing foreign keys by using Access’ Lookup Wizard

Page 23: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

23

In its first screen, leave its default settings and just click on Next:

Figure 1.10 First Access Lookup Wizard screen

Do same thing for the second screen too:

Figure 1.11 Second Access Lookup Wizard screen

Page 24: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

24

On the third one, choose columns x and Country from COUNTRIES, by

using the “>” button, and then click Next:

Figure 1.12 Third Access Lookup Wizard screen

On the fourth one, choose Country to be shown in ascending order, and

then click Next:

Figure 1.13 Fourth Access Lookup Wizard screen

Page 25: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

25

On the fifth one, leave all default options as such (note that x’s values will

be hidden and only corresponding Country’s ones will be shown) and

click Next:

Figure 1.14 Fifth Access Lookup Wizard screen

On the sixth one, click on Enable Data Integrity and then Finish:

Figure 1.15 Sixth Access Lookup Wizard screen

Page 26: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

26

Note that the default Restrict Delete option will prevent users to delete

from COUNTRIES any row which is referred to by at least one row from

CITIES2.

Dually, note that failing to enforce this referential integrity would poten-

tially result in inconsistent (hence, implausible) data instances: for exam-

ple, they might delete the row from Romania, leaving in CITIES “dangl-

ing pointers” (i.e. pointers pointing to inexistent values) for all Romanian

cities.

Next, confirm system’s request to save table, in order for it to save the

corresponding tables’ relationship, by clicking Yes:

Figure 1.16 Access tables relationships saving confirmation screen

Give the name CITIES to the table and click OK:

Figure 1.17 Saving the newly created CITIES table

2 Except for very rare, generally system cases (for users ones always get their prior

written approval for it!), DO NOT USE the Cascade Delete option: its effect is that

when users are deleting a row from COUNTRIES, all corresponding rows from CITIES

will be deleted too Imagine, for example, that Vodafone’s world integrated db would

have all foreign keys declared with the Cascade Delete option: trivially, when deleting

from CONTINENTS the row corresponding to Europe, all Europe’s countries, cities,

customers, invoices, calls, SMSs, etc. would be deleted too!

Page 27: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

27

Type “Country to which city belongs” in corresponding Description co-

lumn and choose Yes for Required:

Figure 1.18 Declaring Country from CITIES to be totally defined

Page 28: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

28

Click on the Lookup tab and note that (see figure 1.19 below):

- the corresponding Display Control is a Combo (not a default Text)

Box, whose values are computed by a query (from a table)

- attached to this combo box (or drop-down list), the following SQL

DML SELECT statement is computing its actually shown values:

SELECT [COUNTRIES].[x], [COUNTRIES].[Country]

FROM COUNTRIES ORDER BY [Country];

- the Country Bound Column (i.e. the values which are actually

stored) is the first one (i.e. x) from those computed by the above

SELECT

- the above SELECT computes 2 columns (redundant Column

Count property!)

- when opened, the combo box will not display Column Heads

- the first computed column (x) is hidden (as its Column Width is 0),

so that the second column (Country) corresponding values are

shown instead (having 1 inch width, that you can modify as

needed)

- change List Rows to 32 (in order to increase the maximum number

of rows that are displayed when opening the combo box)

- the total combo box List Width is 0 + 1 = 1 inch (note that you can

give it other values, but this should not ever be the case: if you set

a lesser value, the combo box would be correspondingly truncated

to its right; if you set a greater one, the combo box would be

correspondingly padded with blanks to its right)

- the Limit to List was set to Yes (its default being No!!), for

preventing users to store not existing rows in countries (but only

letting them to choose from existing ones)

- leave default values for all other lookup properties and save your

modification

Page 29: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

29

Figure 1.19 Country’s lookup actual properties values

In order to enforce the City Country : CITIES ASCII(128)

COUNTRIES minimally one-to-oneness, you should then click on the

Indexes button from the Table Tools tab; the following window will open

(showing the only key of this table up to now, namely the primary one):

Figure 1.20 The Indexes Access window

Page 30: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

30

Type „citiesKey” in the Index Name column of the second row (any

unique index name in this db would do too), chose City in the correspond-

ing Field Name and Country underneath it (leaving blank the correspond-

ing Index Name: if you type anything in this cell, instead of defining an

index on the product City Country, you would define two single inde-

xes, one on City and the other one on Country!) and then, on the first line

of the newly created index, toggle Unique to Yes (otherwise, this would

remain a simple index meant to speedup searches into this table and slow-

down its inserts/deletes/updates!)3.

Figure 1.21 Defining a product (compound, concatenated) key in Access

Close the Indexes window, save, and close the CITIES table.

3 Note that you would always obtain better results for your product (compound, concate-

nated, etc.) indexes usage, by following this rule: in any position of the index, the current

column should have less distinct values than the previous one and more than the subse-

quent one; this is why here we defined this key as City Country instead of Country

City (which are, mathematically speaking, equivalent).

Page 31: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

31

Click on the Database Tools tab and then on Relationships: the only

“one-to-many” existing relationship (corresponding to the foreign key

Country from CITIES) is displayed.

Figure 1.22 Access Relationships Db Tool window

Now you can close this window, open CITIES and enter at least data for

Bucharest, Chișinău, Washington, and London:

Figure 1.23 Entering data in Access’ CITIES table instance

Page 32: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

32

Then, close CITIES and re-open COUNTRIES in design mode for similar-

ly adding Capital to it; after Access saves the corresponding relationship,

its corresponding window looks like:

Figure 1.24 Access Relationships window after adding the foreign key

Capital

First, please note that Access does not show more than one relationship

between any two table instances; as such, it adds a second table instance

(COUNTRIES_1) for COUNTRIES.

Much more important, please note that there is a bug in Access (in fact, a

wrong feature: they confuse one-to-one functions with the bijective ones):

if you first declare a column unique and then a foreign key, then it either

adds a corresponding 1-to-1 relationship instead (if the two involved

tables instances are equipotent), or rejects any attempt to enforce cor-

responding referential integrity (if the two instances are not equipotent):

Figure 1.25 Access error message when trying to enforce referential

integrities on non-equipotent 1-to-1 relationships

Page 33: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

33

When you save COUNTRIES, switch it to the default Datasheet View and

start to enter capitals data, please note that, although in this very

particular case no confusion is possible (at least for Romanians),

generally, city names are not enough to uniquely identify them (recall that

CITIES semantic key is City Country):

Figure 1.26 Updating capitals data by using an Access combo box

To make the Capital combo box display the corresponding countries too,

you have to modify its Row Source property accordingly: switch COUN-

TRIES to design mode, go to Capital’s Lookup tab on the Row Source

property line and click on the “…” button to its right:

Figure 1.27 Modifying an Access combo box Row Source property

Page 34: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

34

The following QBE (Query Design Mode) window opens:

Figure 1.28 An Access QBE (Query Design Mode) window

In order to concatenate to city names their corresponding country ones,

click on Query Type, then on Show Table, choose COUNTRIES, click on

Add, and then on Close:

Figure 1.29 Adding new tables to a query in Access QBE

Page 35: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

35

By default, Access not only adds the corresponding table to the query, but

also all relationships between them (in this case, both ones from figure

1.24 above):

Figure 1.30 Access QBE with all relationships between two tables

As here we do not need the relationship corresponding to Capital, right-

click on it and then click on Delete (note that it will be deleted only from

this query, not from the db):

Figure 1.31 Access QBE with only the needed relationship in this case

Page 36: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

36

Next, in the second column of the first grid row (Field), type after City

the needed suffix so that, in the end, it reads: City, Country: City & “, “ &

COUNTRIES.Country (capitalization doesn’t matter), where the prefix

“City Country” is the label of this column (ended by ‘:’), & is the string

concatenation operator, and prefixing the name of the column Country

with its table name COUNTRIES (separated by a dot) is necessary in or-

der to eliminate ambiguity (as there is also a column Country in CITIES).

If you click on View and then on SQL View, you can see the equivalent

SQL statement (see figure 1.32):

SELECT CITIES.x, [City] & ", " &

[COUNTRIES].[Country] AS [City, Country]

FROM COUNTRIES INNER JOIN CITIES

ON COUNTRIES.x = CITIES.Country

ORDER BY [City] & ", " & [COUNTRIES].[Country];

Figure 1.32 Equivalent Access SQL statement for the Capital combo box

Save and close the query, then toggle Column Heads to Yes, increase both

the second Column and the List Widths to 2”, save the table scheme and

switch it to the normal Datasheet View.

Page 37: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

37

Now, when you open the Capital combo box, both city and corresponding

country names are displayed (separated by a comma and a space):

Figure 1.33 Updating capitals data by using an Access combo box made

out of two concatenated columns (compare with figure 1.26)

1.2.3 Creating tables in Access with SQL DDL statements

The following Access DDL SQL statements are creating absolutely similar

tables:

CREATE TABLE COUNTRIES (x Counter PRIMARY KEY,

Country varchar(255) NOT NULL UNIQUE, Capital

Long, Nationality varchar(32) NOT NULL,

Population Long);4

CREATE TABLE CITIES (x Counter Primary Key,

Country Long NOT NULL, city varchar(255) NOT

NULL, Population Long, CONSTRAINT citiesKey

UNIQUE (Country, City), CONSTRAINT fkContry

FOREIGN KEY (Country) REFERENCES Countries);

ALTER TABLE COUNTRIES ADD CONSTRAINT fkCapital

FOREIGN KEY (Capital) REFERENCES CITIES1;

4 Note that CHECK constraints are allowed only programmatically in Access, via VBA

and ADO or DAO, so that you cannot restrict only through SQL Population values.

Page 38: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

38

In order to create and run such DDL queries in Access, you have to create

a new query by clicking Query Design from the Create tab, then click

Close on the Show table modal popup window (see figure 1.29 above),

without adding any table, then click on View, then on SQL View and then

replace the “SELECT;” statement prefix (see figure 1.34 below) with a

desired DDL statement (see figure 1.35 below), then save, name, close it,

and finally double-click its name for running it.

Figure 1.34 The SQL view of an initially empty Access QBE query

Figure 1.35 The SQL view of an Access DDL SQL query

Page 39: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

39

Note that, when created through SQL, there is no issue whatsoever with

the referential integrity for unique foreign keys, not even in Access.

Unfortunately, when created through SQL, no lookups, check constraints,

or descriptions are possible: you have to add them afterwards, through the

Access GUI, just as explained above.

1.2.4 Creating and opening an Oracle database

Confusingly, Oracle uses the term “user” instead of “database”; you can

create a user through its web Enterprise Manager Console, if logged in as

SYSDBA:

Figure 1.36 Logging in as SYSDBA in Oracle’s Enterprise Manager

Page 40: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

40

Successful login opens the Enterprise Manager Home page:

Figure 1.37 Oracle Enterprise Manager Home page

Click on the Server tab and then on the Users option of the Security

group:

Figure 1.38 Oracle Enterprise Manager Server page

Page 41: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

41

In the Users page, click on the Create button:

Figure 1.39 Oracle Enterprise Manager Users page

Fill in requested data in order to create a new user (that you have to

unlock and not to let Oracle expire its password immediately) :

Figure 1.40 Oracle Enterprise Manager Create User page

Page 42: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

42

Do not create users in system’s tablespaces: click on the flashlight icon to

the right of the Default Tablespace text box and either choose the Users

one (see figure 1.41 below) or a previously created other user tablespace.

Figure 1.41 Oracle Enterprise Manager Select Tablespace page

Click on the USERS radio button, then on Select (to close the Select Ta-

blespace window), and then on the Create one from the Create User page

(see figure 1.40 above).

Page 43: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

43

A new user with the name you chose (in this example, LAB_DB) is

created and added to the Users set:

Figure 1.42 Oracle Enterprise Manager Users page (with the newly

created LAB_DB user selected)

Click on the Edit button: the Edit User page opens in its second Roles tab:

Figure 1.43 Oracle Enterprise Manager Edit User page (Roles tab, before

adding other roles than the default CONNECT one)

Page 44: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

44

Click on the Edit List button to open the Modify Roles page; add to the

CONNECT existing role CTXAPP, DBA, and RESOURCE ones too, and

then click OK:

Figure 1.44 Oracle Enterprise Manager Modify Roles page

Figure 1.45 Oracle Enterprise Manager Edit User page (Roles tab, after

adding other roles than the default CONNECT one)

Page 45: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

45

Click on the System Privileges tab:

Figure 1.46 Oracle Enterprise Manager Edit User page (System Privileges

tab, before adding other privileges than the default CREATE SESSION)

Click on the Edit List button to open the System Privileges page; add to

the CREATE SESSION existing privilege any other ones too (for a

possible, typical subset, please see the SQL script below, from GRANT

ADVISOR TO "LAB_DB" WITH ADMIN OPTION to GRANT UPDATE ANY

TABLE TO "LAB_DB"; especially, do not forget the UNLIMITED

TABLESPACE one), and then click OK:

Figure 1.47 Oracle Enterprise Manager System Privileges page

Page 46: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

46

Note that selecting system privileges may take more than 15’, so split

them into groups, click OK after ending each group and the re-click Edit

List for selecting the following group; otherwise, Oracle will disconnect

you automatically after each 15’ (of “inactivity”) and you lose all of your

selections. When finishing selections, click on the Admin Options check

boxes (on all chosen system privileges, that might span on several pages!)

and then on the Apply button:

Figure 1.48 Oracle Enterprise Manager Edit User page (System Privileges

tab, after adding other privileges than the default CREATE SESSION)

Click on the Object Privileges tab, check all Grant Options check boxes

and then click on the Apply button:

Figure 1.49 Oracle Enterprise Manager Edit User (Object Privileges)

Page 47: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

47

Click on the Quotas tab, just to make sure that your db was granted the

Unlimited Tablespace System Privilege:

Figure 1.50 Oracle Enterprise Manager Edit User page (Quotas tab)

Note that same things could have been achieved by running the following

DDL script (either in the SQL window of the Enterprise Manager, or at

the SQL* command prompt):

CREATE USER "LAB_DB" PROFILE "DEFAULT"

IDENTIFIED BY "*******" DEFAULT TABLESPACE "USERS"

TEMPORARY TABLESPACE "TEMP" ACCOUNT UNLOCK

GRANT CREATE SESSION TO "LAB_DB"

GRANT EXECUTE

ON "APEX_030200"."WWV_FLOW_EPG_INCLUDE_MODULES"

TO "LAB_DB"

GRANT ALTER ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT DELETE ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT FLASHBACK ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT INDEX ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT INSERT ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT ON COMMIT REFRESH

Page 48: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

48

ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT QUERY REWRITE

ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$" TO "LAB_DB"

GRANT REFERENCES ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT SELECT ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT UPDATE ON "FLOWS_FILES"."WWV_FLOW_FILE_OBJECTS$"

TO "LAB_DB"

GRANT "CONNECT" TO "LAB_DB"

GRANT "CTXAPP" TO "LAB_DB"

GRANT "DBA" TO "LAB_DB"

GRANT "RESOURCE" TO "LAB_DB"

ALTER USER "LAB_DB" DEFAULT ROLE ALL

GRANT ADVISOR TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER ANY INDEX TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER ANY PROCEDURE TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER ANY SEQUENCE TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER ANY TRIGGER TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER DATABASE TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER SESSION TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER SYSTEM TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER TABLESPACE TO "LAB_DB" WITH ADMIN OPTION

GRANT ALTER USER TO "LAB_DB" WITH ADMIN OPTION

GRANT BACKUP ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT COMMENT ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY INDEX TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY PROCEDURE TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY SEQUENCE TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY TRIGGER TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE ANY VIEW TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE DATABASE LINK TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE SESSION TO "LAB_DB" WITH ADMIN OPTION

GRANT CREATE USER TO "LAB_DB" WITH ADMIN OPTION

GRANT DEBUG ANY PROCEDURE TO "LAB_DB" WITH ADMIN OPTION

GRANT DEBUG CONNECT SESSION TO "LAB_DB" WITH ADMIN OPTION

GRANT DELETE ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP ANY INDEX TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP ANY PROCEDURE TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP ANY SEQUENCE TO "LAB_DB" WITH ADMIN OPTION

Page 49: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

49

GRANT DROP ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP ANY TRIGGER TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP ANY VIEW TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP TABLESPACE TO "LAB_DB" WITH ADMIN OPTION

GRANT DROP USER TO "LAB_DB" WITH ADMIN OPTION

GRANT EXECUTE ANY PROCEDURE TO "LAB_DB" WITH ADMIN OPTION

GRANT EXECUTE ANY PROGRAM TO "LAB_DB" WITH ADMIN OPTION

GRANT EXPORT FULL DATABASE TO "LAB_DB" WITH ADMIN OPTION

GRANT GRANT ANY OBJECT PRIVILEGE TO "LAB_DB"

WITH ADMIN OPTION

GRANT GRANT ANY PRIVILEGE TO "LAB_DB" WITH ADMIN OPTION

GRANT IMPORT FULL DATABASE TO "LAB_DB" WITH ADMIN OPTION

GRANT INSERT ANY TABLE TO "LAB_DB" WITH ADMIN OPTION

GRANT MANAGE TABLESPACE TO "LAB_DB" WITH ADMIN OPTION

GRANT ON COMMIT REFRESH TO "LAB_DB" WITH ADMIN OPTION

GRANT SELECT ANY SEQUENCE TO "LAB_DB"

GRANT SELECT ANY TABLE TO "LAB_DB"

GRANT SELECT ANY TRANSACTION TO "LAB_DB"

GRANT SYSDBA TO "LAB_DB"

GRANT UNLIMITED TABLESPACE TO "LAB_DB"

GRANT UPDATE ANY TABLE TO "LAB_DB"

From now on, you can connect to and work with your new LAB_DB db;

the easiest tool to use is the Oracle’s SQL Developer (freely downloada-

ble from Oracle’s website); install and open it:

Figure 1.51 Oracle’s SQL Developer About page

Page 50: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

50

Click on the + (New Connection), fill in all necessary connection data,

click on Save, then on Test (if connection data is correct, “Status: Suc-

cess” is displayed in the left bottom corner) and then on Connect:

Figure 1.52 Oracle’s SQL Developer Db Connection page

A corresponding SQL sheet is opened and you can start working with

your LAB_DB db:

Figure 1.53 Oracle’s SQL Developer main page

Page 51: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

51

1.2.5 Creating tables in Oracle with the SQL Developer GUI

Open the LAB_DB tree view, right-click on the Tables node, and click on

New Table:

Figure 1.54 Oracle’s SQL Developer tree view of a db objects

Figure 1.55 Oracle’s SQL Developer standard Create Table page

Page 52: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

52

Click on the Advanced check box:

Figure 1.56 Oracle’s SQL Developer advanced Create Table page

Type COUNTRIES in the table Name text box (overwriting TABLE1),

click on the Comment node and type “Word countries of interest” in the

Comment text box:

Figure 1.57 Associating a comment to an Oracle table

Page 53: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

53

Go back to the Columns node, type x in the first row of the column one

(overwriting COLUMN1), choose Number5 for Type, 3 for Precision

(there are only some 250 countries), 0 for Scale (cardinals are naturals),

check the Cannot be NULL box, and type “Primary surrogate COUN-

TRIES key” in the Comment text one:

Figure 1.58 Defining a surrogate key in Oracle

Click on the Primary Key, move X (note that Oracle only uses capital let-

ters) from the Available to the Selected Columns:

Figure 1.59 Defining the surrogate key to be the primary one in Oracle

5 Note that Oracle does not provide the autonumber data type.

Page 54: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

54

Go back to the Columns node, click on the + (add column) green button,

type Country in Name, leave the VARCHAR2 default Type, type 255 for

Size, “Country name” in Comment, and check the Cannot be NULL box6:

Figure 1.60 Adding the text field Country to COUNTRIES in Oracle

Click on the Unique Constraints node, then on Add, and move COUN-

TRY from Available to Selected Columns – in order to declare it as a key

(as there may not be two countries having same names):

Figure 1.61 Defining single keys constraints in Oracle

6 Note that Oracle is not providing automatic rejection of dirty nulls.

Page 55: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

55

Go back to the Columns node, click on the + (add column) green button,

type Nationality in Name, leave the VARCHAR2 default Type, type 32 for

Size, and “Main country's people nationality” in Comment:

Figure 1.62 Defining text fields that accept nulls in Oracle

Click once more on the + (add column) green button, type Population in

Name, choose Number for Type, 10 for Precision (which allows for a ma-

ximum value of 9,999,999,999), 0 for Scale, and type “Country popula-

tion” in the Comment text one:

Figure 1.63 Defining number fields that accept nulls in Oracle

Page 56: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

56

Click on the Check Constraints node, then on Add, and type “POPULA-

TION BETWEEN 100 AND 2000000000” in the Condition text box (to

implement the corresponding (co) domain constraint)7:

Figure 1.64 Defining (co-)domain constraints in Oracle

As Capital cannot be fully implemented for the time being (because there

is no table CITIES yet), save and close this table scheme, by clicking on

OK. You can review it by clicking on its name:

Figure 1.65 Inspecting table columns with Oracle’s SQL Developer

7 Note that, unfortunately, Oracle does not provide either check constraints correspond-

ing error messages (see, for example, Access’ Validation Text) or number formatting

(see, for example, Access’ Standard Format).

Page 57: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

57

To inspect table’s constraints, click on the Constraints tab; to also visua-

lize the columns to which a constraint refers, click on the desired con-

straint row:

Figure 1.66 Inspecting table constraints with Oracle’s SQL Developer

To inspect table’s indexes, click on the Indexes tab; to also visualize the

columns which are making up an index, click on the desired index row:

Figure 1.67 Inspecting table indexes with Oracle’s SQL Developer

Page 58: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

58

To inspect table’s details, click on the Details tab:

Figure 1.68 Inspecting table details with Oracle’s SQL Developer

Page 59: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

59

You can also inspect the corresponding SQL DDL statements, by clicking

on the SQL tab:

Figure 1.69 Inspecting corresponding table creation SQL DDL script with

Oracle’s SQL Developer

In order to automatically generate unique numbers for the primary surro-

gate key X, you first need to declare a corresponding sequence: right click

on the Sequences node of the LAB_DB scheme tree and then choose New

Sequence:

Figure 1.70 Creating a sequence with Oracle’s SQL Developer

Page 60: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

60

Fill-in corresponding desired values for Name, Increment, Start with, Min,

and Max values, and then click OK:

Figure 1.71 Filling/editing sequence data with Oracle’s SQL Developer

Next, you need to create a trigger: right click on the Triggers node of the

LAB_DB scheme tree and then choose New Trigger:

Figure 1.72 Creating a trigger with Oracle’s SQL Developer

Page 61: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

61

In the Create Trigger window that opens, fill-in Name, Table Name,

Insert, Before, Statement Level, and then click OK:

Figure 1.73 Specifying trigger details with Oracle’s SQL Developer

The corresponding trigger is created, but with a null; PL/SQL body:

Figure 1.74 Initial, null; body Oracle trigger PL/SQL code

Page 62: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

62

Replace null; with:

if (:new.x is null) then

select countries_seq.nextval into :new.x from dual;

end if;

and save it (by clicking on the floppy-disk icon):

Figure 1.75 Final Oracle trigger PL/SQL code

Page 63: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

63

You may check that this trigger is depending on table COUNTRIES and

sequence COUNTRIES_SEQ by clicking on the Dependencies tab:

Figure 1.76 Oracle trigger dependencies example

and inspect its details by clicking on the Details tab:

Figure 1.77 Oracle trigger details example

Page 64: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

64

For entering data into table COUNTRIES, click its Data tab, then, for

each new line, on the green Insert Row icon (or type Ctrl+I or Tab at each

line end), and type corresponding data for Country, Nationality, and Po-

pulation into its instance:

Figure 1.78 Entering data in Oracle

Continue entering data at least on U.S.A., and U.K., by consulting the

Internet for their corresponding populations. Note that X’s values are

automatically filled-in (by the above defined trigger) and that you can

enter any ASCII characters (not only the first 128 standard ones), like, for

example, the Romanian’s ‘â’, ‘ș’, ‘ț’, etc.

Save entered data by clicking on the Refresh icon (or type Ctrl+R) and

then on Yes:

Figure 1.79 Saving data in Oracle

Page 65: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

65

Similarly, create table CITIES with x as primary surrogate key and City,

and Country (with exactly same Type, Precision, and Scale like x in

COUNTRIES):

Figure 1.80 Creating table CITIES in Oracle

Click on the Foreign Keys node, then on Add, choose COUNTRIES as Re-

ferenced Table, COUNTRIES_PK as Referenced Constraint, and Country

as Local Column:

Figure 1.81 Implementing foreign keys in Oracle

Page 66: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

66

Note that, unfortunately, Oracle does not provide an Access type Lookup

facility, so that you should build combo boxes (drop down lists) for all fo-

reign keys, such as to hide pointers and replace them with corresponding

semantic keys values in your db applications.

Also note that the default Restrict On Delete option will prevent users to

delete from COUNTRIES any row which is referred to by at least one row

from CITIES8. Dually, note that failing to enforce this referential integrity

(foreign key) constraint would potentially result in inconsistent (hence,

implausible) data instances: for example, they might delete the row from

Romania, leaving in CITIES “dangling pointers” (i.e. pointers pointing to

inexistent values) for all Romanian cities.

Click the Unique Constraints node, then the Add button, move City and

Country from the Available to the Selected Columns, in order to enforce

the City Country : CITIES ASCII(128) COUNTRIES minimally

one-to-oneness:

Figure 1.82 Defining a product (compound, concatenated) key in Oracle

8 Except for very rare, generally system cases (for users ones always get their prior

written approval for it!), DO NOT USE the Cascade Delete option: its effect is that

when users are deleting a row from COUNTRIES, all corresponding rows from CITIES

will be deleted too Imagine, for example, that Vodafone’s world integrated db would

have all foreign keys declared with the Cascade Delete option: trivially, when deleting

from CONTINENTS the row corresponding to Europe, all Europe’s countries, cities,

customers, invoices, calls, SMSs, etc. would be deleted too!

Page 67: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

67

Click on OK to save the CITIES table scheme and then, similarly, create a

CITIES_SEQ sequence (with maximum value 999999) and a CI-

TIES_AUTONUM trigger (with select cities_seq.nextval into

:new.x from dual; in its body).

Open CITIES Data tab and enter at least data for Bucharest, Chișinău,

Washington, and London (note that you have to pay attention to actual

COUNTRIES.x values in order to correctly specify CITIES.Country ones):

Figure 1.83 Entering data in Oracle CITIES table instance

Re-open COUNTRIES in design mode (right-click on its name and choose

Edit) for similarly adding Capital to it; after saving the corresponding

foreign key, enter data in this column too:

Page 68: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

68

Figure 1.84 Entering data in Oracle COUNTRIES.Capital instance

1.2.6 Creating tables in Oracle with SQL DDL statements

The following Oracle DDL SQL statements are creating absolutely

similar tables as above:

--------------------------------------------------------

-- DDL for Sequence COUNTRIES_SEQ

--------------------------------------------------------

CREATE SEQUENCE "LAB_DB"."COUNTRIES_SEQ" MINVALUE 1

MAXVALUE 300 INCREMENT BY 1 START WITH 1 NOCACHE

ORDER NOCYCLE ;

--------------------------------------------------------

-- DDL for Sequence CITIES_SEQ

--------------------------------------------------------

CREATE SEQUENCE "LAB_DB"."CITIES_SEQ" MINVALUE 1

MAXVALUE 999999 INCREMENT BY 1 START WITH 1 NOCACHE

ORDER NOCYCLE ;

--------------------------------------------------------

-- DDL for Table COUNTRIES

--------------------------------------------------------

Page 69: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

69

CREATE TABLE "LAB_DB"."COUNTRIES"

( "X" NUMBER(3,0),

"COUNTRY" VARCHAR2(255 BYTE),

"NATIONALITY" VARCHAR2(32 BYTE),

"POPULATION" NUMBER(10,0),

"CAPITAL" NUMBER(10,0)

) TABLESPACE "USERS" ;

COMMENT ON COLUMN "LAB_DB"."COUNTRIES"."X" IS 'Primary

surrogate COUNTRIES key';

COMMENT ON COLUMN "LAB_DB"."COUNTRIES"."COUNTRY" IS

'Country name';

COMMENT ON COLUMN "LAB_DB"."COUNTRIES"."NATIONALITY" IS

'Main country''s people nationality';

COMMENT ON COLUMN "LAB_DB"."COUNTRIES"."POPULATION" IS

'Country population';

COMMENT ON COLUMN "LAB_DB"."COUNTRIES"."CAPITAL" IS

'Country capital city;

COMMENT ON TABLE "LAB_DB"."COUNTRIES" IS 'World

countries of interest.';

--------------------------------------------------------

-- DDL for Index COUNTRIES_PK

--------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."COUNTRIES_PK" ON

"LAB_DB"."COUNTRIES" ("X") TABLESPACE "USERS" ;

--------------------------------------------------------

-- DDL for Index COUNTRIES_UK1

--------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."COUNTRIES_UK1" ON

"LAB_DB"."COUNTRIES" ("COUNTRY") TABLESPACE "USERS" ;

--------------------------------------------------------

-- DDL for Index COUNTRIES_UK2

--------------------------------------------------------

Page 70: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

70

CREATE UNIQUE INDEX "LAB_DB"."COUNTRIES_UK2" ON

"LAB_DB"."COUNTRIES" ("CAPITAL") TABLESPACE "USERS" ;

--------------------------------------------------------

-- Constraints for Table COUNTRIES

--------------------------------------------------------

ALTER TABLE "LAB_DB"."COUNTRIES" ADD CONSTRAINT

"COUNTRIES_CHK1" CHECK (POPULATION BETWEEN 100 AND

2000000000) ENABLE;

ALTER TABLE "LAB_DB"."COUNTRIES" ADD CONSTRAINT

"COUNTRIES_PK" PRIMARY KEY ("X")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."COUNTRIES" ADD CONSTRAINT

"COUNTRIES_UK1" UNIQUE ("COUNTRY")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."COUNTRIES" ADD CONSTRAINT

"COUNTRIES_UK2" UNIQUE ("CAPITAL")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."COUNTRIES" MODIFY ("X" NOT NULL

ENABLE);

ALTER TABLE "LAB_DB"."COUNTRIES" MODIFY ("COUNTRY" NOT

NULL ENABLE);

--------------------------------------------------------

-- DDL for Trigger COUNTRIES_AUTONUM

--------------------------------------------------------

CREATE OR REPLACE TRIGGER "LAB_DB"."COUNTRIES_AUTONUM"

before insert on countries

for each row

begin

if (:new.x is null) then

select countries_seq.nextval into :new.x from dual;

end if;

end;

/

Page 71: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

71

ALTER TRIGGER "LAB_DB"."COUNTRIES_AUTONUM" ENABLE;

--------------------------------------------------------

-- DDL for Table CITIES

--------------------------------------------------------

CREATE TABLE "LAB_DB"."CITIES"

( "X" NUMBER(6,0),

"CITY" VARCHAR2(128 BYTE),

"COUNTRY" NUMBER(3,0)

) TABLESPACE "USERS" ;

COMMENT ON COLUMN "LAB_DB"."CITIES"."X" IS 'CITIES

surrogate primary key';

COMMENT ON COLUMN "LAB_DB"."CITIES"."CITY" IS 'City

name';

COMMENT ON COLUMN "LAB_DB"."CITIES"."COUNTRY" IS

'Country to which city belongs to';

COMMENT ON TABLE "LAB_DB"."CITIES" IS 'World cities of

interest.';

--------------------------------------------------------

-- DDL for Index CITIES_PK

--------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."CITIES_PK" ON

"LAB_DB"."CITIES" ("X") TABLESPACE "USERS" ;

--------------------------------------------------------

-- DDL for Index CITIES_UK1

--------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."CITIES_UK1" ON

"LAB_DB"."CITIES" ("CITY", "COUNTRY") TABLESPACE "USERS" ;

--------------------------------------------------------

-- Constraints for Table CITIES

--------------------------------------------------------

Page 72: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

72

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT "CITIES_PK"

PRIMARY KEY ("X") USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT "CITIES_UK1"

UNIQUE ("CITY", "COUNTRY")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("X" NOT NULL

ENABLE);

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("CITY" NOT NULL

ENABLE);

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("COUNTRY" NOT NULL

ENABLE);

--------------------------------------------------------

-- Ref Constraints for Table CITIES

--------------------------------------------------------

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT

"CITIES_COUNTRIES_FK1" FOREIGN KEY ("COUNTRY")

REFERENCES "LAB_DB"."COUNTRIES" ("X") ENABLE;

--------------------------------------------------------

-- DDL for Trigger CITIES_AUTONUM

--------------------------------------------------------

CREATE OR REPLACE TRIGGER "LAB_DB"."CITIES_AUTONUM"

before insert on cities

for each row

begin

if (:new.x is null) then

select cities_seq.nextval into :new.x from dual;

end if;

end;

/

ALTER TRIGGER "LAB_DB"."CITIES_AUTONUM" ENABLE;

--------------------------------------------------------

-- Ref Constraints for Table COUNTRIES

--------------------------------------------------------

Page 73: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

73

ALTER TABLE "LAB_DB"."COUNTRIES" ADD CONSTRAINT

"COUNTRIES_CITIES_FK1" FOREIGN KEY ("CAPITAL")

REFERENCES "LAB_DB"."CITIES" ("X") ENABLE;

In order to create and run such DDL queries in Oracle, you have to enter

them (or copy them from any text editor tool) in a SQL sheet of the SQL

Developer, select the corresponding db (LAB_DB, in this case) in its as-

sociated current db combo box, and then execute it by clicking the Run

Script icon (or pressing F5):

Figure 1.85 Executing SQL scripts with Oracle SQL Developer

Page 74: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

74

1.3 Best practice rules

BPR1.0 For each object set create a corresponding table (giving it the

name of the set and an appropriate semantic description/comment),

having a surrogate numeric primary key x (or ID), preferably of

AutoNumber data type (if the set is not a subset); if this data type is

not available, then program it yourself (e.g., in Oracle, with sequences

and triggers); if the RDBMS allows it, correctly size its co-domain (that

should correspond to the maximum possible cardinal of that object set) .

BPR1.1 For each valuation function, add to the table corresponding

to its domain a column (having the name of the function and an ap-

propriate semantic description/comment) of the type corresponding

to its co-domain, as well as all relational type constraints that apply to

it (domain, NOT NULL, uniqueness, check /tuple).

BPR1.2 For each structural function, add to the table corresponding

to its domain a column (having the name of the function and an ap-

propriate semantic description/comment) of numeric type, of size cor-

responding to the maximum cardinality of its co-domain, declare it as

a foreign key referencing the primary key of the table corresponding

to its co-domain, and add all other relational type constraints that ap-

ply to it (domain, NOT NULL, uniqueness, check /tuple).

BPR1.3 If the RDBMS offers lookup combo boxes, use them for any

foreign key, in order to hide pointers and replace them for users with

corresponding semantic key values.

BPR1.4 Each table must have at least one column which does not ac-

cept nulls.

BPR1.5 Whenever RDBMS provides it, ban dirty nulls for all text

types columns (otherwise, you should program it in your db applica-

tions).

BPR1.6 Each table must have at least one semantic (candidate) key,

with only two exceptions: tables corresponding to subsets or to object

Page 75: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

75

sets of type rabbit/poultry/etc. cages (note that even they may have

such keys, however!).

BPR1.7 If RDBMS provides a GUI, use it first, for increasing your

productivity, and use SQL only then, for refining db schemes, if ne-

eded, or when you need to generate/execute SQL statements pro-

grammatically.

1.4 Homework H1.1 Create a STATES table with (x, State name, Country, State code,

State telephone prefix, State capital, State population) and insert into it at

least 2 states per country.

H1.2 Add (both in Design mode and SQL) the following functions too (as

well as corresponding instance data):

- StateDesignation : COUNTRIES ASCII(255) NULLS, to

store the country’s administrative subdivision names (e.g in the

U.S. they are called ‘state’, in Romania ‘judet’, in Germany and

Austria ‘land’, etc.);

- CountryCode : COUNTRIES ASCII(8), to store the country’s

(vechicle plates) codes (e.g. USA, UK, RO, F, D, RU, etc.);

- Population : CITIES [10, 30000000] NULLS

Page 76: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

76

Chapter 2. 2nd Lab: Transactional DML statements in

SQL and GUI

2.1 Transactional SQL DML statements There are 5 DML standard SQL statements:

INSERT INTO VALUES ... – inserts one row

SELECT ... – inserts n rows, n natural

UPDATE … SET.... [WHERE]– updates columns values

(for all rows, if no WHERE clause, or for only those rows

that satisfy the WHERE clause).

DELETE FROM ... [WHERE] – empties table (if no

WHERE clause) or removes from its instance only those

rows that satisfy the WHERE clause.

SELECT… INTO ... (Selects the needed data, creates the

table and stores in it the selected rows). Please, note that in

the tables created using SELECT INTO statements no

constraints are defined; so, if needed, you should add them

explicitly later.

SELECT... FROM... [WHERE]... [GROUP BY]....

[HAVING]... [ORDER BY] …

Execution of the first 4 statements is transactional or ACID (for SELECT

it is no need, as it only retrieves data), where:

A – Atomic: all involved rows (if no constraint is violated) or none (if at

least one value would violate at least one constraint) are affected by the

respective change;

C – Consistent: Although, sometimes, during a transaction, db con-

straints may be temporarily violated, at the end of any transaction the db

should remain in a consistent state (that is its instance may not violate any

of the db constraints).

I – Independent (Isolation): In concurrent environments, any transac-

tion should behave the same, just as if it were run alone, regardless of any

Page 77: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

77

other concurrent transaction(that is simultaneously running concurrent

transactions are independent one of each other).

D – Durable: At the end of each successful transaction, all new data is

stored for ever as such: only subsequent transactions might modify them.

You can define an explicit transaction (containing any number of DML

and/or DDL statements) as:

BEGIN TRANS[ACTIONS] (transaction opening parenthesis)

...

COMMIT [TRANSACTION] – meaning that the modifications done are

ok and the user agrees to save the modified data. (OK transaction closing

parenthesis)

Or

ROLLBACK [TRANSACTION] – it’s the dual of COMMIT, meaning

that the user wants that the database be restored to the initial database in-

stance prior to modifications, as something went wrong (generally a con-

straint would be violated, but also lack of enough disk/memory free

space, etc.) (KO transaction closing parenthesis).

2.2 Exercises

2.2.1 Prerequisites in Access

a. The table STATES having the following structure should also be alrea-

dy created (see homework from 1st lab):

x- autonumber, Primary Key

State – Text(255), Required: Yes, Allow zero length: No (not allowing

dirty nulls)

Country – Required: Yes, lookup in COUNTRIES:

SELECT x, Country FROM COUNTRIES ORDER BY Country;

StateCode – Text (8), Allow zero length: NO

Page 78: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

78

StateTelPrefix – integer, Validation rule: between 0 and 500

StateCapital - Required: No, lookup in CITIES:

SELECT CITIES.x, [City] & ", " & [STATES].[State]

& ", " & [COUNTRIES].[Country]

AS [City, State, Country]

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY [City] & ", " & [STATES].[State] & ", " &

[COUNTRIES].[Country];

Figure 2.1: STATES table scheme

Page 79: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

79

Figure 2.2: STATES instance sample

Keys: StateCapital, State ● Country (we will later see that StateCode ●

Country and StateTelPrefix ● Country are keys also)

Figure 2.3: STATES keys

Page 80: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

80

b. The table CITIES having the following new structure (see lab 1 and homework

from 1st lab):

Figure 2.4: CITIES instance sample

Page 81: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

81

Figure 2.5: modified CITIES table scheme

Note that, by refining this model (also considering states), cities belong

now to countries transitively (not directly anymore), just like in reality,

through states: for example, Craiova belongs to Romania, as it belongs to

the Dolj state, which belongs to Romania. This is why former Country co-

lumn of CITIES has been replaced by a State one, whose values are

looked up for in STATES:

SELECT STATES.x, [State] & ", " &

[COUNTRIES].[COUNTRY] AS [State, Country]

FROM COUNTRIES INNER JOIN STATES

ON COUNTRIES.x = STATES.Country

ORDER BY [State] & ", " & [COUNTRIES].[COUNTRY];

Page 82: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

82

Mathematically, former Country : CITIES COUNTRIES now becomes

a computable function (so not worth storing) * Country : CITIES

COUNTRIES, * Country = Country State, where Country : STATES

COUNTRIES and State : CITIES STATES.

Corresponding table relationships are shown in figure 2.8 below.

Obviously, CITIES’ key changed also (from City●Country to City●State):

Figure 2.6: new CITIES keys

Table COUNTRIES remains the same, just like in the 1st lab, except for

the Capital combo box, which now contains states too (see the lookup of

StateCapital above):

Page 83: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

83

Figure 2.7: new CITIES instance sample

Figure 2.8: Relationships between the three db tables

Page 84: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

84

2.2.2 Exercises in Access

P2.1. Insert into the db, both by using SQL and MS design mode (an im-

plementation of QBE = Query-by-Example), a city called Memphis as the

capital of the Tennessee state of the U.S.A. (considering that the U.S.A. id

is known: here, it is 3).

Solution:

Obviously, as no such rows exist and as State is compulsory in CITIES,

first we have to insert a corresponding row in STATES, then one in CI-

TIES, and finally declare Memphis as the corresponding state capital:

1.1 Insert Tennessee in STATES

For opening the design mode, click on Create, then Query Design, and

then Close on the Show Table modal popup window:

Figure 2.9: the Query Design Show Table modal popup window

Page 85: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

85

Figure 2.10 shows the corresponding empty query; click on Append (to

change current query type from the default SELECT to the INSERT

type), select table STATES in its Table Name dropdown list and then click

OK (see figure 2.11).

Type “Tennessee” in the Field’s first cell and then 3 in the second one;

choose State in the AppendTo first cell (bellow “Tennessee”) and Country

in its second one (bellow 3) – see figure 2.12. Click View, then SQL View:

figure 2.13 shows the equivalent SQL query generated by the system.

Figure 2.10: the Query Design window for an empty query

Page 86: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

86

Figure 2.11: the Query Design Append window for INSERT type queries

Figure 2.12: the Query Design window for the InsertTennessee query

Page 87: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

87

Figure 2.13: the SQL window for the initial InsertTennessee query

Unfortunately, starting with Access 2010, the system is not generating

anymore INSERT … VALUES statements, but only SELECT ones;

moreover, as we did not select any table in the Show Table window, this

generated SQL statement is even syntactically wrong, as it lacks the

FROM clause; consequently, you have to correct it as follows (see figure

2.14):

INSERT INTO STATES (State, Country)

VALUES (“Tennessee”, 3);

Figure 2.14: the SQL window for the corrected InsertTennessee query

Page 88: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

88

Note that you could have opened the SQL View mode immediately after

closing the Show Table window (figure 2.9 above) and type this whole

INSERT statement.

Click on Run: new corresponding row was added, with x = 8 (see figure

2.4 above); save it then as query insertTennessee: click on the Save icon

(the floppy disk one), type the desired query name and then click on OK

(see figure 2.15).

Figure 2.15: the Query Design Save As modal popup window

1.2 Insert Memphis in CITIES

Similarly as above, but choosing table STATES in the Show Table win-

dow (figure 2.9 above) and table CITIES in the AppendTo one (figure

2.11 above), as well as establishing criteria “Tennessee” for State and 3

for Country (see figure 2.16 below), the system generates:

INSERT INTO CITIES (City, State)

SELECT “Memphis”, x FROM STATES

WHERE State = “Tennessee” AND Country = 3;

When you run it, a new corresponding row was added, with x = 7 (see fi-

gure 2.2 above); save it as query insertMemphisTennessee.

Page 89: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

89

Figure 2.16: the Query Design window for the

insertMemphisTennessee query

1.3 Declare (in STATES) Memphis to be Tennessee‘s state capital

First, please note that, unfortunately, the following standard SQL syntax is

not accepted by Access:

UPDATE STATES SET StateCapital = (SELECT x FROM CITIES

WHERE City=”Memphis” AND State = (SELECT x FROM

STATES

WHERE Country= 3 AND State= “Tennessee”))

WHERE State = “Tennessee” AND Country = 3;

Page 90: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

90

Fortunately, Access provides a library function that is returning the first9 e

value from any SQL statement of the type SELECT TOP 1 e FROM T

WHERE F; its syntax is: DLookup(“e”, “T”, “F”).

For example, DLookup("x", "STATES", "State = 'Tennessee'

AND Country = 3") is computing x’s value for Tennessee from

STATES (7 - see figure 2.2 above); by nesting two calls to it,

DLookup("x", "CITIES", "City='Memphis' AND State = " &

DLookup("x", "STATES", "State = 'Tennessee' AND

Country = 3")) is returning x’s value for Memphis from CITIES (8 -

see figure 2.4 above)10

.

Consequently, the needed query for storing the fact that Memphis is the

capital of Tennessee is:

UPDATE STATES SET StateCapital = DLookup("x",

"CITIES", "City='Memphis' AND State = " &

DLookup("x", "STATES", "State = 'Tennessee' AND

Country = 3"))

WHERE State="Tennessee" AND Country=3;

To build it in MS QBE, open a new query in design mode, just like in 1.1

above, select table STATES in the Show Table modal popup window (see

figure 2.9), click on OK to close it, then on Update (to change current

query type from the default SELECT to the UPDATE type), double-click

the StateCapital column, type the above DLookup expression below it, in

the UpdateTo row’s first cell, double-click State, type “Tennessee” in the

corresponding Criteria cell below it, and double-click Country and type 3

in the corresponding Criteria cell below it (see figure 2.17).

9 Note that, here, first does not imply any ordering! If e is not void, Access is returning

an arbitrary “first” value from e (and when it is void, it returns NULL). Consequently,

DLookup should be used only when F includes a key, so e has only one element, or for

detecting whether or not a subset e is empty. 10

Note that & is the string concatenation operator in Access (VB/VBA/SQL, generally).

Also note that strings inside strings are enclosed in either double quotes or apostrophes.

Page 91: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

91

Figure 2.18 shows the corresponding generated SQL UPDATE statement

(that, again, we could have typed in directly, from the beginning, but

using QBE spares us many risks of syntactical errors).

Figure 2.17: the Query Design window for the

updateTennesseeCapital query

Page 92: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

92

Figure 2.18: the SQL View window for the

updateTennesseeCapital query

Note that, trivially, this a programmatic approach, needed when dynami-

cally having to update data through db software applications (which is the

standard way to manage data, thus hiding both dbs and needed operatio-

nal workflows from end-users); same things may be accomplished stati-

cally, by non-programmer users, using the Access GUI: figures 2.19, 2.20,

and 2.21 are showing how to add state and its state capital Sibiu from

Romania.

Also note that all combo boxes (dropdown lists) of any table/form are

(automatically) computed only when the corresponding table/form is

opened; this is why, for example, in order to be able to select the Sibiu

state too in the CITIES.State combo box immediately after it has been in-

serted in STATES, you have to close and re-open CITIES11

.

11

Note, however, that this can also be done programmatically, in forms, without needing

to close and re-open them, with the VBA Requery method.

Page 93: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

93

Figure 2.19: Inserting a new state (Sibiu) using Access’ GUI

Figure 2.20: Inserting a new city (Sibiu) using Access’ GUI

Page 94: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

94

Figure 2.21: Storing the fact that Sibiu is the capital of the homonym

state, by using Access’ GUI

P2.2. Parameterize the first insert statement of P1 above such as to insert

a new state in any desired existing country.

Solution:

Note that, unlike other RDBMSs, where parameters are syntactically re-

cognized by prefixing their names with some special character (e.g. @ for

MS SQL Server, : for Oracle, etc.), Access uses a semantic approach in-

stead: anywhere in a SQL statement where either a table or a column

name is not existing in the corresponding database, Access is considering

that name as being a parameter; Consequently, when running such a state-

ment Access will ask user for the actual value of all such parameters, by

prompting for each of them the name of the corresponding parameter.

Note that as prompts need white spaces and/or special characters, general-

ly, Access parameters are enclosed in square brackets.

Page 95: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

95

This is why the solution for parameterizing the first insert statement from

P2.1 above (see 1.1 of P2.1 above) is the following (save it as insert-

State):

INSERT INTO STATES (State, Country)

SELECT [Enter desired state name:], x

FROM COUNTRIES

WHERE Country = [Enter desired country

name:];

2.2.3 Prerequisites in Oracle

a. The table STATES having the following structure should also be alrea-

dy created (see homework from 1st lab):

x- autonumber, Primary Key

State – Text(255), NOT NULL: Yes

Country – NOT NULL: Yes, references COUNTRIES

StateCode – Text(8)

StateTelPrefix – integer, Validation rule: between 0 and 500

StateCapital - NOT NULL: No, references CITIES, unique (no city may

simultaneously be the capital of more than one state)

Keys: StateCapital, State ● Country (we will later see that StateCode ●

Country and StateTelPrefix ● Country are keys also)

Here is the corresponding SQL DDL script:

------------------------------------------------------

-- DDL for Sequence STATES_SEQ

------------------------------------------------------

CREATE SEQUENCE "LAB_DB"."STATES_SEQ" MINVALUE 1

MAXVALUE 9999 INCREMENT BY 1 START WITH 1 NOCACHE

ORDER NOCYCLE ;

Page 96: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

96

------------------------------------------------------

-- DDL for Table STATES

------------------------------------------------------

CREATE TABLE "LAB_DB"."STATES"

( "X" NUMBER(6,0),

"STATE" VARCHAR2(255 BYTE),

"COUNTRY" NUMBER(3,0),

"STATE_CODE" VARCHAR2(8 BYTE),

"STATE_TEL_PREFIX" NUMBER(3,0),

"CAPITAL" NUMBER(10,0)

) TABLESPACE "USERS" ;

COMMENT ON COLUMN "LAB_DB"."STATES"."X" IS 'STATES

surrogate primary key';

COMMENT ON COLUMN "LAB_DB"."STATES"."STATE" IS

'State name';

COMMENT ON COLUMN "LAB_DB"."STATES"."COUNTRY" IS

'Country to which state belongs';

COMMENT ON COLUMN "LAB_DB"."STATES"."STATE_CODE" IS

'State (vehicle plates) code';

COMMENT ON COLUMN

"LAB_DB"."STATES"."STATE_TEL_PREFIX" IS 'State

telephone prefix';

COMMENT ON COLUMN "LAB_DB"."STATES"."CAPITAL" IS

'State capital city';

COMMENT ON TABLE "LAB_DB"."STATES" IS 'The set of

countries sub-divisions of interest.';

------------------------------------------------------

-- DDL for Index STATES_PK

------------------------------------------------------

Page 97: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

97

CREATE UNIQUE INDEX "LAB_DB"."STATES_PK" ON

"LAB_DB"."STATES" ("X") TABLESPACE "USERS" ;

------------------------------------------------------

-- DDL for Index STATES_UK1

------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."STATES_UK1" ON

"LAB_DB"."STATES" ("CAPITAL") TABLESPACE "USERS" ;

------------------------------------------------------

-- Constraints for Table STATES

------------------------------------------------------

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_CHK1" CHECK (STATE_TEL_PREFIX BETWEEN 0 AND

500) ENABLE;

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_PK" PRIMARY KEY ("X")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_UK1" UNIQUE ("CAPITAL")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_UK2" UNIQUE ("STATE", "COUNTRY")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."STATES" MODIFY ("X" NOT NULL

ENABLE);

ALTER TABLE "LAB_DB"."STATES" MODIFY ("STATE" NOT

NULL ENABLE);

ALTER TABLE "LAB_DB"."STATES" MODIFY ("COUNTRY" NOT

NULL ENABLE);

Page 98: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

98

------------------------------------------------------

-- Ref Constraints for Table STATES

------------------------------------------------------

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_CITIES_FK1" FOREIGN KEY ("CAPITAL")

REFERENCES "LAB_DB"."CITIES" ("X") ENABLE;

ALTER TABLE "LAB_DB"."STATES" ADD CONSTRAINT

"STATES_COUNTRIES_FK1" FOREIGN KEY ("COUNTRY")

REFERENCES "LAB_DB"."COUNTRIES" ("X") ENABLE;

------------------------------------------------------

-- DDL for Trigger STATES_AUTONUM

------------------------------------------------------

CREATE OR REPLACE TRIGGER "LAB_DB"."STATES_AUTONUM"

before insert on states

for each row

begin

if (:new.x is null) then

select states_seq.nextval into :new.x from dual;

end if;

end;

/

ALTER TRIGGER "LAB_DB"."STATES_AUTONUM" ENABLE;

Then, please also add some lines to its instance:

Page 99: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

99

Figure 2.22: STATES instance sample

b. The table CITIES having the following new structure (see lab 1 and homework

from 1st lab):

Note that, by refining this model (also considering states), cities belong

now to countries transitively (not directly anymore), just like in reality,

through states: for example, Craiova belongs to Romania, as it belongs to

the Dolj state, which belongs to Romania. This is why former Country co-

lumn of CITIES has been replaced by a State one, whose values are

referencing those in STATES.x.

Mathematically, former Country : CITIES COUNTRIES now becomes

a computable function (so not worth storing) * Country : CITIES

COUNTRIES, * Country = Country State, where Country : STATES

COUNTRIES and State : CITIES STATES.

Obviously, CITIES’ key changed also (from City●Country to City●State).

In order to achieve all these, you should first drop the Country former

foreign key, by executing the following DDL statement:

ALTER TABLE CITIES DROP CONSTRAINT CITIES_COUNTRIES_FK1;

Page 100: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

100

Then, you can rename Country to State (the easiest for doing it is to use

SQL Developer’s GUI): note that this is also automatically changing the

key City●Country to City●State.

Then, you have to correctly update data from the State column:

Figure 2.23: CITIES instance sample

Now, you can add the referential integrity constraint for State.

The corresponding new DDL SQL script for this table is the following

(note that the one for its sequence and trigger is not displayed anymore, as

they did not change):

Page 101: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

101

------------------------------------------------------

-- DDL for Table CITIES

------------------------------------------------------

CREATE TABLE "LAB_DB"."CITIES"

( "X" NUMBER(6,0),

"CITY" VARCHAR2(128 BYTE),

"STATE" NUMBER(6,0)

) TABLESPACE "USERS" ;

COMMENT ON COLUMN "LAB_DB"."CITIES"."X" IS 'CITIES

surrogate primary key';

COMMENT ON COLUMN "LAB_DB"."CITIES"."CITY" IS 'City

name';

COMMENT ON COLUMN "LAB_DB"."CITIES"."STATE" IS

'Country to which city belongs to';

COMMENT ON TABLE "LAB_DB"."CITIES" IS 'World

cities of interest.';

------------------------------------------------------

-- DDL for Index CITIES_PK

------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."CITIES_PK" ON

"LAB_DB"."CITIES" ("X") TABLESPACE "USERS" ;

------------------------------------------------------

-- DDL for Index CITIES_UK1

------------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."CITIES_UK1" ON

"LAB_DB"."CITIES" ("CITY", "STATE") TABLESPACE "USERS"

;

------------------------------------------------------

-- Constraints for Table CITIES

------------------------------------------------------

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT

"CITIES_PK" PRIMARY KEY ("X")

USING INDEX TABLESPACE "USERS" ENABLE;

Page 102: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

102

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT

"CITIES_UK1" UNIQUE ("CITY", "STATE")

USING INDEX TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("X" NOT NULL

ENABLE);

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("CITY" NOT

NULL ENABLE);

ALTER TABLE "LAB_DB"."CITIES" MODIFY ("STATE" NOT

NULL ENABLE);

------------------------------------------------------

-- Ref Constraints for Table CITIES

------------------------------------------------------

ALTER TABLE "LAB_DB"."CITIES" ADD CONSTRAINT

"CITIES_STATES_FK1" FOREIGN KEY ("STATE")

REFERENCES "LAB_DB"."STATES" ("X") ENABLE;

Note that table COUNTRIES remains the same, just like in the 1st lab.

2.2.4 Exercises in Oracle

P2.1. Insert into the db, by using SQL12

, a city called Memphis as the ca-

pital of the Tennessee state of the U.S.A. (considering that the U.S.A. id is

known: here, it is 7).

Solution:

Obviously, as no such rows exist and as State is compulsory in CITIES,

first we have to insert a corresponding row in STATES, then one in CI-

TIES, and finally declare Memphis as the corresponding state capital:

12 Note that Oracle’s SQL Developer does not provide QBE (= Query-by-

Example); QBE is provided only by the Oracle’s ADF (= Application De-

velopment Framework, including its free, limited Essentials version),

which is requiring a Java IDE and an Application Server too.

Page 103: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

103

1.1 Insert Tennessee in STATES

Open a SQL tab and attach to it the LAB_DB db (see figure 1.83 above);

type in it the following DML statement:

INSERT INTO STATES (State, Country)

VALUES (‘Tennessee’, 7);

Click on the Run Statement icon (the green triangle pointing to the right)

or press Ctrl+Enter to execute it: the Script Output pane will display “1

rows inserted”, whereas the Messages – Log one will contain a “Commit

Successful” message.

Figure 2.24 Programmatically insertion of a line in a table

The new line was indeed inserted (with x = 11):

Page 104: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

104

Figure 2.25 STATES table’s instance after inserting Tennessee

You can save the pane (by clicking on the floppy-disk icon) as a .sql text

file, but you can also save only this statement as a procedure: right-click

on the Procedures node and click on New Procedure:

Figure 2.26 Creating a new PL/SQL procedure in Oracle SQL Developer

In the Create PL/SQL Procedure window that opens, type “insert_

Tennessee” in the Name text box and then click on OK:

Page 105: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

105

Figure 2.27 Naming a new PL/SQL procedure in Oracle SQL Developer

Note that the body of any newly created SQL/PL procedure is null:

Figure 2.28 The initial null body of a new Oracle PL/SQL procedure

Replace the null with the above INSERT statement and save the proce-

dure:

Page 106: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

106

Figure 2.29 The final INSERT_TENNESSEE Oracle PL/SQL procedure

In order to run it, right-click on its name and then click on the Run option;

click then OK in the Run PL/SQL window that opens:

Figure 2.30 Running an Oracle PL/SQL procedure

Page 107: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

107

As you should expect it, no other line is inserted in STATES, as this would

violate the key State ● Country; any such attempt is not only rejected, but

a corresponding error (red) message is displayed (ORA-00001: unique

constraint (LAB_DB.STATES_UK2) violated ORA-06512: at "LAB_DB

.INSERT_TENNESSEE", line 3 ORA-06512: at line 2):

Figure 2.31 Example of an Oracle PL/SQL procedure error message

1.2 Insert Memphis in CITIES

Similarly as above, you should type in the SQL pane of LAB_DB and

then execute the following statement:

INSERT INTO CITIES (City, State)

SELECT ‘Memphis’, x FROM STATES

WHERE State = ‘Tennessee’ AND Country = 7;

A new corresponding row was added, with X = 44 (see figure 2.32 be-

low); save it as query insertMemphisTennessee.

Page 108: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

108

Figure 2.32: Table CITIES’ instance after inserting Memphis,

Tennessee

Page 109: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

109

1.3 Declare (in STATES) Memphis to be Tennessee‘s state capital

Fortunately, the following standard SQL syntax is accepted by Oracle:

UPDATE STATES SET Capital =

(SELECT x FROM CITIES

WHERE City=’Memphis’ AND State =

(SELECT x FROM STATES

WHERE Country= 7 AND State=

‘Tennessee’))

WHERE State = ‘Tennessee’ AND Country = 7;

You may either enter it in the SQL pane of LAB_DB and then run it or

save it as the updateTennesseeCapital PL/SQL procedure and execute it;

the result is that the capital city for Tennessee is from now on 44 instead

of null (compare with figure 2.25 above):

Figure 2.33: STATES table’s instance after updating Tennessee’s capital

Note that, trivially, this a programmatic approach, needed when dynami-

cally having to update data through db software applications (which is the

standard way to manage data, thus hiding both dbs and needed operatio-

nal workflows from end-users); obviously, same things may be accom-

plished statically, by non-programmer users, using the Oracle SQL Deve-

Page 110: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

110

loper GUI: figures 2.34, 2.35, and 2.36 are showing how to add state and

its state capital Sibiu from Romania.

Figure 2.34: Inserting a new state (Sibiu) using Oracle SQL Developer

Figure 2.35: Inserting a new city (Sibiu) using Oracle SQL Developer

Page 111: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

111

Figure 2.36: Storing the fact that Sibiu is the capital of the homonym

state, by using Oracle SQL Developer

P2.2. Parameterize the first insert statement of P2.1 above such as to in-

sert a new state in any desired existing country.

Solution:

Note that, Oracle requires for its native dynamic SQL parameters valid

variable names prefixed by ‘:’. Consequently, when running such a state-

ment, Oracle will ask users for the actual value of all such parameters.

This is why the solution for parameterizing the first insert statement from

P2.1 above (see 1.1 of P2.1 above) is the following:

INSERT INTO STATES (State, Country)

SELECT :EnterDesiredStateName, x

FROM COUNTRIES

WHERE Country = :EnterDesiredCountrName;

Figures 2.37 and 2.38 below show how actual parameter values are

passed through when running this query from a SQL pane of DB_LAB

(you can select any parameter by clicking on its name; you enter corres-

ponding actual values into the Value text box; when ready, click Apply);

figure 2.39 presents the new STATES table instance, including state Dolj.

Page 112: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

112

Figure 2.37: Providing actual EnterDesiredStateName parameter value

Figure 2.38: Providing actual EnterDesiredCountryName parameter value

Page 113: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

113

Figure 2.39: STATES instance after inserting state Dolj

When such parameterized queries need to be run either frequently and/or

programmatically, the best solution is to store them as a PL/SQL proce-

dure; for example, create and save (similar to figures 2.26 to 2.29 above)

procedure Insert_State. Figure 2.40 shows how to give names, besides to

the procedure itself, to its parameters too. Figure 2.41 shows the corres-

ponding initial code, with a null body. Figure 2.42 shows the final code:

note that in PL/SQL you should not use the prefix ‘:’ for parameters, as

they are explicitly defined, just like in any other high level programming

language.

Figure 2.43 presents how to enter actual parameter values when running

the procedure from the Oracle SQL Developer GUI: you simply have to

replace “null” in their assignment statements with desired actual values

(as both are VARCHAR strings, do not forget the enclosing apo-

strophes!). Figure 2.44 shows STATES instance after inserting North

Dakota.

Page 114: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

114

Figure 2.40: Assigning names to PL/SQL procedure parameters

Figure 2.41: Initially empty Insert_States PL/SQL procedure body

Page 115: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

115

Figure 2.42: Final Insert_States PL/SQL procedure body

Page 116: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

116

Figure 2.43: Passing actual parameters values to a PL/SQL procedure

Figure 2.44: STATES instance after inserting state North Dakota

Page 117: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

117

Note that, both programmatically and from a LAB_DB SQL pane of the

SQL Developer, you can run a PL/SQL procedure and give its actual

parameter values by using the EXECUTE statement; in this case, for

example, you could have run instead:

EXECUTE insert_state ('North Dakota', 'U.S.A.');

2.3 Best practice rules BPR2.0 Before modifying data values, especially for massive updates and

deletes, always backup the corresponding table’s instances (so that if

anything goes wrong you may restore previous values).

BPR2.1 Before modifying data values by using SELECT clauses, espe-

cially for massive modifications, first test corresponding SELECT re-

sults, for checking whether or not they correctly compute the set of desir-

ed rows (be it for insertion, update, or deletion).

BPR2.2 Always strictly modify only data which has to be modified:

don’t forget and program extremely carefully the WHERE clause of the

UPDATE and DELETE statements.

BPR2.3 Even when “nothing can go wrong”, embed data modification

statements in transactions having not only COMMITs, but ROLLBACKs

too: not even RDBMSs are perfect, communications may fail, power ou-

tages may occur, etc.!

BPR2.4 Use the ON DELETE CASCADE predicate with same caution

as when manipulating atomic bombs: it is a potential data “mass-ex-

tinction” weapon!

BPR2.5 Do not forget that, generally, when executing SQL DELETE

statements, RDBMSs do not physically, but only logically delete (in fact,

they mark for deletion) corresponding deleted data; consequently, purge

immediately old unneeded data.

BPR2.6 Always factorize I/O operations, for keeping them to the mini-

mum possible.

Page 118: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

118

BPR2.7 Do not ever deliver any query, view, stored procedure, func-

tion, or trigger without completely and thoroughly unit testing it. All

subsequent tests should be run only with nearly perfectly functioning

units.

2.4 Homework H2.1 Design, develop and test a parameterized query for inserting any ci-

ty in an existing state.

Hint: ask users for city, state, and country names.

H2.2 Parameterize a similar update state capital that has 3 prompts for

country, city, and state and store the fact that corresponding city is the ca-

pital of that state.

H2.3 Insert a test country, 2 test states of it and 4 test cities, 2 per test

state (both manually/SQL and QBE) and then design, develop and test ne-

eded delete statements in order to delete all test data.

Page 119: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

119

Chapter 3. 3rd Lab: INNER JOIN, GROUP BY, and HAVING

clauses

3.1 Introduction Please recall that:

Any time when ambiguities are possible in SQL statements, you

should prefix column names with corresponding table instance

names.

Even when no ambiguities are possible, in ON sub-clauses prefix-

ing of all column names with their corresponding table instance

names is compulsory.

In ORDER BY, ASC is implicit.

Constants should be hard-codded in SQL only exceptionally; ge-

nerally, use parameters instead (e.g. P3.1b below generalizes bil-

lion of queries of the type P3.1a below).

The SQL GROUP BY c1, …, cn clause partitions the set of records

obtained by filtering with the corresponding WHERE clause (if

any) the set of records computed by the corresponding FROM

clause according to the equivalence relation ker(c1 … cn),

where c1, …, cn are columns from that FROM clause table instan-

ces.

Recall that, for any function product f g, ker(f g) = ker(f)

ker(g), and that, for any function f : A B, ker(f) = {(x, y) A2 |

f(x) = f(y)} A2 (called the kernel or nucleus of f).

If you do not give names to your SQL SELECT clause expres-

sions, RDBMSs are assigning automatically generated ones to

them, generally of the type Expr1, Expr2, …

Although there is no standard for what aggregate functions to be

provided, most RDBMSs offer at least the following most fre-

quently used ones: COUNT (for computing set cardinals), SUM,

AVG (for computing arithmetic means), MIN(imum), and MAX(i-

mum).

You cannot compose two SQL aggregate functions (although you

can compose an aggregate function with other library functions).

Page 120: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

120

The so-called GROUP BY golden rule states that, in the presence

of the GROUP BY clause, corresponding SELECT clause can only

contain columns/expressions listed in the GROUP BY clause

and/or any columns/expressions based on columns of the corres-

ponding FROM clause, provided that they are arguments of aggre-

gate functions.

The order of the SQL SELECT clauses is immutable not only for

syntactical reasons, but for conceptual ones too: it is exactly the

order in which RDBMSs are evaluating these queries.

3.2 The algorithm for assisting DML statements

design Algorithm A0 (DML statements design assistance)

start a(n empty) list with involved tables and columns;

draw the desired result table header;

fill its instance with at least a couple of plausible rows;

Select query type

Case SELECT:

end Case SELECT;

Case INSERT:

end Case INSERT;

Case UPDATE:

end Case UPDATE;

Case DELETE:

end Case DELETE;

end Select query type;

end Algorithm A0 (DML statements design assistance);

procedure determineTargetColumnsList

Page 121: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

121

repeat for each column

determine whether current column corresponds to a stored or computed

one;

if it is a stored one

then add corresponding stored column and table to both your list and

result table header;

else design and add to the result table header needed computation

formula;

repeat for all stored columns from the formula

add current column and corresponding table to your list;

end repeat;

end repeat for each column;

end procedure determineTargetColumnsList;

procedure determineTargetTableInstancesList

repeat for each table occurrence from the resulted list

if it is not the first occurrence of current table then

determine whether or not you need another instance of current table;

if yes then give it a unique meaningful name else discard it;

end repeat for each table occurence;

repeat for each table instance from the resulted list

repeat for all other table instances from the resulted list

repeat for all foreign keys between them

determine whether or not current foreign key is needed;

if yes then draw a line in your table list between current

foreign key and corresponding referenced column;

end repeat for all foreign keys;

if no line was draw between current table instances then

determine whether or not you need a Cartesian product between

them;

if yes then draw a line between current table instance names

interrupted in the middle by the Cartesian product operator

end repeat for all other table instances;

end repeat for each table instance;

end procedure determineTargetTableInstancesList;

Page 122: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

122

procedure DetermineFilters;

end procedure DetermineFilters;

3.3 Exercises in Access P3.1 a. Compute the set of cities (name, corresponding state and country

names, and population) that have at least 1,000,000 inhabitants, in the

descending order of their population and then ascending on country, state,

and city names.

b. Parameterize a. above and compute result for both 1,000,000

and 500,000.

Solution:

a.

How should the result look like:

Inspecting corresponding data instances, obviously, only three cities qua-

lify for the result (in this order): New York, London, and Bucharest.

The result should then be:

City STATES.State COUNTRIES.Country CITIES.Population

New York New York U.S.A. 8,336,697

London Greater

London

U.K. 8,308,369

Bucharest Bucharest Romania 1,883,425

Data needed for final result: City, CITIES.Population, STATES.State,

and COUNTRIES.Country;

Page 123: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

123

Data needed to link these three tables’ instances: CITIES.State =

STATES.x and STATES.Country = COUNTRIES.x

Data needed for filtering: CITIES.Population

SQL solution:

SELECT City, STATES.State, COUNTRIES.Country,

CITIES.Population

FROM (CITIES INNER JOIN STATES ON CITIES.State = STATES.x)

INNER JOIN COUNTRIES ON STATES.Country = COUNTRIES.x

WHERE CITIES.Population >= 1000000

ORDER BY CITIES.Population DESC, COUNTRIES.Country,

STATES.State, City;

The result of running it against the lab’s db instance is the following:

Figure 3.1 Result of P3.1a

b.

The only difference with respect to the above query is replacing

the hard-codded constant 1000000 with a parameter:

SELECT City, STATES.State, COUNTRIES.Country,

Page 124: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

124

CITIES.Population

FROM (CITIES INNER JOIN STATES ON CITIES.State = STATES.x)

INNER JOIN COUNTRIES ON STATES.Country = COUNTRIES.x

WHERE CITIES.Population >=

[Please enter desired minimum city population:]

ORDER BY CITIES.Population DESC, COUNTRIES.Country,

STATES.State, City;

Obviously, the result of running it against the lab’s db instance with the

actual parameter value 1000000 is the same as the one in figure 3.1

above.

The result of running it against the lab’s db instance with the actual para-

meter value 500000 (figure 3.2) also selects Chișinău, Memphis, and Wa-

shington (figure 3.3).

Figure 3.2 Entering actual parameter value for P3.1b

Figure 3.3 Result of P3.1b for 500,000

Page 125: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

125

P3.2 a. Compute the set of countries (name, population, sum of corres-

ponding cities population, unaccounted cities population), in the descend-

ing order of unaccounted cities population, sum of corresponding cities

population, stored countries population, and then ascending on country

names.

b. Same as a. above, but only for countries for which the sum of

cities population is at least equal to a parameter value; run it for 7,000,000

people.

c. Same as b. above, but only for countries whose names start with

‘R’; run it for 2,500,000 people.

Solution:

How should the result look like:

Inspecting corresponding data instances, obviously, all four coun-

tries qualify for the result (in this order): U.S.A., U.K., Romania,

and Moldavia.

The result should then be (where UnaccCityPop = Population -

SumCityPop):

Country Population SumCityPop UnaccCityPop

U.S.A. 316,836,000 9,624,175 307,211,825

U.K. 63,181,775 8,308,369 54873406

Romania 20,121,641 2,604,964 17,516,677

Moldavia 3,559,500 671,800 2887700

Data needed for final result: COUNTRIES.Country, COUNTRIES.Popu-

lation, and CITIES.Population;

Page 126: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

126

Data needed to link these three tables’ instances: CITIES.State =

STATES.x and STATES.Country = COUNTRIES.x

SQL solution:

Both conceptually and from the RDBMSs performance point of view, it is

preferable to split complex problems into smaller and simpler sub-pro-

blems and to interconnect in the end their solutions.

Consequently, let us first solve the sub-problem of computing the sum of

cities populations per countries.

Obviously, by using the SQL aggregate function SUM in the following

query, it computes the sum of all cities populations in the world (see

figure 3.4 for its result):

SELECT SUM(Population) AS TotCitiesPop FROM CITIES;

Figure 3.4 The sum of all cities’ populations

For computing total city populations per country, we obviously need to

partition cities on group per countries, such as for SUM to compute totals

per countries, instead of the worldwide one:

SELECT Sum(CITIES.Population) AS CityPopSum, Country

FROM STATES INNER JOIN CITIES

ON STATES.x = CITIES.State

GROUP BY Country;

Page 127: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

127

Running this query, saved as P3-2-0, against the current lab’s db instance,

it is computing the following result:

Figure 3.5 The sum of all cities’ populations per country

The second sub-problem is to use the results of the previous one for com-

puting final results; obviously, a join of query P3-2-0 with the COUN-

TRIES table is needed in order to get both country names and populations:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

FROM [P3-2-0] INNER JOIN COUNTRIES

ON [P3-2-0].Country = COUNTRIES.x

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

Population DESC, COUNTRIES.Country;

The result of running it against the lab’s db instance is the following:

Page 128: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

128

Figure 3.6 Result of P3.2a

Note that, unfortunately, many programmers would actually come up with

the following equivalent, but not optimal solution:

P3-2-0Bis:

SELECT Sum(CITIES.Population) AS CityPopSum,

COUNTRIES.Country

FROM (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State) INNER JOIN COUNTRIES

ON STATES.Country = COUNTRIES.x

GROUP BY COUNTRIES.Country;

P-3-2aBis: SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

FROM [P3-2-0Bis] INNER JOIN COUNTRIES

ON [P3-2-0Bis].Country = COUNTRIES.Country

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

Population DESC, COUNTRIES.Country;

Note that P3-2-0B is already taking more time and both memory and disk

space, as it makes an additional join and computes country names (that, in

average, have some 32 ASCII chars) instead of surrogate key values (that

need 4 binary bytes).

Much worse is P-3-2aBis, which is joining not on surrogate key values

(requiring the fastest –arithmetic-logic– unit of the CPU and only one me-

mory cycle per comparison), like P-3-2a, but on ASCII strings (requiring

Page 129: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

129

the slowest –decimal– unit of the CPU and an average of 32 memory cy-

cles per comparison).

b.

Obviously, the only thing that has to be done is to add a HAVING clause

to P3-2-0:

P3-2-0b:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM STATES INNER JOIN CITIES ON STATES.x = CITIES.State

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >= [Please enter desired

minimum cities total population per country:];

Figure 3.7 shows Access’ actual parameter values input window, figures

3.8 – corresponding result of P3-2-0b for 7,000,000, and 3.9 – the one for

the corresponding P-3-2b:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

FROM [P3-2-0b] INNER JOIN COUNTRIES

ON [P3-2-0b].Country = COUNTRIES.x

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

Figure 3.7 Entering actual parameter value for P3.2-0b

Page 130: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

130

Figure 3.8 Result of P3.2-0b for 7,000,000 people

Figure 3.9 Result of P3.2b for 7,000,000 people

Note that a same result may be obtained with a single statement, by using

a subquery (but generally, subqueries are less fast evaluated by RDBMSs

than queries hierarchies):

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

Page 131: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

131

FROM (SELECT Sum(CITIES.Population) AS CityPopSum,

STATES.Country

FROM STATES INNER JOIN CITIES

ON STATES.x = CITIES.State

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >= [Please enter

desired minimum cities total population per

country:]) AS [P3-2-0b]

INNER JOIN COUNTRIES ON [P3-2-0b].Country = COUNTRIES.x

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

Page 132: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

132

c.

Even if not that obvious, the best thing to do is to add a corresponding

filter to P-3-2-0b:

P-3-2-0c:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

WHERE COUNTRIES.Country Like "R*"

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >= [Please enter desired

minimum cities total population per country:];

Figure 3.10 shows Access’ actual parameter values input window, figures

3.11 – corresponding result of P3-2-0c for 2,500,000, and 3.12 – the one

for the corresponding P-3-2c:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

FROM [P3-2-0c] INNER JOIN COUNTRIES

ON [P3-2-0c].Country = COUNTRIES.x

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

Figure 3.10 Entering actual parameter value for P3.2-0c

Page 133: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

133

Figure 3.11 Result of P3.2-0c for 2,500,000 people

Figure 3.12 Result of P3.2c for 2,500,000 people

Please note again that, unfortunately, some programmers would rather

come up with one of the following equivalent, but not at all optimal

solutions:

Page 134: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

134

P-3-2-0cBis:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

GROUP BY STATES.Country

HAVING COUNTRIES.Country Like "R*" AND

Sum(CITIES.Population) >= [Please enter desired

minimum cities total population per country:];

or keeping P-3-2-0b as such and modifying P-3-2c to:

P-3-2cBis:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

[Population]-[CityPopSum] AS UnaccPop

FROM [P3-2-0cBis] INNER JOIN COUNTRIES

ON [P3-2-0cBis].Country = COUNTRIES.x

WHERE COUNTRIES.Country Like "R*"

ORDER BY [Population]-[CityPopSum] DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

When you compare them, it is trivial that:

P3-2-0c is only computing, in this particular case, one group (for

Romania) and, generally, about one dozen group (for Romania,

Russia, Rwanda, etc.), whereas

Both P-3-2-0cBis and P-3-2cBis are still computing all groups

(four in this particular case, but some 250 for full countries’ data)

and then are throwing away the vast majority of their computation

results (three groups in this particular case, but some 238 for full

countries’ data).

Generally, note that we cannot get rid of HAVING clauses, as this is the

only place where we can add filters on data computed (generally through

aggregation) after grouping; dually, we could sometimes get rid of

WHERE clauses (not always, as –see figure 3.4 above– sometimes we

Page 135: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

135

might need filters on global applications of aggregate functions) and only

use HAVING ones, but this would be a stupid thing to do, both concep-

tually and, especially, performance-wise.

3.4 Exercises in Oracle P3.1 a. Compute the set of cities (name, corresponding state and country

names, and population) that have at least 1,000,000 inhabitants, in the

descending order of their population and then ascending on country, state,

and city names.

b. Parameterize a. above and compute results for both 1,000,000

and 500,000.

Solution:

a.

How should the result look like:

Inspecting corresponding data instances, obviously, only three cities qua-

lify for the result (in this order): New York, London, and Bucharest.

The result should then be:

City STATES.State COUNTRIES.Country CITIES.Population

New York New York U.S.A. 8,336,697

London Greater

London

U.K. 8,308,369

Bucharest Bucharest Romania 1,883,425

Data needed for final result: City, CITIES.Population, STATES.State,

and COUNTRIES.Country;

Data needed to link these three tables’ instances: CITIES.State =

STATES.x and STATES.Country = COUNTRIES.x

Page 136: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

136

Data needed for filtering: CITIES.Population

SQL solution:

SELECT City, STATES.State, COUNTRIES.Country,

CITIES.Population

FROM (CITIES INNER JOIN STATES ON CITIES.State = STATES.x)

INNER JOIN COUNTRIES ON STATES.Country = COUNTRIES.x

WHERE CITIES.Population >= 1000000

ORDER BY CITIES.Population DESC, COUNTRIES.Country,

STATES.State, City;

The result of running it against the lab’s db instance is the following:

Figure 3.13 Result of P3.1a

Page 137: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

137

b.

The only difference with respect to the above query is replacing

the hard-codded constant 1000000 with a parameter:

SELECT City, STATES.State, COUNTRIES.Country,

CITIES.Population

FROM (CITIES INNER JOIN STATES ON CITIES.State = STATES.x)

INNER JOIN COUNTRIES ON STATES.Country = COUNTRIES.x

WHERE CITIES.Population >=

:Minimum_city_population

ORDER BY CITIES.Population DESC, COUNTRIES.Country,

STATES.State, City;

Obviously, the result of running it against the lab’s db instance with the

actual parameter value 1000000 is the same as the one in figure 3.13

above.

The result of running it against the lab’s db instance with the actual para-

meter value 500000 (figure 3.14) also selects Chișinău, Memphis, and

Washington (figure 3.15). Note that Oracle variable names can be of at

most 30 chars and cannot contain spaces.

Figure 3.14 Entering actual parameter value for P3.1b

Page 138: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

138

Figure 3.15 Result of P3.1b for 500,000

P3.2 a. Compute the set of countries (name, population, sum of corres-

ponding cities population, unaccounted cities population), in the descend-

ing order of unaccounted cities population, sum of corresponding cities

population, stored countries population, and then ascending on country

names.

b. Same as a. above, but only for countries for which the sum of

cities population is at least equal to a parameter value; run it for 7,000,000

people.

c. Same as b. above, but only for countries whose names start with

‘R’; run it for 2,500,000 people.

Solution:

How should the result look like:

Page 139: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

139

Inspecting corresponding data instances, obviously, all four coun-

tries qualify for the result (in this order): U.S.A., U.K., Romania,

and Moldavia.

The result should then be (where UnaccCityPop = Population -

SumCityPop):

Country Population SumCityPop UnaccCityPop

U.S.A. 316,836,000 9,624,175 307,211,825

U.K. 63,181,775 8,308,369 54873406

Romania 20,121,641 2,604,964 17,516,677

Moldavia 3,559,500 671,800 2887700

Data needed for final result: COUNTRIES.Country, COUNTRIES.Popu-

lation, and CITIES.Population;

Data needed to link these three tables’ instances: CITIES.State =

STATES.x and STATES.Country = COUNTRIES.x

SQL solution:

Both conceptually and from the RDBMSs performance point of view, it is

preferable to split complex problems into smaller and simpler sub-pro-

blems and to interconnect in the end their solutions.

Consequently, let us first solve the sub-problem of computing the sum of

cities populations per countries.

Obviously, by using the SQL aggregate function SUM in the following

query, it computes the sum of all cities populations in the world (see

figure 3.4 for its result):

SELECT SUM(Population) AS TotCitiesPop FROM CITIES;

Page 140: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

140

Figure 3.16 The sum of all cities’ populations

For computing total city populations per country, we obviously need to

partition cities on group per countries, such as for SUM to compute totals

per countries, instead of the worldwide one:

SELECT Sum(CITIES.Population) AS CityPopSum, Country

FROM STATES INNER JOIN CITIES

ON STATES.x = CITIES.State

GROUP BY Country;

Running this query against the current lab’s db instance is computing the

following result:

Page 141: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

141

Figure 3.17 The sum of all cities’ populations per country

In order to make use of it in the final step, you should save this query as

view P3-2-0; right-click the View node of LAB_DB, then click on New

View (figure 3.18); in the Create View window that pops up (figure 3.19),

enter the Name of the view (that should be distinct from names of any

other tables and views of LAB_DB) and copy the statement in the SQL

Query text box; click on the Check Syntax button: the message “SQL

Parse Results: No errors found in SQL” should be displayed in the bot-

tom-left corner of the window; click on the Test Query button: the Test

Query window that pops up (figure 3.20) should display the “Query exe-

cuted successfully” Result; click on Close and then on the OK button of

the Create View (figure 3.19): your view is saved and ready to be used.

Page 142: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

142

Figure 3.18 Creating a new view in Oracle SQL Developer

Figure 3.19 Naming and specifying a view in Oracle SQL Developer

Page 143: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

143

Figure 3.20 Testing a view in Oracle SQL Developer

Note that the same result could have been obtained by running the follow-

ing DDL statement:

--------------------------------------------------------

-- DDL for View P3_2_0

--------------------------------------------------------

CREATE OR REPLACE FORCE VIEW "LAB_DB"."P3_2_0"

("CITYPOPSUM", "COUNTRY") AS

SELECT SUM(CITIES.POPULATION) AS CityPopSum, COUNTRY

FROM STATES INNER JOIN CITIES ON STATES.X = CITIES.STATE

GROUP BY COUNTRY;

The second sub-problem is to use the results of the previous one for com-

puting final results; obviously, a join of view P3-2-0 with the COUN-

TRIES table is needed in order to get both country names and populations:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

Population - CityPopSum AS UnaccPop

FROM P3_2_0 INNER JOIN COUNTRIES

ON P3_2_0.Country = COUNTRIES.x

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

Population DESC, COUNTRIES.Country;

Page 144: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

144

The result of running it against the lab’s db instance is the following:

Figure 3.21 Result of P3.2a

Note that, unfortunately, many programmers would actually come up with

the following equivalent, but not optimal solution:

P3_2_0Bis:

SELECT Sum(CITIES.Population) AS CityPopSum,

COUNTRIES.Country

FROM (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State) INNER JOIN COUNTRIES

ON STATES.Country = COUNTRIES.x

GROUP BY COUNTRIES.Country;

P_3_2aBis: SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

Population - CityPopSum AS UnaccPop

FROM P3_2_0Bis INNER JOIN COUNTRIES

ON P3_2_0Bis.Country = COUNTRIES.Country

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

Population DESC, COUNTRIES.Country;

Page 145: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

145

Note that P3_2_0B is already taking more time and both memory and

disk space, as it makes an additional join and computes country names

(that, in average, have some 32 ASCII chars) instead of surrogate key va-

lues (that need 4 binary bytes).

Much worse is P_3_2aBis, which is joining not on surrogate key values

(requiring the fastest –arithmetic-logic– unit of the CPU and only one me-

mory cycle per comparison), like P_3_2a, but on ASCII strings (requiring

the slowest –decimal– unit of the CPU and an average of 32 memory cy-

cles per comparison).

b.

Obviously, the only thing that has to be done is to add a HAVING clause

to P3_2_0; here is the corresponding P3_2_0b:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM STATES INNER JOIN CITIES ON STATES.x = CITIES.State

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

:Min_city_tot_pop_per_country;

Figure 3.22 shows Oracle’s actual parameter values input window,

figures 3.23 – corresponding result of P3_2_0b for 7,000,000, and 3.24 –

the one for the corresponding P_3_2b (with P_3_2_0b as a subquery):

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

Population - CityPopSum AS UnaccPop

FROM (SELECT Sum(CITIES.Population) AS CityPopSum,

STATES.Country

FROM STATES INNER JOIN CITIES

ON STATES.x = CITIES.State

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

:Min_city_tot_pop_per_country) P3_2_0b

INNER JOIN COUNTRIES ON P3_2_0b.Country = COUNTRIES.x

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

Page 146: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

146

Figure 3.22 Entering actual parameter value for P3_2_0b

Figure 3.23 Result of P3_2_0b for 7,000,000 people

Page 147: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

147

Figure 3.24 Result of P3_2b for 7,000,000 people

c.

Even if not that obvious, the best thing to do is to add a corresponding

filter to P_3_2_0b:

P_3_2_0c:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

WHERE COUNTRIES.Country Like ‘R%’

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

:Min_city_tot_pop_per_country;

Page 148: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

148

Figure 3.25 shows Oracle’ actual parameter values input window, figures

3.26 – corresponding result of P3_2_0c for 2,500,000, and 3.27 – the one

for the corresponding P_3_2c:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

Population - CityPopSum AS UnaccPop

FROM (SELECT Sum(CITIES.Population) AS CityPopSum,

STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

WHERE COUNTRIES.Country Like ‘R%’

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

:Min_city_tot_pop_per_country)

P3_2_0c INNER JOIN COUNTRIES

ON P3_2_0c.Country = COUNTRIES.x

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

Figure 3.25 Entering actual parameter value for P3_2_0c

Page 149: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

149

Figure 3.26 Result of P3_2_0c for 2,500,000 people

Figure 3.27 Result of P3_2c for 2,500,000 people

Page 150: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

150

Unfortunately, Oracle does not accept parameterized views; consequent-

ly, the only way to store and run parameterized queries are the PL/SQL

stored procedures; as it is best to group all such procedures addressing

some same functional specifications in a PL/SQL package, let us create

such a package. Right-click the Packages node of LAB_DB and then

click on New Package:

Figure 3.28 Creating a new PL/SQL package

In the Create PL/SQL Package window that pops up, enter desired pac-

kage name:

Figure 3.29 Naming a new PL/SQL package

Page 151: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

151

In the header of the newly created package, replace the comment /* To do

… */ with the following two declarations (see figure 3.30):

TYPE GenericCursorType IS REF CURSOR;

procedure p3_2c (min_city_tot_pop_per_country number,

rc OUT GenericCursorType);

Figure 3.30 The header of the LAB_DB_SQL PL/SQL package

For creating the package body, right-click on the package’s name and

then click on Create Body…:

Figure 3.31 Creating the body of the LAB_DB_SQL PL/SQL package

Page 152: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

152

In the newly created body, enter procedure’s P3_2c definition (see figure

3.32):

procedure p3_2c

(

Min_city_tot_pop_per_country in number,

rc out GenericCursorType

) is

begin

open rc for

SELECT COUNTRIES.Country, COUNTRIES.Population,

CityPopSum, Population - CityPopSum AS UnaccPop

FROM (SELECT Sum(CITIES.Population) AS CityPopSum,

STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

WHERE COUNTRIES.Country Like 'R%'

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

Min_city_tot_pop_per_country)

P3_2_0c INNER JOIN COUNTRIES

ON P3_2_0c.Country = COUNTRIES.x

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

end p3_2c;

In order to run this packaged procedure with desired parameters, enter in

a LAB_DB SQL tab the following statements:

var c refcursor;

exec lab_db_pl_sql.p3_2c(2500000, :c);

print c;

Running them (see figure 3.33), you get same results as in figure 3.26

above; the main advantage with this approach is that you can obtain and

then process this result from now on programmatically too (e.g. in VBA,

Java, .NET, etc.).

Page 153: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

153

Figure 3.32 The body of the LAB_DB_SQL PL/SQL package

Page 154: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

154

Figure 3.33 Running the LAB_DB_SQL.P3_2C PL/SQL packaged

procedure

Please note again that, unfortunately, some programmers would rather

come up with one of the following equivalent, but not at all optimal solu-

tions:

P_3_2_0cBis:

SELECT Sum(CITIES.Population) AS CityPopSum, STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

GROUP BY STATES.Country

HAVING COUNTRIES.Country Like ‘R%’ AND

Sum(CITIES.Population) >= : Min_city_tot_pop_per_country;

Page 155: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

155

or keeping P_3_2_0c as such and modifying P_3_2c to:

P_3_2cBis:

SELECT COUNTRIES.Country, COUNTRIES.Population, CityPopSum,

Population - CityPopSum AS UnaccPop

FROM (SELECT Sum(CITIES.Population) AS CityPopSum,

STATES.Country

FROM COUNTRIES INNER JOIN (STATES INNER JOIN CITIES

ON STATES.x = CITIES.State)

ON STATES.Country = COUNTRIES.x

GROUP BY STATES.Country

HAVING Sum(CITIES.Population) >=

:Min_city_tot_pop_per_country)

P3_2_0c INNER JOIN COUNTRIES

ON P3_2_0c.Country = COUNTRIES.x

WHERE COUNTRIES.Country Like ‘R%’

ORDER BY Population - CityPopSum DESC, CityPopSum DESC,

COUNTRIES.Population DESC, COUNTRIES.Country;

When you compare them, it is trivial that:

P3_2_0c is only computing, in this particular case, one group (for

Romania) and, generally, about one dozen group (for Romania,

Russia, Rwanda, etc.), whereas

Both P_3_2_0cBis and P_3_2cBis are still computing all groups

(four in this particular case, but some 250 for full countries’ data)

and then are throwing away the vast majority of their computation

results (three groups in this particular case, but some 238 for full

countries’ data).

Generally, note that we cannot get rid of HAVING clauses, as this is the

only place where we can add filters on data computed (generally through

aggregation) after grouping; dually, we could sometimes get rid of

WHERE clauses (not always, as –see figure 3.4 above– sometimes we

might need filters on global applications of aggregate functions) and only

Page 156: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

156

use HAVING ones, but this would be a stupid thing to do, both concep-

tually and, especially, performance wise.

3.5 Best practice rules BPR3.0 Always name your SQL SELECT clause expressions with

proper names (by using the AS renaming operator).

BPR3.1 Both conceptually and from the RDBMSs performance point of

view, it is preferable to split complex problems into smaller and sim-

pler sub-problems and to interconnect in the end their solutions.

BPR3.2 Always use only necessary data (dually: never use

unnecessary tables and/or columns) in your queries.

BPR3.3 When possible, always join table instances on smallest nume-

rical keys (generally, primary surrogate ones), instead of any other

existing equivalent keys.

BPR3.4 Always use WHERE for filtering as much as possible before

grouping.

BPR3.5 Use HAVING only for filtering on data computed after

grouping (dually: never use HAVING for filters that can be placed on

WHERE!).

BPR3.6 Never present users with unordered results, except for cases

when they are explicitly asking for it.

BPR3.7 Always order results intelligently, such as to maximize users

experience with your application.

BPR3.8 Never order data more than once, in the final querying step.

BPR3.9 Never order on more columns/expressions than needed: or-

dering costs a lot!

BPR3.10 Never order by using column positions! For example, always

use SELECT x, y … ORDER BY x, y; never use SELECT x, y

… ORDER BY 1, 2; instead, as, one day, when you will have to

Page 157: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

157

change it to SELECT y, x … ORDER BY x, y;, you have to also

change the ordering order (to SELECT y, x … ORDER BY x, y;) .

3.5 Homework H3.0 Prove that:

a. the functions kernel relation is an equivalence one.

b. the kernel of a function product is equal to the intersection of

involved kernels

H3.1 Prove that there is no SQL solution for P3.2 above without subque-

ries or queries hierarchies.

Hint: consider both the “GROUP BY golden rule” and the restriction that

aggregate functions cannot be composed between them.

H3.2 Compute the set of countries having at least k states, each of which

has at least n cities (k and n being natural parameters), for which the unac-

counted states and cities population per countries are at least equal to

other two distinct parameters, respectively, in the descending order of the

unaccounted states population per country, city population per country,

corresponding accounted ones, stored countries population, and then as-

cending on country name.

p.s. It is highly possible that an exercise of this type, generally simpler

from the arithmetic point of view, be the main oral examination subject at

the end of this semester!

H3.3 a. Add to the COUNTRIES table data for Hungary, Serbia, Bulgaria,

Greece, Malta, and Ukraine.

b. Add to your lab db a table for storing the NEIGHBORS binary

relation defined over COUNTRIES: NEIGHBORS = { (x,y) COUN-

TRIES2 |x is neighbor to y } and populate it with actual data for all

countries in COUNTRIES.

H3.4 Translate into relational algebra and optimize all the SELECT state-

ments from these first three DB labs.

Page 158: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

158

Chapter 4. 4th Lab: Outer Joins, the Is Null predicate,

and UNIONs

4.1 Prerequisites in Access Homework 3.3 is the pre-requisite for this lab.

4.1.1 Adding needed countries to the COUNTRIES table

COUNTRIES should have the following instance:

Figure 4.1 COUNTRIES instance after solving homework 3.3a

4.1.2 Adding the NEIGHBORS table and populating its instance

Obviously, the RDM scheme and corresponding instance should be the

one presented in figure 4.2; figures 4.3 and 4.4 show its corresponding

Access implementation and instance.

Note that, trivially, Country Neighbor is a key, as it wouldn’t make

sense to store more than once any neighboring fact. Moreover, obviously,

from a db perspective, this mathematical relation is irreflexive (as it is

senseless to store the fact that a country is neighbor to itself) and antisym-

metric (as, once having stored that country c is neighbor to country n, the

dual fact that country n is neighbor to country c is computable, so it does

not make sense to store it too). Unfortunately, no RDBMS can enforce

these constraints (as they are non-relational, so not expressible in pure

Page 159: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

159

SQL), but only through triggers or trigger-type methods (using either

extended SQL or high level programming languages – Java, C#, VBA, ...).

NEIGHBORS (x, Country Neighbor)

x Country Neighbor

autonumber(4) Im(COUNTRIES.x) Im(COUNTRIES.x)

NOT NULL NOT NULL NOT NULL

1 1 2

2 1 5

3 1 6

4 1 9

5 1 10

6 2 9

7 5 6

8 5 10

9 6 7

10 9 10

Figure 4.2 NEIGHBORS table (see homework 3.3b)

Figure 4.3 Access implementation of the NEIGHBORS table

Page 160: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

160

Figure 4.4 Access instance of the NEIGHBORS table

4.2 Exercises in Access P4.1. a. Compute the number of neighbors of country ‘Moldavia’.

b. Parameterize this query and compute the numbers of neighbors

of country ‘Serbia’.

Solution:

a.

Firstly, please note that, due to NEIGHBORS antisymmetry, any country

may appear in this table instance either only in the Country column (e.g.

Romania), or only in the Neighbor one (e.g. Hungary), or in both of them

(e.g. Serbia, Bulgaria, Ukraine).

Trivially, the only table we need is NEIGHBORS, but, generally, for any

country, we have to add the number of its occurrences in both columns

(corresponding to this math relation canonical Cartesian projections).

Page 161: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

161

Consequently, the SQL solution (save it as query P4-1) is the following:

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

DLookup("x", "COUNTRIES", "Country = 'Moldavia'")

OR NEIGHBOR =

DLookup("x", "COUNTRIES", "Country = 'Moldavia'");

The equivalent Design mode (QBE) solution is:

Figure 4.5 Access solution to P4-1

Please note first that this is the fastest possible solution: Access only eva-

luates once the DLookup (as it has same actual parameter values in both

calls); the only faster solution is when we know the corresponding coun-

try code (as no access to COUNTRIES is needed anymore):

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY = 2 OR NEIGHBOR = 2;

Another equivalent, more elegant, but less performing solution involves

using subqueries instead of the DLookup function (which also has a di-

dactic advantage: it provides yet another example of the DLookup seman-

tics; note that the TOP predicate is not needed here, as Country is a key in

COUNTRIES):

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

(SELECT x FROM COUNTRIES WHERE Country = 'Moldavia')

Page 162: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

162

OR NEIGHBOR =

(SELECT x FROM COUNTRIES WHERE Country = 'Moldavia');

The following equivalent solution, which replaces subqueries with a hie-

rarchies of queries is only a very little bit faster, but still slower than the

P4-1 above (the one which also uses DLookup, but in only one step), be-

cause it is evaluating twice same DLookup call:

P4-1CBis:

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

DLookup("x", "COUNTRIES", "Country = 'Moldavia'");

P4-1NBis:

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE NEIGHBOR =

DLookup("x", "COUNTRIES", "Country = 'Moldavia'");

P4-1Bis:

SELECT P4-1aCBis.MoldaviaNeighborNo +

P4-1aNBis.MoldaviaNeighborNo AS MoldaviaNeighborNo

FROM P4-1aCBis, P4-1aNBis;

Note that if irreflexivity is not enforced, then any row of type <x,x>

would vitiate this result (as compared to the mental corresponding com-

putation): for example, if the table instance would also contain line <11,

2, 2>, then (because of the OR), SQL computes 3, whereas there are 4 oc-

currences of 2 (two in Countries and 2 in Neighbors). Obviously, this is

just another reason for enforcing irreflexivity of NEIGHBORS too.

b.

Parameterization of P4-1a is straightforward (save it as P-41b):

SELECT COUNT(*) AS CountryNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

DLookup("x", "COUNTRIES", "Country = '” &

Page 163: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

163

[Please enter desired country name:] & “'")

OR NEIGHBOR =

DLookup("x", "COUNTRIES", "Country = '” &

[Please enter desired country name:] & “'");

Figure 4.6 shows the window for passing “Serbia” as an actual parameter

value to it, whereas 4.7 presents its result for this value:

Figure 4.6 Passing an actual parameter value to query P4-1b

Figure 4.7 Query P4-1b result for “Serbia”

P4.2 Compute the set of countries without neighbors, in ascending order

of their names.

Solution:

Obviously, all needed data is stored in COUNTRIES and NEIGHBORS

and, again, due to NEIGHBORS math relation antisymmetry, we have to

look up for such countries in both Country and Neighbor columns.

Page 164: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

164

Unfortunately, as Access does not accept unions in subqueries, the

following simplest and most elegant SQL solution cannot be used:

SELECT COUNTRY FROM COUNTRIES WHERE X NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS

UNION

SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

ORDER BY COUNTRY;

Consequently, we have to modify it slightly (save it as P4-2):

SELECT COUNTRY FROM COUNTRIES

WHERE x NOT IN (SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN (SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

ORDER BY COUNTRY;

Figure 4.8 shows its result; note that, just like in math, the SQL UNION

operator eliminates duplicates13

.

Figure 4.8 Query P4-2 result

A faster, subqueryless equivalent statement makes use of outer joins, the

Is Null predicate, and a queries hierarchy (save it as P4-2Bis) based on

two dual preliminary queries (P4-2CBis and P4-2NBis):

13

Whenever you need such duplicates, use UNION ALL instead.

Page 165: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

165

P4-2CBis:

SELECT DISTINCT Country AS x FROM NEIGHBORS;

P4-2NBis:

SELECT DISTINCT Neighbor AS x FROM NEIGHBORS;

P4-2Bis:

SELECT Country

FROM (COUNTRIES LEFT JOIN [P4-2CBis]

ON COUNTRIES.x = [P4-2CBis].x) LEFT JOIN

[P4-2NBis] ON COUNTRIES.x = [P4-2NBis].x

WHERE [P4-2CBis].x Is Null AND [P4-2NBis].x Is Null

ORDER BY COUNTRIES.Country;

Note that without DISTINCT, the result is the same, but it takes more

time to be computed: for example, P4-2CBis above computes the set {1,

2, 5, 6, 9} (see figure 4.9), whereas SELECT Country AS x FROM

NEIGHBORS; is computing the list {1, 1, 1, 1, 1, 2, 5, 5, 6, 9}.

Figure 4.9 Result of running P4-2CBis

Also note that the following simpler, one step equivalent query, is the fas-

test of them all, as it does not use either subqueries or queries hierarchies,

but only two instances of table NEIGHBORS:

SELECT DISTINCT COUNTRIES.Country

FROM (COUNTRIES LEFT JOIN NEIGHBORS

Page 166: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

166

ON COUNTRIES.x = NEIGHBORS.Country) LEFT JOIN

NEIGHBORS AS NEIGHBOR_COUNTRIES

ON COUNTRIES.x = NEIGHBOR_COUNTRIES.Neighbor

WHERE NEIGHBORS.Country Is Null AND

NEIGHBOR_COUNTRIES.Neighbor Is Null

ORDER BY COUNTRIES.Country;

P4.3. a. Compute the set of pairs <country name, neighbors number> for

countries having at least k neighbors (k natural), in descending order of

the number of their neighbors and then ascending on their names.

b. What are the corresponding results for k = 3 and k = 0?

Solution:

Obviously, the corresponding result for any k 0, manually computed (by

writing all countries from COUNTRIES, in alphabetic order, in the first

column of the table shown in figure 4.10, counting how many times each

one appears in NEIGHBOR.Country and writing the result in the Right-

Neighbors column, then same thing for the NEIGHBOR.Neighbor and

writing the result in the LeftNeighbors one, and then adding the two pre-

vious column values and writing them down in the TotalNeighbors co-

lumn), is the following (but only in the alphabetic order of Country, not in

the one asked by the exercise):

Country RightNeighbors LeftNeighbors TotalNeighbors

Bulgaria 1 2 3

Greece 0 1 1

Hungary 0 3 3

Malta 0 0 0

Moldavia 1 1 2

Romania 5 0 5

Serbia 2 1 3

Page 167: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

167

U.K. 0 0 0

U.S.A. 0 0 0

Ukraine 1 2 3

Figure 4.10 Results of manually computing total number of neighbors per

country (in the ascending order of country names)

As even manually this problem is sub-dividable in smaller problems, let’s

program it in SQL in the same manner, step by step:

P4-3a0C (compute total number of neighbors per country for Country):

SELECT Country, Count(Neighbor) AS [N#]

FROM NEIGHBORS GROUP BY Country;

P4-3a0N (compute total number of neighbors per country for Neighbor):

SELECT Neighbor, Count(Country) AS [N#]

FROM NEIGHBORS GROUP BY Neighbor;

P4-3a1B (compute total number of neighbors per country for countries

occurring both in Country and Neighbor):

SELECT Country,

[P4-3a0c].[N#]+[P4-3a0n].[N#] AS NeighborsInBothSides

FROM [P4-3a0C] INNER JOIN [P4-3a0N]

ON [P4-3a0C].Country = [P4-3a0N].Neighbor;

P4-3a1L (compute total number of neighbors per country for countries

occurring only in Country):

SELECT Country, [P4-3a0C].[N#]

FROM [P4-3a0C] LEFT JOIN [P4-3a0N]

ON [P4-3a0C].Country = [P4-3a0N].Neighbor

WHERE Neighbor Is Null;

Page 168: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

168

P4-3a1R (compute total number of neighbors per country for countries

occurring only in Neighbor):

SELECT Neighbor, [P4-3a0N].[N#]

FROM [P4-3a0N] LEFT JOIN [P4-3a0C]

ON [P4-3a0N].Neighbor = [P4-3a0C].Country

WHERE Country Is Null;

P4-3a2 (union results of P4-2, for countries with no neighbors, slightly

modified in order to select x instead of Country,with the ones of P4-3a1B,

P4-3a1L, and P4-3a1R):

SELECT x, 0 AS NeighborsNo FROM COUNTRIES

WHERE x NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN

(SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

UNION

SELECT * FROM [P4-3a1B]

UNION

SELECT * FROM [P4-3a1L]

UNION

SELECT * FROM [P4-3a1R];

P4-3a (computing final result):

SELECT Country, NeighborsNo

FROM COUNTRIES INNER JOIN [P4-3a2]

ON COUNTRIES.x = [P4-3a2].x

WHERE NeighborsNo >= [k:]

ORDER BY NeighborsNo DESC, COUNTRIES.Country;

Figures 4.11 and 4.12 show the corresponding results for k = 3 and k = 0:

Page 169: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

169

Figure 4.11 Result of P4-3a for k = 3

Figure 4.12 Result of P4-3a for k = 0

Again, just like for P4-2 above, the following simpler solution is not ac-

cepted by Access, as it uses UNION in a subquery:

SELECT COUNTRIES.COUNTRY, [NEIGHBORS#]

FROM COUNTRIES INNER JOIN

(SELECT COUNTRY, SUM ([N#]) AS [NEIGHBORS#] FROM

(SELECT COUNTRY, COUNT(*) AS [N#]

Page 170: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

170

FROM NEIGHBORS GROUP BY COUNTRY

UNION

SELECT NEIGHBOR, COUNT(*) AS [N#]

FROM NEIGHBORS GROUP BY NEIGHBOR

UNION

SELECT x, 0 AS NeighborsNo FROM COUNTRIES

WHERE x NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN

(SELECT DISTINCT NEIGHBOR FROM NEIGHBORS))

GROUP BY COUNTRY

HAVING SUM ([N#]) >= [k:]) AS S

ON COUNTRIES.X = S.COUNTRY

ORDER BY [NEIGHBORS#] DESC, COUNTRIES.COUNTRY;

4.3 Prerequisites in Oracle

Homework 3.3 is the pre-requisite for this lab.

4.1.1 Adding needed countries to the COUNTRIES table

COUNTRIES should have the following instance:

Page 171: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

171

Figure 4.13 COUNTRIES instance after solving homework 3.3a

4.1.2 Adding the NEIGHBORS table and populating its instance

Obviously, the RDM scheme and corresponding instance should be the

one presented in figure 4.14; figures 4.15 and 4.16 show its corresponding

Oracle implementation and instance.

Note that, trivially, Country Neighbor is a key, as it wouldn’t make

sense to store more than once any neighboring fact. Moreover, obviously,

from a db perspective, this mathematical relation is irreflexive (as it is

senseless to store the fact that a country is neighbor to itself) and antisym-

metric (as, once having stored that country c is neighbor to country n, the

dual fact that country n is neighbor to country c is computable, so it does

not make sense to store it too). Unfortunately, no RDBMS can enforce

these constraints (as they are non-relational, so not expressible in pure

SQL), but only through triggers or trigger-type methods (using either

extended SQL or high level programming languages – Java, C#, VBA, ...).

NEIGHBORS (x, Country Neighbor)

x Country Neighbor

autonumber(4) Im(COUNTRIES.x) Im(COUNTRIES.x)

NOT NULL NOT NULL NOT NULL

1 1 2

2 1 25

3 1 26

4 1 29

5 1 30

6 2 29

7 25 26

8 25 30

9 26 27

10 29 30

Figure 4.14 NEIGHBORS table (see homework 3.3b)

Page 172: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

172

Figure 4.15 Oracle implementation of the NEIGHBORS table

Figure 4.16 Oracle instance of the NEIGHBORS table

Page 173: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

173

4.4 Exercises in Oracle P4.1. a. Compute the number of neighbors of country ‘Moldavia’.

b. Parameterize this query and compute the numbers of neighbors

of country ‘Serbia’.

Solution:

a.

Firstly, please note that, due to NEIGHBORS antisymmetry, any country

may appear in this table instance either only in the Country column (e.g.

Romania), or only in the Neighbor one (e.g. Hungary), or in both of them

(e.g. Serbia, Bulgaria, Ukraine).

Trivially, the only table we need is NEIGHBORS, but, generally, for any

country, we have to add the number of its occurrences in both columns

(corresponding to this math relation canonical Cartesian projections).

Consequently, the SQL solution (save it as query P4_1) is the following:

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

(SELECT x FROM COUNTRIES WHERE Country = 'Moldavia')

OR NEIGHBOR =

(SELECT x FROM COUNTRIES WHERE Country = 'Moldavia');

Please note first that Oracle only evaluates once the common subquery;

the only faster solution is when we know the corresponding country code

(as no access to COUNTRIES is needed anymore):

SELECT COUNT(*) AS MoldaviaNeighborNo FROM NEIGHBORS

WHERE COUNTRY = 2 OR NEIGHBOR = 2;

Note that if irreflexivity is not enforced, then any row of type <x,x>

would vitiate this result (as compared to the mental corresponding com-

putation): for example, if the table instance would also contain line <11,

2, 2>, then (because of the OR), SQL computes 3, whereas there are 4 oc-

currences of 2 (two in Countries and 2 in Neighbors). Obviously, this is

just another reason for enforcing irreflexivity of NEIGHBORS too.

Page 174: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

174

b.

Parameterization of P4_1a is straightforward:

SELECT COUNT(*) AS CountryNeighborNo FROM NEIGHBORS

WHERE COUNTRY =

(SELECT x FROM COUNTRIES WHERE Country =

:Please_enter_country_name)

OR NEIGHBOR =

(SELECT x FROM COUNTRIES WHERE Country =

:Please_enter_country_name);

Figure 4.17 shows the window for passing “Serbia” as an actual parame-

ter value to it, whereas 4.18 presents its result for this value:

Figure 4.17 Passing an actual parameter value to query P4_1b

Page 175: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

175

Figure 4.18 Query P4_1b result for “Serbia”

As Oracle does not accept parameterized views, the best way to save

P_41b is as a PL/SQL stored function that takes a country name as its pa-

rameter and returns the corresponding number of neighbors. For creating

such a function, right-click on the Function node of the LAB_DB db and

then click on New Function…:

Page 176: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

176

Figure 4.19 Creating a PL/SQL function

In the Create PL/SQL Function window that pops up, enter function

Name, change the “<Return>” parameter type to Number, add a VAR-

CHAR2 IN(PUT) Country_Name parameter, and then click OK:

Page 177: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

177

Figure 4.20 Specifying a PL/SQL function signature

Click on the save icon to save this initially null returning function:

Figure 4.21 Saving a PL/SQL function definition

Page 178: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

178

Change return type from number to int, define a int cnn variable, save in-

to it the result of the SELECT COUNT(*), and return it (instead of null);

do not forget to replace both occurences of the SQL bind variable

:Please_enter_country_name with the Country_Name parameter,

and, finally, save your modifications:

Figure 4.22 Modifying a PL/SQL function body

The same result may be obtained by running the following DDL SQL

script into a LAB_DB SQL pane:

------------------------------------------------------

-- DDL for Function P4_1B

------------------------------------------------------

CREATE OR REPLACE FUNCTION "LAB_DB"."P4_1B"

(

country_name in varchar2

) return int as

cnn int;

Page 179: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

179

begin

SELECT COUNT(*) AS CountryNeighborNo INTO cnn

FROM NEIGHBORS

WHERE COUNTRY =

(SELECT x FROM COUNTRIES

WHERE Country = country_name)

OR NEIGHBOR =

(SELECT x FROM COUNTRIES

WHERE Country = country_name);

return cnn;

end p4_1b;

/

From now on, you can use this function both programmatically and in

SQL (and, if you wish, may move it into a PL/SQL package); for example,

if you type SELECT P4_1B(‘Serbia’) AS SerbiaNeighborsNo

FROM DUAL;14

in a LAB_DB SQL pane of the SQL Developer and run it,

you get the corresponding result:

Figure 4.23 Using a PL/SQL function

14

DUAL is an underlying table of Oracle’s metadata catalog having only one row.

Page 180: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

180

P4.2 Compute the set of countries without neighbors, in ascending order

of their names.

Solution:

Obviously, all needed data is stored in COUNTRIES and NEIGHBORS

and, again, due to NEIGHBORS math relation antisymmetry, we have to

look up for such countries in both Country and Neighbor columns.

The following SQL solution is the simplest and most elegant one (save it

as view P4-2):

SELECT COUNTRY FROM COUNTRIES WHERE X NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS

UNION

SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

ORDER BY COUNTRY;

Figure 4.24 shows its result; note that, just like in math, the SQL UNION

operator eliminates duplicates15

.

Figure 4.24 Query P4_2 result

15

Whenever you need such duplicates, use UNION ALL instead.

Page 181: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

181

Note that, as UNION is the slowest operator, replacing it with an

equivalent AND one yields a faster solution (0.005” instead of 0.007” on

my PC):

SELECT COUNTRY FROM COUNTRIES

WHERE x NOT IN (SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN (SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

ORDER BY COUNTRY;

An even faster, subqueryless equivalent solution (0.001” on my PC, save

it as P4_2Even_Faster) makes use of outer joins, the Is Null predicate,

and a queries hierarchy based on two dual preliminary views (P4_2C and

P4-2N):

P4-2C:

SELECT DISTINCT Country AS x FROM NEIGHBORS;

P4-2N:

SELECT DISTINCT Neighbor AS x FROM NEIGHBORS;

P4-2Fastest:

SELECT Country

FROM (COUNTRIES LEFT JOIN P4_2C

ON COUNTRIES.x = P4_2C.x) LEFT JOIN

P4_2N ON COUNTRIES.x = P4_2N.x

WHERE P4_2C.x Is Null AND P4_2N.x Is Null

ORDER BY COUNTRIES.Country;

Note that without DISTINCT, the result is the same, but it takes more

time to be computed: for example, P4-2C above computes the set {1, 2,

25, 26, 29}, whereas SELECT Country AS x FROM NEIGHBORS; is

computing the list {1, 1, 1, 1, 1, 2, 25, 25, 26, 29}.

The fastest possible (0.006” on my PC, save it as view P4_2Fastest), sim-

pler, one step query, which is not using either UNION, or subqueries, or

Page 182: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

182

queries hierarchies, but is using two instances of the table NEIGHBORS is

the following16

:

SELECT DISTINCT COUNTRIES.Country

FROM (COUNTRIES LEFT JOIN NEIGHBORS

ON COUNTRIES.x = NEIGHBORS.Country) LEFT JOIN

NEIGHBORS NEIGHBOR_COUNTRIES

ON COUNTRIES.x = NEIGHBOR_COUNTRIES.Neighbor

WHERE NEIGHBORS.Country Is Null AND

NEIGHBOR_COUNTRIES.Neighbor Is Null

ORDER BY COUNTRIES.Country;

P4.3. a. Compute the set of pairs <country name, neighbors number> for

countries having at least k neighbors (k natural), in descending order of

the number of their neighbors and then ascending on their names.

b. What are the corresponding results for k = 3 and k = 0?

Solution:

Obviously, the corresponding result for any k 0, manually computed (by

writing all countries from COUNTRIES, in alphabetic order, in the first

column of the table shown in figure 4.25, counting how many times each

one appears in NEIGHBOR.Country and writing the result in the Right-

Neighbors column, then same thing for the NEIGHBOR.Neighbor and

writing the result in the LeftNeighbors one, and then adding the two pre-

vious column values and writing them down in the TotalNeighbors co-

lumn), is the following (but only in the alphabetic order of Country, not in

the one asked by the exercise).

As even manually this problem is sub-dividable in smaller problems, let’s

program it in SQL in the same manner, step by step:

P4_3a0C (compute total number of neighbors per country for Country):

SELECT Country, Count(Neighbor) AS N#

FROM NEIGHBORS GROUP BY Country;

16

Note that Oracle does not accept the AS keyword: the renaming RA operator simply

does not have any name!

Page 183: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

183

Country RightNeighbors LeftNeighbors TotalNeighbors

Bulgaria 1 2 3

Greece 0 1 1

Hungary 0 3 3

Malta 0 0 0

Moldavia 1 1 2

Romania 5 0 5

Serbia 2 1 3

U.K. 0 0 0

U.S.A. 0 0 0

Ukraine 1 2 3

Figure 4.25 Results of manually computing total number of neighbors per

country (in the ascending order of country names)

P4_3a0N (compute total number of neighbors per country for Neighbor):

SELECT Neighbor, Count(Country) AS N#

FROM NEIGHBORS GROUP BY Neighbor;

P4_3a1B (compute total number of neighbors per country for countries

occurring both in Country and Neighbor):

SELECT Country,

P4_3a0c.N# + P4_3a0n.N# AS NeighborsInBothSides

FROM P4_3a0C INNER JOIN P4_3a0N

ON P4_3a0C.Country = P4_3a0N.Neighbor;

P4_3a1L (compute total number of neighbors per country for countries

occurring only in Country):

Page 184: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

184

SELECT Country, P4_3a0C.N#

FROM P4_3a0C LEFT JOIN P4_3a0N

ON P4_3a0C.Country = P4_3a0N.Neighbor

WHERE Neighbor Is Null;

P4_3a1R (compute total number of neighbors per country for countries

occurring only in Neighbor):

SELECT Neighbor, P4_3a0N.N#

FROM P4_3a0N LEFT JOIN P4_3a0C

ON P4_3a0N.Neighbor = P4_3a0C.Country

WHERE Country Is Null;

P4_3a2 (union results of P4-2, for countries with no neighbors, slightly

modified in order to select x instead of Country, with the ones of P4_

3a1B, P4_3a1L, and P4_3a1R):

SELECT x, 0 AS NeighborsNo FROM COUNTRIES

WHERE x NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN

(SELECT DISTINCT NEIGHBOR FROM NEIGHBORS)

UNION

SELECT * FROM P4_3a1B

UNION

SELECT * FROM P4_3a1L

UNION

SELECT * FROM P4_3a1R;

P4_3a (computing final result; add this procedure too in the LAB_DB_

PL_SQL package):

SELECT Country, NeighborsNo

FROM COUNTRIES INNER JOIN P4_3a2

ON COUNTRIES.x = P4_3a2.x

WHERE NeighborsNo >= :k

ORDER BY NeighborsNo DESC, COUNTRIES.Country;

Figures 4.26 and 4.27 show the corresponding results for k = 3 and k = 0:

Page 185: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

185

Figure 4.26 Result of P4-3a for k = 3

Page 186: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

186

Figure 4.27 Result of P4-3a for k = 0

The following equivalent solution is embedding all above steps into only

one SELECT statement (using subqueries instead of queries hierarchies):

Page 187: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

187

SELECT COUNTRIES.COUNTRY, NEIGHBORS#

FROM COUNTRIES INNER JOIN

(SELECT COUNTRY, SUM (N#) NEIGHBORS# FROM

(SELECT COUNTRY, COUNT(*) N#

FROM NEIGHBORS GROUP BY COUNTRY

UNION

SELECT NEIGHBOR, COUNT(*) N#

FROM NEIGHBORS GROUP BY NEIGHBOR

UNION

SELECT x, 0 AS NeighborsNo FROM COUNTRIES

WHERE x NOT IN

(SELECT DISTINCT COUNTRY FROM NEIGHBORS)

AND x NOT IN

(SELECT DISTINCT NEIGHBOR FROM NEIGHBORS))

GROUP BY COUNTRY

HAVING SUM (N#) >= :k) S

ON COUNTRIES.X = S.COUNTRY

ORDER BY NEIGHBORS# DESC, COUNTRIES.COUNTRY;

4.5 Best practice rules

4.6 Homework H4.1 Compute the set of countries that do not appear in column Country

of table NEIGHBORS, in ascending order of their names, without

using sub-queries. What is the corresponding result?

H4.2 Compute the set of pairs <country name, neighbors number>, in

descending order of neighbors number and then ascending on country

name, also including countries that do not have neighbors. What is the

corresponding result?

H4.3 Design, develop, and test a SQL script for adding the fact that

Ukraine is also neighbor to Russia, without knowing anything on the

two table instances except for the fact that Ukraine exists in

COUNTRIES, while Russia does not. What lines will be added

according to the current test instance?

H4.4 Design, develop, and test a SQL script for discarding all

neighborhood data for all countries whose names start with a letter

given as a parameter. What lines will disappear?

H4.5 Prove that left, right, and full outer joins are not only distinct

between them and as compared to the inner join, but also distinct from

the Cartesian product. Hints: give intelligent counter examples; note

Page 188: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

188

that some wrongly consider the full outer join to be always equal to

the Cartesian product.

Page 189: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

189

Chapter 5. 5th Lab: Self-Joins and Transitive Closures

5.1 Exercises in Access P5.1 Design, develop, and test a SQL script for changing to uppercase the

names of the countries having the property that they are neighbors to

at least one neighbor of one of their neighbors (i.e. country x will have

its name modified if and only if it is neighbor both to countries y and

z, where z is a neighbor of y). Give both subquery and subqueryless

equivalent solutions. What are the countries whose names will be mo-

dified?

Solution:

Inspecting table NEIGHBORS’s instance (see figures 4.2 and 4.4 above),

it is obvious that there are four such countries triangles: Romania, Molda-

via, Ukraine; Romania, Serbia, Bulgaria; Romania, Serbia, Hungary; and

Romania, Hungary, Ukraine. Consequently, all of these six involved

countries will have their names changed to ROMANIA, MOLDOVA,

SERBIA, BULGARIA, HUNGARY, and UKRAINE, respectively.

As a first step, it is a good decision to compute the symmetrical (actual)

math NEIGHBORS relation, in order not to care anymore on which one is

the order in which neighboring data pairs are stored (see figure 5.1 for its

result):

P5-1-a: SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS;

In a second step, we should compute the pairs <x, z>, such that there are

pairs <x, y> and <y, z> in P5-1-a (that is neighbors of neighbors), but, tri-

vially, where x z (as even the math NEIGHBORS relation is irreflexive);

to accomplish it, we obviously need two instances of P-5-1-a and a self-

join between them (see figure 5.2 for its result):

P-5-1-b: SELECT DISTINCT [P5-1-a].COUNTRY,

[P5-1-a.TransNeighbors].NEIGHBOR

FROM [P5-1-a] INNER JOIN

[P5-1-a] AS [P5-1-a-TransNeighbors]

ON [P5-1-a].NEIGHBOR = [P5-1-a-TransNeighbors].COUNTRY

WHERE [P5-1-a].COUNTRY <>

[P5-1-a-TransNeighbors].[Neighbor];

Page 190: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

190

Figure 5.1 Result of P-5-1-a

In a third step, we should filter out from P5-1-b all rows which do not

exist in P5-1-a (that is to enforce x neighbor to z also directly) and only

retain the set of corresponding countries (see figure 5.3 for its result):

P-5-1-c: SELECT DISTINCT [P5-1-a].COUNTRY

FROM [P5-1-a] INNER JOIN [P-5-1-b]

ON [P5-1-a].NEIGHBOR = [P-5-1-b].COUNTRY AND

[P5-1-a].COUNTRY = [P-5-1-b].NEIGHBOR;

Page 191: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

191

Figure 5.2 Result of P-5-1-b

Page 192: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

192

Figure 5.3 Result of P-5-1-c

Finally, we can update COUNTRIES.Country for all (and only) those

countries whose ids are computed by P-5-1-c:

P-5-1: UPDATE COUNTRIES SET Country = UCase([Country])

WHERE x IN (SELECT * FROM [P-5-1-c]);

By replacing the above queries hierarchy with corresponding subqueries,

the following equivalent statement is obtained:

P-5-1SubQ: UPDATE COUNTRIES SET COUNTRY = UCase(COUNTRY)

WHERE X IN

(SELECT DISTINCT A.COUNTRY FROM

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) A

INNER JOIN

(SELECT DISTINCT A.COUNTRY, B.NEIGHBOR FROM

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) A

INNER JOIN

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) B

ON A.NEIGHBOR = B.COUNTRY AND

A.COUNTRY <> B.NEIGHBOR) B

Page 193: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

193

ON A.NEIGHBOR = B.COUNTRY AND

A.COUNTRY = B.NEIGHBOR);

Figure 5.4 presents the instance of table COUNTRIES after running P-5-1

or P-5-1SQuery:

Figure 5.4 COUNTRIES’s instance after running P-5-1 or P-5-1SQuery

P5.2 Consider the table from figure 5.5.17

Design, develop, and test Ac-

cess (pure, ANSI 92) SQL queries for computing (both with and without

subqueries) the set of all pairs <z, y> such that y is a descendent of z,

where z and y are corresponding people names, in the ascending order of z

and y (that is the transitive closure of Father Mother). Give a solution

using a queries hierarchy and an equivalent one of only one statement.

What should the result be? Which solution is faster and why?

Solution:

Inspecting table PEOPLE’s instance, it is obvious that it stores the genea-

logical tree (of King Mihai I of Romania) shown in figure 5.6.

Using the Left-Root-Right traversal18

of this tree, the answer (trivially not

in the desired order) of any such query should be the set from figure 5.7.

17

Note that, obviously, as they model (genealogical) trees, both Father and Mother

should always be acyclic (cycle free)! 18

Note that this is an algebraic-type algorithm, dealing with elements of sets (one by

one).

Page 194: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

194

PEOPLE (x, Name)

x Name Father Mother

Autonumber ASCI(255) Im(x) Im(x)

NOT NULL NOT NULL

1 Queen Victoria of U.K.

2 Duke Alfred of Saxe-Coburg & Gotha 1

3 King Alexander II of Russia

4 Princess Maria Alexandrovna 3

5 Queen Maria of Romania 2 4

6 King Ferdinand I of Romania

7 King Carol II of Romania 6 5

8 King Frederic III of Prussia

9 Queen Sofia of Greece 8

10 King Constantin I of Greece

11 Queen Elena of Romania 10 9

12 King Mihai I of Romania 7 11

Figure 5.5 An instance fragment for the genealogical tree of the latest

Romania’s Kings and Queens

Queen Victoria of U.K. King Alexander II of Russia

Duke Alfred Princess Maria Alexandrovna King Frederic III of Prussia

Queen Maria King Ferdinand I Queen Sofia King Constantin I

King Carol II of Romania Queen Elena of Romania

King Mihai I of Romania

Figure 5.6 The genealogical tree stored in table PEOPLE

Page 195: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

195

Ancestor Descendent

Queen Victoria of U.K. Duke Alfred of Saxe-Coburg &

Gotha

Queen Victoria of U.K. Queen Maria of Romania

Duke Alfred of Saxe-Coburg &

Gotha

Queen Maria of Romania

Princess Maria Alexandrovna Queen Maria of Romania

King Alexander II of Russia Queen Maria of Romania

King Alexander II of Russia Princess Maria Alexandrovna

Queen Maria of Romania King Carol II of Romania

Queen Maria of Romania King Mihai I of Romania

King Carol II of Romania King Mihai I of Romania

Queen Elena of Romania King Mihai I of Romania

Queen Sofia of Greece Queen Elena of Romania

King Frederic III of Prussia Queen Sofia of Greece

King Frederic III of Prussia Queen Elena of Romania

King Constantin I of Greece Queen Elena of Romania

King Constantin I of Greece King Mihai I of Romania

Figure 5.7 The (transitive closure) set that should be the answer of P5-2

As you were taught in the previous lecture, SQL (just like the first order

logic on which it is based) is meant to exploit a dual, parallel-type ap-

Page 196: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

196

proach19

, of computing, for example, all descendants of all direct ances-

tors (mothers and fathers) in only one step; consequently, the best first ap-

proach to any problem of this type is to start by computing pairs of <pa-

rents, children> (level one), then to continue with pairs of <grandparents,

grandchildren> (level two), <grand-grandparents, grand-grandchildren>

(level three), etc., and, finally, to merge them in order to compute the re-

quested result. Generally, at least in logic and dbs, DO NOT THINK IN

TERMS OF ELEMENTS OF SETS, BUT RATHER IN TERMS OF

SETS OF ELEMENTS!

Obviously, the following statement computes (see figure 5.8 for the cor-

responding result) the first level of this hierarchy (genealogical tree):

19

Dually, logic type approaches deal with sets of elements (processing all their elements

in parallel, in only one step).

Page 197: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

197

P5-2-L1:

SELECT Father AS Ancestor, x AS Descendant FROM PEOPLE

WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant FROM PEOPLE

WHERE Mother Is Not Null;

Figure 5.8 The set of pairs <parents, children>

Note that we are not interested in pairs of the type <null, y>!

Then, the following statement computes (see figure 5.9 for the corres-

ponding result) the second level of this hierarchy (genealogical tree):

Page 198: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

198

P5-2-L2:

SELECT [P5-2-L1].Ancestor, [P5-2-L1_1].Descendant

FROM [P5-2-L1] INNER JOIN [P5-2-L1] AS [P5-2-L1_1]

ON [P5-2-L1].Descendant = [P5-2-L1_1].Ancestor;

Figure 5.9 The set of pairs <grandparents, grandchildren>

Note that, indeed, by using two instances of query P5-2-L1, we are easily

obtaining the fathers/mothers of fathers/mothers – that is the grandparents

of the (grand)children, with a self-join.

Next, the following statement computes (see figure 5.10 for the corres-

ponding result) the third level of this hierarchy (genealogical tree):

P5-2-L3:

SELECT [P5-2-L2].Ancestor, [P5-2-L1].Descendant

FROM [P5-2-L2] INNER JOIN [P5-2-L1]

ON [P5-2-L2].Descendant = [P5-2-L1].Ancestor;

Page 199: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

199

Figure 5.10 The set of pairs <grand-grandparents, grand-grandchildren>

Next, the following statement computes (see figure 5.11 for the corres-

ponding result) the fourth level of this hierarchy (genealogical tree):

P5-2-L4:

SELECT [P5-2-L3].Ancestor, [P5-2-L1].Descendant

FROM [P5-2-L3] INNER JOIN [P5-2-L1]

ON [P5-2-L3].Descendant = [P5-2-L1].Ancestor;

Figure 5.11 The set of pairs <grand-grand-grandparents, grand-grand-

grandchildren>

Page 200: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

200

Note that you could compute level four alternatively with two instances of

P5-2-L2 instead20

.

Next, the following statement computes (see figure 5.12 for the corres-

ponding result) the fifth level of this hierarchy (genealogical tree):

P5-2-L5:

SELECT [P5-2-L4].Ancestor, [P5-2-L1].Descendant

FROM [P5-2-L4] INNER JOIN [P5-2-L1]

ON [P5-2-L4].Descendant = [P5-2-L1].Ancestor;

Figure 5.12 The set of pairs <grand-grand-grand-grandparents, grand-

grand-grand-grandchildren>

Obviously, as the result of this query is the empty set, this means that

there are no such pairs, so there is no use to continue, as there will not be

any other pairs of higher level either. Note that, indeed, the longest paths

in the tree from figure 5.6 above (those from Queen Victoria of U.K. and

King Alexander II of Russia to King Mihai I of Romania) have length 4,

so this tree height is four.

Consequently, in order to get the almost final result we only need to union

all queries computing the first four levels (see figure 5.13 for the corres-

ponding result):

P5-2-TransClosure:

SELECT * FROM [P5-2-L1]

UNION

20

As, indeed, 3 + 1 = 4 = 2 + 2!

Page 201: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

201

SELECT * FROM [P5-2-L2]

UNION

SELECT * FROM [P5-2-L3]

UNION

SELECT * FROM [P5-2-L4];

Finally, by joining this result with two instances of PEOPLE (one for an-

cestors and one for descendants) and sorting them in the desired ordered,

we get the requested result (see figure 5.14):

P5-2:

SELECT PEOPLE.Name AS Ancestors,

PEOPLE_1.Name AS Descendants

FROM (PEOPLE INNER JOIN [P5-2-TransClosure]

ON PEOPLE.x = [P5-2-TransClosure].Ancestor)

INNER JOIN PEOPLE AS PEOPLE_1

ON PEOPLE_1.x = [P5-2-TransClosure].Descendant

ORDER BY PEOPLE.Name, PEOPLE_1.Name;

Please note that, not only for SQL programmer beginners, there is a huge

temptation in such cases to offer, at a first glance, just another definition

of the empty set: if you do not use two instances of PEOPLE, but only

one, the following query will always compute the empty set, regardless of

the (valid) instance of PEOPLE (as, from the transitivity of equality, from

PEOPLE.x = [P5-2-TransClosure].Ancestor AND PEOPLE.x =

[P5-2-TransClosure].Descendant, it results that [P5-2-Trans-

Closure].Ancestor = [P5-2-TransClosure].Descendant,

which is never happening for valid instances of PEOPLE, as it is acyclic

both for Father and Mother, so it is irreflexive too – that is nobody can be

his/her own ancestor/descendant!):

SELECT Name AS Ancestors,

Name AS Descendants

FROM PEOPLE INNER JOIN [P5-2-TransClosure]

ON PEOPLE.x = [P5-2-TransClosure].Ancestor AND

PEOPLE.x = [P5-2-TransClosure].Descendant

ORDER BY Name, Name;

Page 202: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

202

Figure 5.13 The transitive closure of Father Mother from figure 5.5

Page 203: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

203

Figure 5.14 The result of the solution to exercise P5-2

Page 204: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

204

Obviously, the above queries hierarchy can be equivalently replaced by

the following single SQL statement, which makes (heavy) use of

subqueries:

P5-2-SQuery:

SELECT PEOPLE.Name AS Ancestors,

PEOPLE_1.Name AS Descendants

FROM (PEOPLE INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null

UNION

SELECT [P5-2-L1].Ancestor, [P5-2-L1_1].Descendant

FROM

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1_1]

ON [P5-2-L1].Descendant = [P5-2-L1_1].Ancestor

UNION

SELECT [P5-2-L2].Ancestor, [P5-2-L1].Descendant

FROM

(SELECT [P5-2-L1].Ancestor,

[P5-2-L1_1].Descendant

FROM

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

Page 205: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

205

AS [P5-2-L1] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1_1]

ON [P5-2-L1].Descendant = [P5-2-L1_1].Ancestor)

AS [P5-2-L2] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1]

ON [P5-2-L2].Descendant = [P5-2-L1].Ancestor

UNION

SELECT [P5-2-L3].Ancestor, [P5-2-L1].Descendant

FROM

(SELECT [P5-2-L2].Ancestor, [P5-2-L1].Descendant

FROM

(SELECT [P5-2-L1].Ancestor,

[P5-2-L1_1].Descendant

FROM

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1_1]

ON [P5-2-L1].Descendant = [P5-2-L1_1].Ancestor)

AS [P5-2-L2] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

Page 206: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

206

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1]

ON [P5-2-L2].Descendant = [P5-2-L1].Ancestor)

AS [P5-2-L3] INNER JOIN

(SELECT Father AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant

FROM PEOPLE WHERE Mother Is Not Null)

AS [P5-2-L1]

ON [P5-2-L3].Descendant = [P5-2-L1].Ancestor)

AS [P5-2-TransClosure]

ON PEOPLE.x = [P5-2-TransClosure].Ancestor)

INNER JOIN PEOPLE AS PEOPLE_1

ON PEOPLE_1.x = [P5-2-TransClosure].Descendant

ORDER BY PEOPLE.Name, PEOPLE_1.Name;

Generally, P5-2 is faster than P5-2SQuery (for large enough instances of

PEOPLE), as subqueries are evaluated slower than queries hierarchies.

5.2 Exercises in Oracle P5.1 Design, develop, and test a SQL script for changing to uppercase the

names of the countries having the property that they are neighbors to

at least one neighbor of one of their neighbors (i.e. country x will have

its name modified if and only if it is neighbor both to countries y and

z, where z is a neighbor of y). Give both subquery and subqueryless

equivalent solutions. What are the countries whose names will be mo-

dified?

Solution:

Inspecting table NEIGHBORS’s instance (see figures 4.14 and 4.16

above), it is obvious that there are four such countries triangles: Romania,

Moldavia, Ukraine; Romania, Serbia, Bulgaria; Romania, Serbia, Hun-

gary; and Romania, Hungary, Ukraine. Consequently, all of these six in-

volved countries will have their names changed to ROMANIA, MOLDA-

VIA, SERBIA, BULGARIA, HUNGARY, and UKRAINE, respectively.

Page 207: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

207

As a first step, it is a good decision to compute the symmetrical (actual)

math NEIGHBORS relation, in order not to care anymore on which one is

the order in which neighboring data pairs are stored (see figure 5.15 for

its result):

P51_a: SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS;

Figure 5.15 Result of P5_1a

Page 208: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

208

In a second step, we should compute the pairs <x, z>, such that there are

pairs <x, y> and <y, z> in P5_1a (that is neighbors of neighbors), but, tri-

vially, where x z (as even the math NEIGHBORS relation is irreflexive);

to accomplish it, we obviously need two instances of P5-1a and a self-

join between them (see figure 5.16 for its result):

P5_1b: SELECT DISTINCT P5_1a.COUNTRY,

P5_1a_TransNeighbors.NEIGHBOR

FROM P5_1a INNER JOIN

P5_1a P5_1a_TransNeighbors

ON P5_1a.NEIGHBOR = P5_1a_TransNeighbors.COUNTRY

WHERE P5_1a.COUNTRY <>

P5_1a_TransNeighbors.Neighbor;

In a third step, we should filter out from P5_1b all rows which do not

exist in P5_1a (that is to enforce x neighbor to z also directly) and only

retain the set of corresponding countries (see figure 5.17 for its result):

P5_1c: SELECT DISTINCT P5_1a.COUNTRY

FROM P5_1a INNER JOIN P5_1b

ON P5_1a.NEIGHBOR = P5_1b.COUNTRY AND

P5_1a.COUNTRY = P5_1b.NEIGHBOR;

Finally, we can update COUNTRIES.Country for all (and only) those

countries whose ids are computed by P5_1c:

P5_1: UPDATE COUNTRIES SET Country = Upper(Country)

WHERE x IN (SELECT * FROM P5_1c);

By replacing the above queries hierarchy with corresponding subqueries,

the following equivalent statement is obtained:

P5_1SubQ: UPDATE COUNTRIES SET COUNTRY = Upper(COUNTRY)

WHERE X IN

(SELECT DISTINCT A.COUNTRY FROM

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) A

INNER JOIN

(SELECT DISTINCT A.COUNTRY, B.NEIGHBOR FROM

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) A

INNER JOIN

Page 209: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

209

Figure 5.16 Result of P5_1b

Page 210: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

210

Figure 5.17 Result of P5_1c

(SELECT COUNTRY, NEIGHBOR FROM NEIGHBORS

UNION

SELECT NEIGHBOR, COUNTRY FROM NEIGHBORS) B

ON A.NEIGHBOR = B.COUNTRY AND

A.COUNTRY <> B.NEIGHBOR) B

ON A.NEIGHBOR = B.COUNTRY AND

A.COUNTRY = B.NEIGHBOR);

Figure 5.18 presents the instance of table COUNTRIES after running

P5_1 or P5_1SQuery (save them as procedures, because Oracle views

cannot contain INSERT, UPDATE, or DELETE):

Page 211: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

211

Figure 5.18 COUNTRIES’s instance after running P5_1 or P5_1SQuery

P5.2 Consider the table from figure 5.19.21

Design, develop, and test pure,

ANSI 92 Oracle SQL queries for computing (both with and without sub-

queries) the set of all pairs <z, y> such that y is a descendent of z, where z

and y are corresponding people names, in the ascending order of z and y

(that is the transitive closure of Father Mother). Give a solution using a

queries hierarchy and an equivalent one of only one statement. What

should the result be? Which solution is faster and why?

Solution:

Inspecting table PEOPLE’s instance, it is obvious that it stores the

genealogical tree (of King Mihai I of Romania) shown in figure 5.20.

21

Note that, obviously, as they model (genealogical) trees, both Father and Mother

should always be acyclic (cycle free)!

Page 212: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

212

PEOPLE (x, Name)

x Name Father Mother

Autonumber ASCI(255) Im(x) Im(x)

NOT NULL NOT NULL

1 Queen Victoria of U.K.

2 Duke Alfred of Saxe-Coburg & Gotha 1

3 King Alexander II of Russia

4 Princess Maria Alexandrovna 3

5 Queen Maria of Romania 2 4

6 King Ferdinand I of Romania

7 King Carol II of Romania 6 5

8 King Frederic III of Prussia

9 Queen Sofia of Greece 8

10 King Constantin I of Greece

11 Queen Elena of Romania 10 9

12 King Mihai I of Romania 7 11

Figure 5.19 An instance fragment for the genealogical tree of the latest

Romania’s Kings and Queens

Queen Victoria of U.K. King Alexander II of Russia

Duke Alfred Princess Maria Alexandrovna King Frederic III of Prussia

Queen Maria King Ferdinand I Queen Sofia King Constantin I

King Carol II of Romania Queen Elena of Romania

King Mihai I of Romania

Figure 5.20 The genealogical tree stored in table PEOPLE

Page 213: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

213

Using the Left-Root-Right traversal22

of this tree, the answer (trivially not

in the desired order) of any such query should be the following set:

Ancestor Descendent

Queen Victoria of U.K. Duke Alfred of Saxe-Coburg &

Gotha

Queen Victoria of U.K. Queen Maria of Romania

Duke Alfred of Saxe-Coburg &

Gotha

Queen Maria of Romania

Princess Maria Alexandrovna Queen Maria of Romania

King Alexander II of Russia Queen Maria of Romania

King Alexander II of Russia Princess Maria Alexandrovna

Queen Maria of Romania King Carol II of Romania

Queen Maria of Romania King Mihai I of Romania

King Carol II of Romania King Mihai I of Romania

Queen Elena of Romania King Mihai I of Romania

Queen Sofia of Greece Queen Elena of Romania

King Frederic III of Prussia Queen Sofia of Greece

King Frederic III of Prussia Queen Elena of Romania

King Constantin I of Greece Queen Elena of Romania

King Constantin I of Greece King Mihai I of Romania

Figure 5.21 The (transitive closure) set that should be the answer of P5.2

22

Note that this is an algebraic-type algorithm, dealing with elements of sets (one by

one).

Page 214: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

214

As you were taught in the previous lecture, SQL (just like the first order

logic on which it is based) is meant to exploit a dual, parallel-type ap-

proach23

, of computing, for example, all descendants of all direct ances-

tors (mothers and fathers) in only one step; consequently, the best first ap-

proach to any problem of this type is to start by computing pairs of <pa-

rents, children> (level one), then to continue with pairs of <grandparents,

grandchildren> (level two), <grand-grandparents, grand-grandchildren>

(level three), etc., and, finally, to merge them in order to compute the re-

quested result. Generally, at least in logic and dbs, DO NOT THINK IN

TERMS OF ELEMENTS OF SETS, BUT RATHER IN TERMS OF

SETS OF ELEMENTS!

Obviously, the following statement computes (see figure 5.22 for the cor-

responding result) the first level of this hierarchy (genealogical tree):

P5_2_L1:

SELECT Father AS Ancestor, x AS Descendant FROM PEOPLE

WHERE Father Is Not Null

UNION

SELECT Mother AS Ancestor, x AS Descendant FROM PEOPLE

WHERE Mother Is Not Null;

23

Dually, logic type approaches deal with sets of elements (processing all their elements

in parallel, in only one step).

Page 215: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

215

Figure 5.22 The set of pairs <parents, children>

Note that we are not interested in pairs of the type <null, y>!

Then, the following statement computes (see figure 5.23 for the corres-

ponding result) the second level of this hierarchy (genealogical tree):

P5_2_L2:

SELECT P5_2_L1.Ancestor, P5_2_L1_1.Descendant

FROM P5_2_L1 INNER JOIN P5_2_L1 P5_2_L1_1

ON P5_2_L1.Descendant = P5_2_L1_1.Ancestor;

Page 216: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

216

Figure 5.23 The set of pairs <grandparents, grandchildren>

Note that, indeed, by using two instances of query P5_2_L1, we are easily

obtaining the fathers/mothers of fathers/mothers – that is the grandparents

of the (grand)children, with a self-join.

Next, the following statement computes (see figure 5.24 for the corres-

ponding result) the third level of this hierarchy (genealogical tree):

P5_2_L3:

SELECT P5_2_L2.Ancestor, P5_2_L1.Descendant

FROM P5_2_L2 INNER JOIN P5_2_L1

ON P5_2_L2.Descendant = P5_2_L1.Ancestor;

Page 217: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

217

Figure 5.24 The set of pairs <grand-grandparents, grand-grandchildren>

Next, the following statement computes (see figure 5.25 for the corres-

ponding result) the fourth level of this hierarchy (genealogical tree):

Page 218: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

218

P5_2_L4:

SELECT P5_2_L3.Ancestor, P5_2_L1.Descendant

FROM P5_2_L3 INNER JOIN P5_2_L1

ON P5_2_L3.Descendant = P5_2_L1.Ancestor;

Figure 5.25 The set of pairs <grand-grand-grandparents, grand-grand-

grandchildren>

Note that you could compute level four alternatively with two instances of

P5_2_L2 instead24

.

Next, the following statement computes (see figure 5.26 for the corres-

ponding result) the fifth level of this hierarchy (genealogical tree):

P5_2_L5:

SELECT P5_2_L4.Ancestor, P5_2_L1.Descendant

FROM P5_2_L4 INNER JOIN P5_2_L1

24

As, indeed, 3 + 1 = 4 = 2 + 2!

Page 219: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

219

ON P5_2_L4.Descendant = P5_2_L1.Ancestor;

Figure 5.26 The set of pairs <grand-grand-grand-grandparents, grand-

grand-grand-grandchildren>

Obviously, as the result of this query is the empty set, this means that

there are no such pairs, so there is no use to continue, as there will not be

any other pairs of higher level either. Note that, indeed, the longest paths

in the tree from figure 5.20 above (those from Queen Victoria of U.K. and

King Alexander II of Russia to King Mihai I of Romania) have length 4,

so this tree height is four.

Consequently, in order to get the almost final result we only need to union

all queries computing the first four levels (see figure 5.27 for the corres-

ponding result):

P5_2_TransClosure:

SELECT * FROM P5_2_L1

UNION

SELECT * FROM P5_2_L2

UNION

SELECT * FROM P5_2_L3

UNION

Page 220: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

220

SELECT * FROM P5_2_L4;

Figure 5.27 The transitive closure of Father Mother from figure 5.19

Page 221: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

221

Finally, by joining this result with two instances of PEOPLE (one for an-

cestors and one for descendants) and sorting them in the desired ordered,

we get the requested result (see figure 5.28):

P5_2:

SELECT PEOPLE.Name AS Ancestors,

PEOPLE_1.Name AS Descendants

FROM (PEOPLE INNER JOIN P5_2_TransClosure

ON PEOPLE.x = P5_2_TransClosure.Ancestor) INNER

JOIN PEOPLE PEOPLE_1

ON PEOPLE_1.x = P5_2_TransClosure.Descendant

ORDER BY PEOPLE.Name, PEOPLE_1.Name;

Please note that, not only for SQL programmer beginners, there is a huge

temptation in such cases to offer, at a first glance, just another definition

of the empty set: if you do not use two instances of PEOPLE, but only

one, the following query will always compute the empty set, regardless of

the (valid) instance of PEOPLE (as, from the transitivity of equality, from

PEOPLE.x = P5_2_TransClosure.Ancestor AND PEOPLE.x =

P5_2_TransClosure.Descendant, it results that P5_2_TransClo-

sure.Ancestor = P5_2_TransClosure.Descendant, which is

never happening for valid instances of PEOPLE, as it is acyclic both for

Father and Mother, so it is irreflexive too – that is nobody can be his/her

own ancestor/descendant!):

SELECT Name Ancestors,

Name Descendants

FROM PEOPLE INNER JOIN P5_2_TransClosure

ON PEOPLE.x = P5_2_TransClosure.Ancestor AND

PEOPLE.x = P5_2_TransClosure.Descendant

ORDER BY Name, Name;

Page 222: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

222

Figure 5.28 The result of the solution to exercise P5.2

Obviously, the above queries hierarchy can be equivalently replaced by

the following single SQL statement, which makes (heavy) use of

subqueries:

Page 223: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

223

P5_2_SQuery:

SELECT PEOPLE.Name Ancestors,

PEOPLE_1.Name Descendants

FROM (PEOPLE INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null

UNION

SELECT P5_2_L1.Ancestor, P5_2_L1_1.Descendant

FROM

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null) P5_2_L1

INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null)

P5_2_L1_1

ON P5_2_L1.Descendant = P5_2_L1_1.Ancestor

UNION

SELECT P5_2_L2.Ancestor, P5_2_L1.Descendant

FROM

(SELECT P5_2_L1.Ancestor,

P5_2_L1_1.Descendant

FROM

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null)

P5_2_L1 INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

Page 224: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

224

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null) P5_2_L1_1

ON P5_2_L1.Descendant = P5_2_L1_1.Ancestor)

P5_2_L2 INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null) P5_2_L1

ON P5_2_L2.Descendant = P5_2_L1.Ancestor

UNION

SELECT P5_2_L3.Ancestor, P5_2_L1.Descendant

FROM

(SELECT P5_2_L2.Ancestor, P5_2_L1.Descendant

FROM

(SELECT P5_2_L1.Ancestor,

P5_2_L1_1.Descendant

FROM

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null)

P5_2_L1 INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null)

P5_2_L1_1

ON P5_2_L1.Descendant = P5_2_L1_1.Ancestor)

P5_2_L2 INNER JOIN

(SELECT Father Ancestor, x Descendant

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null) P5_2_L1

ON P5_2_L2.Descendant = P5_2_L1.Ancestor)

P5_2_L3 INNER JOIN

(SELECT Father Ancestor, x Descendant

Page 225: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

225

FROM PEOPLE WHERE Father Is Not Null

UNION

SELECT Mother, x

FROM PEOPLE WHERE Mother Is Not Null) P5_2_L1

ON P5_2_L3.Descendant = P5_2_L1.Ancestor)

P5_2_TransClosure

ON PEOPLE.x = P5_2_TransClosure.Ancestor)

INNER JOIN PEOPLE PEOPLE_1

ON PEOPLE_1.x = P5_2_TransClosure.Descendant

ORDER BY PEOPLE.Name, PEOPLE_1.Name;

Generally, P5_2 is faster than P5_2SQuery (for large enough instances of

PEOPLE), as subqueries are evaluated slower than queries hierarchies:

for example, on my PC, the first one takes 0.06”, while the second 0.085”.

5.3 Best practice rules

5.4 Homework H5.0 Create table PEOPLE in your lab db and fill it with figure 5.2

instance data.

H5.1 Compute in SQL, for the instance of table PEOPLE (see figure 5.2

above) the transitive closure of Father, union it with that of Mother, and

note that the result is included in the result of P5-2, but the reverse is not

true. Generalize your findings and use them to prove that, for any two

auto-functions f and g defined on and taking values from a same set, f+

g+ (f

g)

+, but the converse is not true.

H5.2 Compute in SQL all files on your PC under the Windows folder for

the first four tree depth levels.

H5-3 Prove by induction that, in order to computer in SQL all files of le-

vel n, n natural, belonging to a subtree of files arbitrarily chosen, you ne-

ed n-1 unions and, for each member i (1 i n) of these unions, you need

either i-1 subqueries or i instances of table FILES and i-1 joins between

them.

H5-4 Prove that pure SQL cannot compute the above query when n is a

parameter. Hint: There is no such thing as “…”between either joins or

Page 226: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

226

unions; you cannot write, for example, INNER JOIN ... INNER

JOIN and/or UNION .... UNION.

H5-5 As a corollary, prove that pure SQL cannot compute transitive clo-

sures either.

(Recall from sets algebra that, given any set and any binary, transitive

operator on it, the transitive closure of that set is the smallest superset

that includes all transitively computed elements of the set. For example,

given the following FILES instance:

FILES.x FILES.Folder

3 1

4 3

5 4

The corresponding Folder+ transitive closure is {<3,1>, <4,3>, <5,4>,

<4,1>, <5,3>, <5,1>}.)

H5-6 Write a program in any high level programming language of your

choice, which takes as input a table name, a column name which is an

autoforeign key in that table, an arbitrary value of that column, and an

arbitrary value of tree depth and outputs the corresponding SQL

statements for computing the transitive subclosure restricted to level n of

that table instance for that column name and initial value. Do it with

either subqueries, or self-joins, or query hierarchies, at your choice.

H5-7 Generalize 5-6 above by adding a fifth parameter, e.g. of type inte-

ger, but only accepting, e.g., -1 for subqueries, 0 for query hierarchies,

and 1 for self joins. Run this program for table “FILES”, column “Fol-

der”, and your PC's C drive folders, by choosing a subtree having at least

10 levels.

H5-8 Write a high level programming language method for computing all

the first four level of depth in table FILES without SQL.

H5-9 Write a program in a high level programming language embedding

SQL (e.g. Java, C#, VBA, PHP, etc.) that implements the following

algorithm for computing the transitive closure, where FolderValue is a

parameter, and run it for your PC O.S. data:

Page 227: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

227

TransClosureAlgorithm:

INT i, card, oldcard;

Exec "DELETE FROM Tmp"; //in VBA: DoCmd.RunSQL= Exec

i = 0;

oldcard = 0;

Exec "INSERT INTO Tmp(File, Folder, Level) SELECT

x, Folder, 0 FROM FILES WHERE Folder=" & FolderValue;

card = DCount("*","Tmp"); // in Access, DCount returns the

// cardinal of the corresponding set (here, table Tmp instance)

while oldcard card

oldcard = card;

Exec "INSERT INTO Tmp(File, Folder, Level)

SELECT x, Folder, " & i+1 & " FROM FILES INNER JOIN

Tmp ON FILES.Folder=Tmp.File WHERE Level=" & i & "

AND Folder =" & FolderValue;

i = i + 1;

card = DCount("*", "Tmp");

endwhile;

NOTE: DO NOT FORGET THAT NEXT WEEK YOU SHOULD

PASS YOUR FIRST (SQL) DB TEST (WHICH IS WORTH 10%,

THAT IS 1p FROM YOUR FINAL MARK); GOOD LUCK!

Page 228: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

228

Chapter 6. 6th Lab: First test (SQL) 90 minutes, 27 points, open book, individual, no electronic devices

6.1 Number 1 a. (2p.) Design and develop a SQL script for adding to the lab db the city

“Sinaia” from the Romania’s state “Prahova”, knowing that Romania’s id

is 1 and that state “Prahova” does not exist either.

b. (3.5p.) Design and develop a SQL script for adding to the lab db the

function BirthPlace : PEOPLE CITIES, having the following graph

and knowing that there is only one city named “Sinaia”:

x City BirthPlace(x)

7 Sinaia

12 Sinaia

c. (Only in Access)(4.5p.) Describe needed steps for adding a lookup

combo-box to BirthPlace, without using the Lookup Wizard.

c. (Only in Oracle) (3.5p.) Design and develop a SQL statement for

creating a view CITIES_STATES_CONTRIES, which computes the

following result:

x City, State, Country

7 Bucharest, Bucharest, ROMANIA

23 Chișinău, Chișinău, MOLDAVIA

41 Constanța, Constanța, ROMANIA

43 Iași, Iași, ROMANIA

25 London, Greater London, U.K.

44 Memphis, Tennessee, U.S.A.

42 New York, New York, U.S.A.

45 Sibiu, Sibiu, ROMANIA

24 Washington, District of Columbia, U.S.A.

Page 229: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

229

d. (17p Access/18p Oracle) Compute, without using subqueries, the set of

triples <Name, ChildrenNo, GrandChildrenNo>, in the descending order

of ChildrenNo and GrandChildrenNo, and then ascending on Name, for

all grandfathers that have at least k children, each of which having at least

n children (k and n being natural parameters). Which is the result for the

PEOPLE lab db instance when k = n = 1 and k = n = 2?

Hints offered as answers to students’ questions during tests:

a. No, there is not only one form of the INSERT SQL statement!

b. Yes, the Key Propagation Principle should be applied in all such

cases!

c. The corresponding SELECT statement is worth 3.5p and the most

important combo-boxes’ property 0.5p.

d. No, there are no ChildrenNo and GrandChildrenNo fields in the

PEOPLE table, but they are computable!

6.1.1 Access solution

a.

INSERT INTO STATES (State, Country)

VALUES (“Prahova”, 1); (0.5p)

INSERT INTO CITIES (City, State)

SELECT “Sinaia”, x FROM STATES

WHERE State = “Prahova” AND Country = 1; (1.5p)

b.

ALTER TABLE PEOPLE ADD COLUMN BirthPlace LONG;

(0.5p)

ALTER TABLE PEOPLE ADD CONSTRAINT fkBPlace

FOREIGN KEY (BirthPlace) REFERENCES CITIES; (1.25p)

UPDATE PEOPLE SET BirthPlace = DLookup(“x”,

“CITIES”, “City=’Sinaia’) WHERE x IN (7, 12);

(1.75p)

c.

- open PEOPLE in Design mode; (0.05p)

Page 230: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

230

- on the BirthPlace line, in the Lookup tab, switch the Display Control

property from Text to Combo box; (0.05p)

- in the Row Source property, type:

SELECT CITIES.x, [City] & ", " & [STATES].[State]

& ", " & [COUNTRIES].[Country]

AS [City, State, Country]

FROM COUNTRIES INNER JOIN (STATES INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY [City] & ", " & [STATES].[State] & ", "

& [COUNTRIES].[Country]; (3.5p)

- set the Column Count property to 2; (0.15p)

- set the Column Heads property to Yes; (0.05p)

- set the Column Width property to 0”;4”; (0.05p)

- set the List Rows property to 32; (0.05p)

- set the List Width property to 4”; (0.05p)

- set the Limit to List property to Yes; (0.5p)

- save and close the table scheme window. (0.05p)

d.

- step 1: fathers with at least k children

PeopleHavingAtLeastkChildren: (5p)

SELECT PEOPLE.x, Count(CHILDREN.x) AS ChildrenNo

FROM PEOPLE AS CHILDREN INNER JOIN PEOPLE

ON CHILDREN.Father = PEOPLE.x

GROUP BY PEOPLE.x

HAVING Count(CHILDREN.x) >=

[Enter desired minimum number of children:];

Page 231: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

231

- step 2: grandfathers with at least k children, each of which has n children

PeopleHavingAtLeastkChildrenAndnGrandChildren: (7p)

SELECT PeopleHavingAtLeastkChildren.x,

PeopleHavingAtLeastkChildren.ChildrenNo,

Count(GrandChildren.x) AS GrandChildrenNo

FROM PEOPLE AS GrandChildren INNER JOIN (PEOPLE AS CHILDREN

INNER JOIN PeopleHavingAtLeastkChildren

ON CHILDREN.Father = PeopleHavingAtLeastkChildren.x)

ON GrandChildren.Father = CHILDREN.x

GROUP BY PeopleHavingAtLeastkChildren.x,

PeopleHavingAtLeastkChildren.ChildrenNo

HAVING Count(GrandChildren.x) >=

[Enter desired minimum number of grand children:];

- step 3: getting names and sorting

Test-1d: (3p)

SELECT PEOPLE.Name,

PeopleHavingAtLeastkChildrenAndnGrandChildren.ChildrenNo,

PeopleHavingAtLeastkChildrenAndnGrandChildren.GrandChildrenNo

FROM PEOPLE INNER JOIN

PeopleHavingAtLeastkChildrenAndnGrandChildren

ON PEOPLE.x = PeopleHavingAtLeastkChildrenAndnGrandChildren.x

ORDER BY

PeopleHavingAtLeastkChildrenAndnGrandChildren.ChildrenNo DESC,

PeopleHavingAtLeastkChildrenAndnGrandChildren.GrandChildrenNo

DESC, PEOPLE.Name;

Figure 6.1 Result of query Test-1d for k = n = 1 (1p)

Page 232: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

232

Figure 6.2 Result (empty set) of query Test-1d for k = n = 2 (1p)

6.1.2 Oracle solution

a.

INSERT INTO STATES (State, Country)

VALUES ('Prahova', 1); (0.5p)

INSERT INTO CITIES (City, State)

SELECT 'Sinaia', x FROM STATES

WHERE State = 'Prahova' AND Country = 1; (1.5p)

b.

ALTER TABLE PEOPLE ADD BirthPlace NUMBER(6,0);

(0.5p)

ALTER TABLE PEOPLE ADD CONSTRAINT fkBPlace

FOREIGN KEY (BirthPlace) REFERENCES CITIES;

(1.25p)

UPDATE PEOPLE SET BirthPlace = (SELECT x FROM

CITIES WHERE City='Sinaia') WHERE x IN (7, 12);

(1.75p)

c.

-------------------------------------------------

-- DDL for View CITIES_STATES_CONTRIES

-------------------------------------------------

CREATE OR REPLACE FORCE VIEW

"LAB_DB"."CITIES_STATES_CONTRIES"

("X", "City, State, Country") AS

SELECT CITIES.x, City || ', ' || STATES.State ||

Page 233: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

233

', ' || COUNTRIES.Country "City, State, Country"

FROM COUNTRIES INNER JOIN (STATES INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY City || ', ' || STATES.State || ', ' ||

COUNTRIES.Country; (3.5p)

d.

- step 0: create a temporary table for storing fathers with at least k

children (1p)

-------------------------------------------------

-- DDL for Table TMPPHLKC

-------------------------------------------------

CREATE TABLE "LAB_DB"."TMPPHLKC"

( "X" NUMBER(6,0),

"CHILDRENNO" NUMBER(2,0)

) SEGMENT CREATION IMMEDIATE

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

NOCOMPRESS LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS";

- step 1: add to the LAB_DB_PL_SQL package the following procedure:

procedure AtLeastkChildrennGrandChildren

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType);

procedure AtLeastkChildrennGrandChildren

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType) is

begin

Page 234: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

234

--0. initialize tmpPHLkC (0.5p) DELETE FROM tmpPHLkC;

--1. compute and store into it fathers with at least k

--children (4.5p) INSERT INTO tmpPHLkC

SELECT PEOPLE.x, Count(CHILDREN.x) ChildrenNo

FROM PEOPLE CHILDREN INNER JOIN PEOPLE

ON CHILDREN.Father = PEOPLE.x

GROUP BY PEOPLE.x

HAVING Count(CHILDREN.x) >= Min_no_of_children;

--2. compute and return grandfathers with at least k

--children, each of which has n children (9p) OPEN rc FOR

SELECT NAMES.Name, ChildrenNo,

Count(GrandChildren.x) GrandChildrenNo

FROM (PEOPLE GrandChildren INNER JOIN (PEOPLE CHILDREN

INNER JOIN tmpPHLkC

ON CHILDREN.Father = tmpPHLkC.x)

ON GrandChildren.Father = CHILDREN.x) INNER JOIN PEOPLE

NAMES ON tmpPHLkC.x = NAMES.x

GROUP BY NAMES.Name, tmpPHLkC.ChildrenNo

HAVING Count(GrandChildren.x) >= Min_no_of_grand_children

ORDER BY ChildrenNo DESC, Count(GrandChildren.x) DESC,

NAMES.Name;

end AtLeastkChildrennGrandChildren;

- step 3: test for k = n = 1, respectively 2

var c refcursor;

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildren(1,1,:c);

print c;

Page 235: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

235

Figure 6.3 Result of stored procedure

AtLeastkChildrennGrandChildren for k = n = 1 (1p)

Page 236: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

236

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildren(2,2,:c);

print c;

Figure 6.4 Result (empty set) of stored procedure

AtLeastkChildrennGrandChildren for k = n = 2 (1p)

6.2 Number 2 a. (2p.) Design and develop a SQL script for adding to the lab db the city

“Curtea de Argeș” from the Romania’s state “Argeș”, knowing that Ro-

mania’s id is 1 and that state “Argeș” does not exist either.

b. (3.5p.) Design and develop a SQL script for adding to the lab db the

function BurrialPlace: PEOPLE CITIES, having the following graph

and knowing that there is only one city named “Curtea de Argeș”:

x City BurrialPlace (x)

7 Curtea de Argeș

6 Curtea de Argeș

Page 237: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

237

c. (Only in Access)(4.5p.) Describe needed steps for adding a lookup

combo-box to BurrialPlace, without using the Lookup Wizard.

c. (Only in Oracle) (3.5p.) Design and develop a SQL statement for

creating a view CITIES_STATES_CONTRIES, which computes the fol-

lowing result:

x City, State, Country

7 Bucharest, Bucharest, ROMANIA

23 Chișinău, Chișinău, MOLDAVIA

41 Constanța, Constanța, ROMANIA

43 Iași, Iași, ROMANIA

25 London, Greater London, U.K.

44 Memphis, Tennessee, U.S.A.

42 New York, New York, U.S.A.

45 Sibiu, Sibiu, ROMANIA

24 Washington, District of Columbia, U.S.A.

d. (17p Access/18p Oracle) Compute, without using subqueries, the set of

triples <Name, ChildrenNo, GrandChildrenNo>, in the descending order

of ChildrenNo and GrandChildrenNo, and then ascending on Name, for

all grandmothers that have at least k children, each of which having at

least n children (k and n being natural parameters). Which is the result for

the PEOPLE lab db instance when k = n = 1 and k = n = 2?

Hints offered as answers to students’ questions during tests:

a. No, there is not only one form of the INSERT SQL statement!

b. Yes, the Key Propagation Principle should be applied in all such

cases!

c. The corresponding SELECT statement is worth 3.5p and the most

important combo-boxes’ property 0.5p.

d. No, there are no ChildrenNo and GrandChildrenNo fields in the

PEOPLE table, but they are computable!

Page 238: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

238

6.2.1 Access solution

a.

INSERT INTO STATES (State, Country)

VALUES (“Argeș”, 1); (0.5p)

INSERT INTO CITIES (City, State)

SELECT “Curtea de Argeș”, x FROM STATES

WHERE State = “Argeș” AND Country = 1; (1.5p)

b.

ALTER TABLE PEOPLE ADD COLUMN BurrialPlace LONG;

(0.5p)

ALTER TABLE PEOPLE ADD CONSTRAINT fkBurPlace

FOREIGN KEY (BurrialPlace) REFERENCES CITIES;

(1.25p)

UPDATE PEOPLE SET BurrialPlace = DLookup(“x”,

“CITIES”, “City=’Curtea de Argeș’”) WHERE x IN

(7,6); (1.75p)

c.

- open PEOPLE in Design mode; (0.05p)

- on the BurrialPlace line, in the Lookup tab, switch the Display Control

property from Text to Combo box; (0.05p)

- in the Row Source property, type:

SELECT CITIES.x, [City] & ", " & [STATES].[State]

& ", " & [COUNTRIES].[Country]

AS [City, State, Country]

FROM COUNTRIES INNER JOIN (STATES INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY [City] & ", " & [STATES].[State] & ", "

& [COUNTRIES].[Country]; (3.5p)

- set the Column Count property to 2; (0.15p)

- set the Column Heads property to Yes; (0.05p)

- set the Column Width property to 0”;4”; (0.05p)

Page 239: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

239

- set the List Rows property to 32; (0.05p)

- set the List Width property to 4”; (0.05p)

- set the Limit to List property to Yes; (0.5p)

- save and close the table scheme window. (0.05p)

d.

- step 1: mothers with at least k children

PeopleHavingAtLeastkChildrenM: (5p)

SELECT PEOPLE.x, Count(CHILDREN.x) AS ChildrenNo

FROM PEOPLE AS CHILDREN INNER JOIN PEOPLE

ON CHILDREN.Mother = PEOPLE.x

GROUP BY PEOPLE.x

HAVING Count(CHILDREN.x) >=

[Enter desired minimum number of children:];

- step 2: grandmothers with at least k children, each of which has n

children

PeopleHavingAtLeastkChildrenAndnGrandChildrenM: (7p)

SELECT PeopleHavingAtLeastkChildrenM.x,

PeopleHavingAtLeastkChildrenM.ChildrenNo,

Count(GrandChildren.x) AS GrandChildrenNo

FROM PEOPLE AS GrandChildren INNER JOIN (PEOPLE AS CHILDREN

INNER JOIN PeopleHavingAtLeastkChildrenM

ON CHILDREN.Mother = PeopleHavingAtLeastkChildrenM.x)

ON GrandChildren.Mother = CHILDREN.x

GROUP BY PeopleHavingAtLeastkChildrenM.x,

PeopleHavingAtLeastkChildrenM.ChildrenNo

HAVING Count(GrandChildren.x) >=

[Enter desired minimum number of grand children:];

Page 240: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

240

- step 3: getting names and sorting

Test1-d2: (3p)

SELECT PEOPLE.Name,

PeopleHavingAtLeastkChildrenAndnGrandChildrenM.ChildrenNo,

PeopleHavingAtLeastkChildrenAndnGrandChildrenM.GrandChildrenNo

FROM PEOPLE INNER JOIN

PeopleHavingAtLeastkChildrenAndnGrandChildrenM

ON PEOPLE.x = PeopleHavingAtLeastkChildrenAndnGrandChildrenM.x

ORDER BY

PeopleHavingAtLeastkChildrenAndnGrandChildrenM.ChildrenNo

DESC,

PeopleHavingAtLeastkChildrenAndnGrandChildrenM.GrandChildrenNo

DESC, PEOPLE.Name;

Figure 6.5 Result of query Test1-d2 for k = n = 1 (1p)

Figure 6.6 Result (empty set) of query Test1-d2 for k = n = 2 (1p)

Page 241: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

241

6.2.2 Oracle solution

a.

INSERT INTO STATES (State, Country)

VALUES ('Argeș', 1); (0.5p)

INSERT INTO CITIES (City, State)

SELECT 'Curtea de Argeș', x FROM STATES

WHERE State = 'Argeș' AND Country = 1; (1.5p)

b.

ALTER TABLE PEOPLE ADD BurrialPlace NUMBER(6,0);

(0.5p)

ALTER TABLE PEOPLE ADD CONSTRAINT fkBurPlace

FOREIGN KEY (BurrialPlace) REFERENCES CITIES;

(1.25p)

UPDATE PEOPLE SET BurrialPlace = (SELECT x FROM

CITIES WHERE City='Curtea de Argeș') WHERE x IN

(6,7); (1.75p)

c.

-------------------------------------------------

-- DDL for View CITIES_STATES_CONTRIES

-------------------------------------------------

CREATE OR REPLACE FORCE VIEW

"LAB_DB"."CITIES_STATES_CONTRIES"

("X", "City, State, Country") AS

SELECT CITIES.x, City || ', ' || STATES.State ||

', ' || COUNTRIES.Country "City, State, Country"

FROM COUNTRIES INNER JOIN (STATES INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY City || ', ' || STATES.State || ', ' ||

COUNTRIES.Country; (3.5p)

d.

- step 0: create a temporary table for storing mothers with at least k

children (1p)

Page 242: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

242

-------------------------------------------------

-- DDL for Table TMPPHLKC

-------------------------------------------------

CREATE TABLE "LAB_DB"." TMPPHLKC"

( "X" NUMBER(6,0),

"CHILDRENNO" NUMBER(2,0)

) SEGMENT CREATION IMMEDIATE

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

NOCOMPRESS LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS";

- step 1: add to the LAB_DB_PL_SQL package the following procedure:

procedure AtLeastkChildrennGrandChildrnM

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType);

procedure AtLeastkChildrennGrandChildrenM

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType) is

begin

--0. initialize tmpPHLkC (0.5p) DELETE FROM tmpPHLkC;

--1. compute and store into it mothers with at least k

--children (4.5p) INSERT INTO tmpPHLkC

SELECT PEOPLE.x, Count(CHILDREN.x) ChildrenNo

FROM PEOPLE CHILDREN INNER JOIN PEOPLE

ON CHILDREN.Mother = PEOPLE.x

GROUP BY PEOPLE.x

HAVING Count(CHILDREN.x) >= Min_no_of_children;

--2. compute and return grandmothers with at least k

--children, each of which has n children (9p)

Page 243: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

243

OPEN rc FOR

SELECT NAMES.Name, ChildrenNo,

Count(GrandChildren.x) GrandChildrenNo

FROM (PEOPLE GrandChildren INNER JOIN (PEOPLE CHILDREN

INNER JOIN tmpPHLkC

ON CHILDREN.Mother = tmpPHLkC.x)

ON GrandChildren.Mother = CHILDREN.x) INNER JOIN PEOPLE

NAMES ON tmpPHLkC.x = NAMES.x

GROUP BY NAMES.Name, tmpPHLkC.ChildrenNo

HAVING Count(GrandChildren.x) >= Min_no_of_grand_children

ORDER BY ChildrenNo DESC, Count(GrandChildren.x) DESC,

NAMES.Name;

end AtLeastkChildrennGrandChildrnM;

- step 3: test for k = n = 1, respectively 2

var c refcursor;

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildrnM(1,1,:c);

print c;

Figure 6.7 Result of stored procedure

AtLeastkChildrennGrandChildrnM for k = n = 1 (1p)

Page 244: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

244

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildrenM(2,2,:c);

print c;

Figure 6.8 Result (empty set) of stored procedure

AtLeastkChildrennGrandChildrnM for k = n = 2 (1p)

6.3 Best practice rules

6.4 Homework H6.1. Prove that any acyclic binary, homogeneous relations (including

autofunctions) are also irreflexive, anti-symmetric and anti-transitive.

H6.2. Prove that any function is idempotent (that is f2 = f f = f) if and

only if it is transitive. Also it is anti-idempotent if and only if it is anti-

transitive.

H6.3. Prove that an autofunction is symmetric if and only if f2 is equal to

the unity mapping.

H6.4. Establish a similar characterization theorem for reflexive and anti-

reflexive functions.

Page 245: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

245

H6.5. Consider the REIGNS db scheme from the previous lecture

(including object sets RULERS, MARRIAGES, and REIGNS) and forma-

lize the following “business rules”, by using object constraints:

a) Nobody can get married, neither before he/she is born, nor after he/she

passed away.

b) No children may be born after their mother passed away for more than

one day.

c) No king, president, etc. can rule without being alive.

Page 246: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

246

Volume II: Database

design

Page 247: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

247

Chapter 7. 7th Lab: Business Analysis

7.1 Exercises P7.1 (Forward engineering)(FE)

Consider the sub-universe of a PC store and design a rdb for it such as to

allow storing data on its catalog of products and stocks, limited, to begin

with, at types, characteristics, quantities, manufacturers, and prices, by

applying the algorithms for business analysis assistance and for translat-

ing E-RDs and restriction lists into rdb schemes. Provide a plausible in-

stance for this rdb.

Solution:

Trivially, manufacturers and products are sets of objects; note that, just

like as bought/lent/borrowed/etc. books are copies of edition volumes,

products are categorized into types (e.g. notebooks, iPads, memory, etc.),

which is also a set of objects (even if abstract). Besides names, products

also have unique codes. Obviously, any product is of only one type and

made by only one manufacturer (whereas both types and manufacturers

include/make several products).

Consequently, the first half of this sub-universe should be modeled by the

following E-RD:

TypeName PROD_TYPES Code ProductName

Type

Manufacturer PRODUCTS

ManufactName MANUFACTURERS Price StockQty

Figure 7.1 First half of the E-RD for P7.1

Page 248: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

248

The following business rules exist for this first half:

- Product manufacturer, product type, as well as manufacturer and

product type names, product name, code, price, and stock quantity

are compulsory.

- Manufacturer name, product type name, and product code unique-

ly identify the elements of the corresponding sets.

- Prices (let’s say in Euros, with maximum 2 decimals) and stocks

(naturals) are positive and not greater than, let’s say, 9999.

On characteristics, note first that there are several ones having same mea-

surement units (e.g. internal and external memories’ size, USBs, modems,

network adapters’ speed, etc.): consequently, it is a good idea to add such

an object set too. Then, same goes for product type characteristics: several

product types have same characteristics (e.g. size, speed, resolution,

weight, etc.), so that it is a good idea to abstract both an entity-type object

set CHARACTERISTICS and a relationship-type one PROD_TYPE_

CHARS relating it to the PROD_TYPES above. Moreover, in order to

store actual products characteristics values, a similar PRODUCTS_

CHARS relationship is needed too. Consequently, the second half of this

sub-universe should be modeled by the following E-RD:

PROD_TYPES PROD_TYPES_CHARS CharName

CHARACTERISTICS

MU

PRODUCTS PRODUCTS_CHARS MEASURE_UNITS

CharactValue MUName

Figure 7.2 Second half of the E-RD for P7.1

Page 249: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

249

The following business rules exist for this second half:

- Characteristics and measurement units’ names, as well as values

of characteristics for products are compulsory (measurement units

for characteristics are not, as there are type-types ones too).

- Characteristics and measurement units’ names are uniquely identi-

fying their corresponding object sets elements.

Figure 7.3 shows the corresponding full structural E-RD.

Manufacturer Type

MANUFACTURERS PRODUCTS PROD_TYPES

PRODUCTS_CHARS PROD_TYPES_CHARS

CHARACTERISTICS

MU

MEASURE_UNITS

Figure 7.3 Structural E-RD for P7.1

The following restriction list is associated to it:

1. MANUFACTURERS

a. max. cardinality: 99 (R0)

b. attribute (co-)domains (ranges):

ManufactName: ASCII(32) (R1)

c. compulsory data: ManufactName (R2)

d. uniqueness: ManufactName (there does not exist two manu-

facturers having same names) (R3)

2. PROD_TYPES

a. max. cardinality: 99 (R4)

Page 250: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

250

b. attribute (co-)domains (ranges):

TypeName: ASCII(16) (R5)

c. compulsory data: TypeName (R6)

d. uniqueness: TypeName (there may not be two product

types having same names) (R7)

3. PRODUCTS

a. max. cardinality: 9999 (R8)

b. attribute (co-)domains (ranges):

ProductName, Code: ASCII(16) (R9)

Price, StockQty: RAT+(6,2) (R10)

c. compulsory data: ProductName, Code, Price, StockQty,

Type, Manufacturer (R11)

d. uniqueness: Code (there does not exist two products

having same codes) (R12)

4. MEASURE_UNITS

a. max. cardinality: 99 (R13)

b. attribute (co-)domains (ranges):

MUName: ASCII(16) (R14)

c. compulsory data: MUName (R15)

d. uniqueness: MUName (R16)

5. CHARACTERISTICS

a. max. cardinality: 99 (R17)

b. attribute (co-)domains (ranges):

CharName: ASCII(16) (R18)

c. compulsory data: CharName, MU (R19)

d. uniqueness: CharName (R20)

6. PROD_TYPES_CHARS

a. max. cardinality: 99999 (R21)

b. compulsory data: ProductType, Characteristic (R22)

c. uniqueness: <ProductType, Characteristic> (it is sense-

less to store twice a same characteristic for

a same product type) (R23)

7. PRODUCTS_CHARS

a. max. cardinality: 99999 (R24)

b. attribute (co-)domains (ranges):

Page 251: Laborator Baze date

Christian Mancas & Alina Dicu, FILS, Bucharest Polytechnic Univ.: DB Lab. Notes

251

CharactValue: ASCII(16) (R25)

c. compulsory data: CharactValue, Product, Characteristic

(R26)

d. uniqueness: <Product, Characteristic> (there may not be two

values for a same characteristic for a same product) (R27)

Note that ProductType and Characteristic are the two canonical Cartesian

projections of PROD_TYPES_CHARS; as such, their values are compul-

sory and their product is minimally one-to-one. Same thing obviously is

true for Product and Characteristic of PRODUCTS_CHARS.

Also note that there is an associated non-relational type restriction,

namely:

“In order for a product to have a characteristic, the corresponding product

type should also have that characteristic”. (R28)

Figure 7.4 shows the corresponding rdb and a plausible instance.

Note that many beginners are not using the power of abstraction: instead

of PRODUCTS, PROD_TYPES, CHARACTERISTICS, PROD_TYPES_

CHARS, and PRODUCTS_CHARS, they are adding unrelated object sets

for each product type (e.g. NOTEBOOKS, PADS, MONITORS, etc.) and

attaching to each of them as attributes (properties) all characteristics that

apply. This means that instead of these above 7 tables, each having an

average of 4 columns and some 1,000 rows, their “dbs” have dozens of ta-

bles, each one having in average dozens of columns and only dozens of

rows. To avoid such mistakes, always remember the business analysis

(BA) “golden rules” BAR1 and BAR2.

Also note that they would most probably not abstract MANUFACTU-

RERS, PROD_TYPES, and MEASURE_UNITS either: instead, they are

adding text attributes Manufacturer, Type, and MU to all of their tables!

Obviously, besides violating BAR3, this has as very unpleasant effects

both insertion, update, and deletion anomalies.

Page 252: Laborator Baze date

252

MANUFACTURERS(x,

ManufactName)

x ManufactName

Auton(2) ASCII(32)

NOT NULL NOT NULL

1 Intel

2 Apple

3 Samsung

4 Dell

PROD_TYPES(x, TypeName)

x TypeName

Auton(2) ASCII(16)

NOT NULL NOT NULL

1 notebooks

2 monitors

3 memories

4 hard disks

PRODUCTS(x, Code)

x Code Product

Name

Pric

e

Stock

Qty

Type Manufacturer

Auto

n(4)

ASCII(1

6)

ASCII(1

6)

RAT+(6,2

)

RAT+

(6,2)

Im(PROD

_TYPES,x

)

Im(MANUFAC

TURERS,x)

NOT

NUL

L

NOT

NULL

NOT

NULL

NOT

NUL

L

NOT

NUL

L

NOT

NULL

NOT NULL

1 DI5520 INSPIR

ON

5520

$600 8 1 4

2 AMBA MacBoo

k Air

$120

0

4 1 2

3 SMSA4

60

SA460 $380 6 2 3

4 SSD7T

D250

MZ-

7TD250

$170 10 4 3

Page 253: Laborator Baze date

247

MEASURE_UNITS(x, MUName)

x MUName

Auton(2) ASCII(16)

NOT NULL NOT NULL

1 Kg

2 GHz

3 GB

4 TB

5 Inch

6 M

7 MB

8 KB

9 DPI

CHARACTERISTICS (x,

CharName)

x CharName MU

Auto-

n(2)

ASCII(16) Im(MEA-

SURE

_UNITS.x)

NOT

NULL

NOT

NULL

1 Weight 1

2 CPU speed 2

3 Disk size 4

4 HDD type

PROD_TYPES_CHARS(x, ProductType Characteristic)

x ProductType Characteristic

Auton(5) Im(PROD_TYPES.x) Im(CHARACTERISTICS.x)

NOT NULL NOT NULL NOT NULL

1 1 1

2 1 2

3 1 4

4 3 3

PRODUCTS_CHARS(x, Product Characteristic)

x Product Characteristic CharactValue

Auton(5) Im(PRO-

DUCTS.x)

Im(CHARAC-

TERISTICS.x)

ASCII(16)

NOT NULL NOT NULL NOT NULL NOT NULL

1 1 1 3.08

2 1 2 2.5

3 4 4 SSD

4 4 3 0.25

Figure 7.4 P7.1 rdb and a plausible instance

Page 254: Laborator Baze date

248

P7.2 (Reverse engineering)(RE)

Consider the attached rdb GeografieBD/GeographyDB and infer its relatio-

nal scheme, as well as corresponding E-RDs and restrictions list, by applying

corresponding algorithms for reverse engineering Access/Oracle dbs and

translating relational schemes into E-RDs and restriction lists.

Access Solution:

a. relational schemes Access dbs

When opening GeografieBD, you note that there are 42 tables in it; accord-

ing to the algorithm, you have to inspect it all in design mode; for example,

figure 7.5 shows the design view of table VECINATATIM:

Figure 7.5 Design view of the Access GeografieBD VECINATATIM table

You should note that this table has 5 columns (attributes): #VM (the surro-

gate autonumber primary key), Mare, TaraVecina, KmMal, and PunctCar-

dinal.

From Mare’s lookup row source:

SELECT [#M], Mare FROM MARI ORDER BY Mare;

Page 255: Laborator Baze date

249

it results that Mare is a foreign key referencing (the primary surrogate key

#M of) table MARI.

Note that, when foreign keys do not have associated lookup combo-boxes,

you can detect them in Access in at least two other ways, by using either:

1. the Relationships db tools:

Click on the Relationships icon from the Database Tools tab of the Ribbon:

Figure 7.6 Relationships of GeografieBD

When, such as in this case, there are too many relationships, click on the

Clear Layout icon of the Ribbon’s Relationship Tools Design tab and con-

firm your request:

Page 256: Laborator Baze date

250

Figure 7.7 Confirmation message for clearing the Relationships window

Next, click on the Ribbon’s Show Table icon and add the VECINATATIM ta-

ble:

Figure 7.8 Adding a table instance to the Relationships window

After clicking on the Add button, click on the Close one; next, click on the

Ribbon’s Direct Relationships icon (see figure 7.9): all (and only the) foreign

keys of VECINATATIM are shown.

Page 257: Laborator Baze date

251

Figure 7.9 Inspecting VECINATATIM foreign keys

Page 258: Laborator Baze date

252

2. or the metadata catalog table MSysRelationships:

Open the MSysRelationships table (a hidden, system table), which contains a

row for every db foreign key:

Figure 7.10 GeografieBD MSysRelationships instance fragment

You may sort it, for example, ascendingly on szObject (which stores table

names containing foreign keys) and you then find easily the two foreign keys

of : Mare and TaraVecina (in the szColumn column). Note that column

szReference stores corresponding referenced columns, while the szRe-

ferenceObject one stores corresponding referenced table.

Similarly, from TaraVecina’s lookup row source:

SELECT [#T], Tara FROM TARI ORDER BY Tara;

it results that TaraVecina is a foreign key referencing (the primary surrogate

key #T of) table TARI.

KmMal is a natural attribute taking values, according to its Validation Rule

property (from the General tab), into [1, 999999999].

Finally, PunctCardinal, is also natural taking values, according to its Row

Source property (from the Lookup tab), into [1, 9].

Page 259: Laborator Baze date

253

From the Required property of the General tab, it follows that Mare, Tara-

Vecina, and PunctCardinal are compulsory (trivially, being the primary key,

#VM is compulsory too, by definition).

By clicking on the Ribbon’s Indexes icon (of the Table Tools Design tab), we

find out that, besides its primary key, this table also has the semantic key (as

its Unique property is set to Yes) Mare TaraVecina.

Figure 7.11 Inspecting VECINATATIM keys

Figure 7.12 shows VECINATATIM table’s properties: as there is no valida-

tion rule, you should infer that this table scheme does not contain any tuple

(check) constraint.

Figure 7.12 Inspecting VECINATATIM table’s properties

Page 260: Laborator Baze date

254

Figure 7.13 presents the corresponding rdb, obtained by the above reverse

engineering of this table scheme, as well as its first instance row values.

VECINATATIM (#VM, Mare TaraVecina)

#VM Mare TaraVecina KmMal PunctCardinal

Auton. Im(MARI.#M) Im(TARI.#T) [1,

999999999]

[1, 9]

NOT

NULL

NOT NULL NOT NULL NOT NULL

1 13 1 4

Figure 7.13 Relational scheme of VECINATATIM and its first row

b. E-RDs + restriction lists relational schemes

Figure 7.14 shows the corresponding E-RD. Note that, as Mare and TaraVe-

cina are compulsory and the semantic key of this table is Mare TaraVe-

cina, you can infer that, in fact, VECINATATIM is a relationship: see equi-

valent corresponding E-RD in figure 7.15.25

PunctCardinal

Mare TaraVecina

MARI VECINATATIM TARI

KmMal

Figure 7.14 E-RD of VECINATATIM

25

Note that this is also obvious from this table instance: it stores pairs of type < c, s >, where

c is a country which is neighbor to a sea s, so TaraVecina and Mare are the corresponding

canonical Cartesian projections of VECINATATIM.

Page 261: Laborator Baze date

255

PunctCardinal

MARI VECINATATIM TARI

KmMal

Figure 7.15 Equivalent E-RD of VECINATATIM

The associated list of restrictions fragment is the following:

J. VECINATATIM

a. attribute (co-)domains (ranges):

KmMal: [1, 999999999] (Ri)

PunctCardinal: [1, 9] (Ri+1)

b. compulsory data: Mare, TaraVecina, PunctCardinal (Ri+2)

c. uniqueness: Mare TaraVecina (it is senseless to store

more than once that a country is neighbor to a sea) (Ri+3)

Oracle Solution:

a. relational schemes Oracle dbs

When opening GeographyDB, you note that there are 42 tables in it; accord-

ing to the algorithm, you have to inspect it all; for example, figure 7.16

shows the design view of table SNEIGHBORS.

Obviously, we could use in what follows the GUI of the SQL Developer, just

like we used Access’ one above (see homework 7.7); however, we prefer

here the following other two equivalent solutions:

querying Oracle’s metacatalog (see, for a similar Access solution,

homework 7.6);

extracting metadata from the corresponding SQL DDL statements.

Both of them are general, although also needing technological knowledge.

Page 262: Laborator Baze date

256

Figure 7.16 Oracle GeographyDB SNEIGHBORS table scheme

a.1 querying Oracle’s metacatalog

In order to find out what are the user tables of a db, run the following query

(see figure 7.17):

select TABLE_NAME, TABLESPACE_NAME, STATUS,

NUM_ROWS, TEMPORARY, READ_ONLY

from user_tables

where DROPPED = 'NO'

order by TABLESPACE_NAME, TABLE_NAME;

Figure 7.17 Querying Oracle’s metacatalogue for finding tables

Page 263: Laborator Baze date

257

Note that:

- user_tables is a system view (like all of the following data sources

from this sub-section)

- you may obtain dozens of other metadata on tables from this view

- the normal STATUS of tables is ‘VALID’

- NUM_ROWS gives you corresponding actual cardinalities

- fundamental tables have TEMPORARY = ‘N’.

Similarly, you can get metadata on user table columns by running the follow-

ing query (see figure 7.18):

select TABLE_NAME, COLUMN_NAME, DATA_TYPE,

DATA_LENGTH, DATA_PRECISION, NULLABLE,

COLUMN_ID, DATA_DEFAULT, CHARACTER_SET_NAME,

CHAR_LENGTH

from user_tab_columns

order by TABLE_NAME, COLUMN_NAME;

Figure 7.18 Querying Oracle’s metacatalogue for finding table columns

Note that:

- user_tab_columns is a system view

- you may obtain dozens of other metadata on columns from this view

- the actual (physical) order of columns within tables is stored in

COLUMN_ID

Page 264: Laborator Baze date

258

- DATA_LENGTH gives corresponding actual logical number of cha-

racters/digits

- DATA_PRECISION gives corresponding actual number of digits after

the decimal point (and is null for all other data types)

- NULLABLE = ‘N’ means that corresponding columns does not accept

null values

- CHARACTER_SET_NAME gives (for text type columns) the actual

alphabet used for storing corresponding values (with ‘CHAR_ CS’

meaning ASCII and null for non-text columns)

- CHAR_LENGTH gives for text columns (for numeric ones it is al-

ways 0!) the actual (physical) maximum number of bytes needed to

store corresponding column values (which is always equal to DA-

TA_LENGTH above for the ASCII alphabet, but, for example, four

times bigger for UNICODE).

Similarly, you can get metadata on user constraints by running the following

query (see figure 7.19):

select TABLE_NAME, CONSTRAINT_TYPE,

CONSTRAINT_NAME, SEARCH_CONDITION,

R_CONSTRAINT_NAME

from user_constraints

where INVALID is null AND STATUS = 'ENABLED'

order by TABLE_NAME, CONSTRAINT_TYPE,

CONSTRAINT_NAME;

Note that:

- user_constraints is a system view

- you may obtain many other metadata on constraints from this view

- figure 7.20 decodes constraint types codes given by CON-

STRAINT_TYPE

- SEARCH_CONDITION gives corresponding logic expressions for

check (tuple) and NOT NULL constraints (and null for the rest)

- R_CONSTRAINT_NAME gives the corresponding referenced prima-

ry/unique constraint name (note that constraint names are unique

within any db, just like for tables/views, etc.) for foreign keys

(referential integrities)( and null for the rest).

Page 265: Laborator Baze date

259

Figure 7.19 Querying Oracle’s metacatalogue for finding table constraints

Figure 7.20 Oracle’s constraint types

Finaly, you can get metadata on user constraint columns by running the fol-

lowing query (see figure 7.21):

select * from user_cons_columns

order by TABLE_NAME, CONSTRAINT_NAME,

COLUMN_NAME;

Page 266: Laborator Baze date

260

Figure 7.21 Querying Oracle’s metacatalogue for constraint columns

Note that:

- user_cons_columns is a system view

- POSITION gives corresponding column position in the constraint

(when applicable: e.g. in keys and foreign keys)

Obviously, you can combine all this data into only one result, also filtered by

a table name (see figure 7.22), for example with the following query:

select X.TABLESPACE_NAME, X.TABLE_NAME, STATUS,

Page 267: Laborator Baze date

261

NUM_ROWS, TEMPORARY, READ_ONLY,

X.COLUMN_NAME, DATA_TYPE, DATA_LENGTH,

DATA_PRECISION, NULLABLE, COLUMN_ID,

DATA_DEFAULT, CHARACTER_SET_NAME,

CHAR_LENGTH, CONSTRAINT_TYPE,

CONSTRAINT_NAME, SEARCH_CONDITION,

R_CONSTRAINT_NAME, POSITION

from

(select TABLESPACE_NAME, T.TABLE_NAME, T.STATUS,

NUM_ROWS, TEMPORARY, READ_ONLY,

A.COLUMN_NAME, DATA_TYPE, DATA_LENGTH,

DATA_PRECISION, NULLABLE, COLUMN_ID,

DATA_DEFAULT, CHARACTER_SET_NAME,

CHAR_LENGTH

from user_tables t inner join user_tab_columns a

on t.table_name = a.table_name

where DROPPED = 'NO' AND

t.table_name = 'SNEIGHBORS') x

full outer join

(select TABLESPACE_NAME, T.TABLE_NAME,

CONSTRAINT_TYPE, C.CONSTRAINT_NAME,

SEARCH_CONDITION, R_CONSTRAINT_NAME,

COLUMN_NAME, POSITION

from user_tables t inner join user_constraints c

on t.table_name = c.table_name inner join

user_cons_columns cc on c.constraint_name =

cc.constraint_name

where INVALID is null AND C.STATUS = 'ENABLED'

AND t.table_name = 'SNEIGHBORS') y

on x.table_name = y.table_name and

x.column_name = y.column_name

order by X.TABLESPACE_NAME, X.TABLE_NAME,

CONSTRAINT_TYPE, CONSTRAINT_NAME,

X.COLUMN_NAME;

Page 268: Laborator Baze date

262

Figure 7.22 Querying Oracle’s catalogue for SNEIGHBORS metadata

a.1 extracting metadata from corresponding SQL DDL statements

The easiest way to extract all SQL DDL statements pertaining to a table is to

right-click its name, select the Quick DDL option and then click on the Save

to Clipboard one:

Figure 7.23 Extracting SQL DDL statements for table SNEIGHBORS

Then, you can paste the result in any text file (including SQL Developer

worksheets); here is the one obtained for table SNEIGHBORS:

Page 269: Laborator Baze date

263

-------------------------------------------------

-- DDL for Table SNEIGHBORS

-------------------------------------------------

CREATE TABLE "LAB_DB"."SNEIGHBORS"

( "X" NUMBER(3,0),

"SEA" NUMBER(3,0),

"COUNTRY" NUMBER(3,0),

"SHOREKM" NUMBER(9,0),

"CARDINALPOINT" NUMBER(1,0)

) SEGMENT CREATION IMMEDIATE

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

NOCOMPRESS LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS" ;

COMMENT ON COLUMN "LAB_DB"."SNEIGHBORS"."X" IS

'Primary surrogate SNEIGHBORS key';

COMMENT ON COLUMN "LAB_DB"."SNEIGHBORS"."SEA" IS

'Neighbor sea (to country)';

COMMENT ON COLUMN

"LAB_DB"."SNEIGHBORS"."COUNTRY" IS 'Neighbor

country (to sea)';

COMMENT ON COLUMN

"LAB_DB"."SNEIGHBORS"."SHOREKM" IS 'Total number of

Km of country''s sea shore';

COMMENT ON COLUMN

"LAB_DB"."SNEIGHBORS"."CARDINALPOINT" IS 'Cardinal

point of the sea shore for the country';

COMMENT ON TABLE "LAB_DB"."SNEIGHBORS" IS 'The

set of pairs of interest <s,c> storing the fact

that sea s is neighbor to country c.';

-------------------------------------------------

-- DDL for Index TARI_PK

-------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."TARI_PK" ON

"LAB_DB"."SNEIGHBORS" ("X")

PCTFREE 10 INITRANS 2 MAXTRANS 255

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

Page 270: Laborator Baze date

264

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS" ;

-------------------------------------------------

-- DDL for Index SNEIGHBORS_UK1

-------------------------------------------------

CREATE UNIQUE INDEX "LAB_DB"."SNEIGHBORS_UK1" ON

"LAB_DB"."SNEIGHBORS" ("COUNTRY", "SEA")

PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE

STATISTICS

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS" ;

-------------------------------------------------

-- Constraints for Table SNEIGHBORS

-------------------------------------------------

ALTER TABLE "LAB_DB"."SNEIGHBORS" ADD CONSTRAINT

"SNEIGHBORS_UK1" UNIQUE ("COUNTRY", "SEA")

USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255

COMPUTE STATISTICS

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS" ENABLE;

ALTER TABLE "LAB_DB"."SNEIGHBORS" MODIFY ("X" NOT

NULL ENABLE);

ALTER TABLE "LAB_DB"."SNEIGHBORS" MODIFY ("SEA"

NOT NULL ENABLE);

ALTER TABLE "LAB_DB"."SNEIGHBORS" MODIFY

("COUNTRY" NOT NULL ENABLE);

ALTER TABLE "LAB_DB"."SNEIGHBORS" MODIFY

("CARDINALPOINT" NOT NULL ENABLE);

ALTER TABLE "LAB_DB"."SNEIGHBORS" ADD CONSTRAINT

"TARI_PK" PRIMARY KEY ("X")

USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255

Page 271: Laborator Baze date

265

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS" ENABLE;

-------------------------------------------------

-- Ref Constraints for Table SNEIGHBORS

-------------------------------------------------

ALTER TABLE "LAB_DB"."SNEIGHBORS" ADD CONSTRAINT

"SNEIGHBORS_COUNTRIES_FK1" FOREIGN KEY ("COUNTRY")

REFERENCES "LAB_DB"."COUNTRIES" ("X")

ENABLE;

ALTER TABLE "LAB_DB"."SNEIGHBORS" ADD CONSTRAINT

"SNEIGHBORS_SEAS_FK1" FOREIGN KEY ("SEA")REFERENCES

"LAB_DB"."SEAS" ("X") ENABLE;

Obviously, this script too contains all needed metadata for RE table

SNEIGHBORS, just like the result shown in figure 7.22 does.

Finally, regardless of which above method we used, we can infer the follow-

ing metadata on the SNEIGHBORS table:

It has 5 columns (attributes): X (the surrogate autonumber primary

key), Sea, Country, ShoreKm, and CardinalPoint

Sea is a foreign key referencing (the primary surrogate key X of)

table SEAS

Country is a foreign key referencing (the primary surrogate key X of)

table COUNTRIES

ShoreKm is a natural attribute taking values into [1, 999999999]

CardinalPoint is also natural taking values into [1, 9]

Sea, Country, and CardinalPoint are compulsory (trivially, being the

primary key, X is compulsory too, by definition)

It also has the semantic key Country Sea

No check (tuple) constraint is defined on this table.

Figure 7.24 presents the corresponding rdb, obtained by the above reverse

engineering of this table scheme, as well as its first instance row values.

Page 272: Laborator Baze date

266

SNEIGHBORS (X, Sea Country)

x Sea Country ShoreKm Cardi-

nalPoint

Auto-

n(3)

Im(SEAS.X) Im(COUNTRIES.X) [1,

999999999]

[1, 9]

NOT

NULL

NOT NULL NOT NULL NOT

NULL

1 13 1 4

Figure 7.24 Relational scheme of SNEIGHBORS and its first row

b. E-RDs + restriction lists relational schemes

Figure 7.25 shows the corresponding E-RD. Note that, as Sea and Country

are compulsory and the semantic key of this table is Sea Country, you can

infer that, in fact, SNEIGHBORS is a relationship: see equivalent

corresponding E-RD in figure 7.26.26

CardinalPoint

Sea Country

SEAS SNEIGHBORS COUNTRIES

ShoreKm

Figure 7.25 E-RD of SNEIGHBORS

26

Note that this is also obvious from this table instance: it stores pairs of type < c, s >, where

c is a country which is neighbor to a sea s, so Country and Sea are the corresponding

canonical Cartesian projections of SNEIGHBORS.

Page 273: Laborator Baze date

267

CardinalPoint

SEAS SNEIGHBORS COUNTRIES

ShoreKm

Figure 7.26 Equivalent E-RD of SNEIGHBORS

The associated list of restrictions fragment is the following:

J. SNEIGHBORS

d. attribute (co-)domains (ranges):

ShoreKm: [1, 999999999] (Ri)

CardinalPoint: [1, 9] (Ri+1)

e. compulsory data: Sea, Country, CardinalPoint (Ri+2)

f. uniqueness: Sea Country (it is senseless to store

more than once that a country is neighbor to a sea) (Ri+3)

7.2 Best practice rules (BAR1) Use abstraction to obtain as few object sets (with as many

elements) and attributes as possible (dually: do not inflate the concept

sets, that is db schemes, but their instances).

(BAR2) Except for very few exceptions (e.g. db parameters), all ob-

ject sets should be related to at least one other object set.

(BAR3) Object names are character strings, but objects are not! For

example, people are not born or living or getting married in character

strings, but in cities; Apple, Intel, IBM, Microsoft are not character

strings, but corporations, etc.

7.3 Homework H7.0 Design at least one translation algorithm from rdbs to:

a. Access

b. Oracle

c. any other RDBMS of your choice

Implement the rdb from figure 7.4 above, by applying at least one of them.

Page 274: Laborator Baze date

268

H7.1 Extend the data model shown in figure 7.3 above for also storing the re-

lationships between measurement units (e.g. 1TB = 1024GB = 1024 *

1024MB = 1024 * 1024 * 1024KB), as well as family of products, product

models, product serial numbers, and product compositions (out of other

products; e.g. a notebook is made out of a motherboard, several CPUs,

memory chips, a HDD, etc.). Modify accordingly your above im-

plementation (see 7.0).

H7.2 Consider the sub-universe of a university and design a rdb for it such as

to allow storing data on its faculties, departments, streams, deans, dept.

heads, professors, students, curriculums, disciplines, credits, exams, and stu-

dents exam results, by applying the algorithms for business analysis assis-

tance and for translating E-RDs and restriction lists into rdb schemes. Pro-

vide a plausible instance for this rdb.

H7.3 Finish P7.2 above. Should the restrictions list also contain non-relatio-

nal type business rules? If yes, give at least three examples of different types.

H7.4 Design forward and reverse engineering algorithms for MySQL. Apply

them for P7.1 above and a corresponding rdb of your choice.

H7.5 Prove that for any binary mathematical relation the product of its two

canonical Cartesian projections is minimally one-to-one.

H7.6 Design an equivalent RE algorithm for inferring relational schemes

from Access dbs, by using only its metacatalogue (i.e. the set of system, hid-

den MSys prefixed tables).

H7.7 Design an equivalent RE algorithm for inferring relational schemes

from Oracle dbs, by using the SQL Developer GUI.

Page 275: Laborator Baze date

269

Chapter 8. 8th Lab: Elementary mathematic db schemes

8.1 Exercises

P8.1 Consider the following student attendances to classes sub-universe

description, E-RD, and restrictions list:

Enrolled students (SSN, first, and last name) may obtain marks (between 1

and 20) when attending scheduled (week day, start and end date, room

number) classes (calendar date) of disciplines (name and between 1 and 20

credit points), held by teachers (SSN, first, and last name). Trivially, classes

may not end before starting.

SSN FName LName

STUDENTS ATTENDANCES Mark

Date CLASSES

Schedule StartH

ROOMS SCHEDULES WeekDay

EndH

RoomNo

TEACHERS COMPETENCES DISCIPLINES

SSN FName LName Discipline Credits

Fig. 8.1: E-RD of student attendances to classes’ sub-universe

Page 276: Laborator Baze date

270

Associated restrictions list:

a. Maximum cardinalities

STUDENTS: 99999 (R1)

CLASSES, ROOMS, TEACHERS, DISCIPLINES: 999 (R2)

COMPETENCES, SCHEDULES: 9999 (R3)

ATTENDANCES: 999999 (R4)

b. Ranges

SSN: [1, 999999999] (R5)

FName, LastName, Discipline: ASCII(64) (R6)

Mark, Credits: [1, 20] (R7)

Date: [1 Oct. 2010, 30 May Year(SysDate()) + 1] (R8)

RoomNo: ASCII(8) (R9)

Weekday: [1, 5] (R10)

StartH: [8, 19] (R11)

EndH: [9, 20] (R12)

c. Compulsory data

SSN, FName, LastName, Discipline, Credits, Date, RoomNo,

StartH, EndH, Weekday, Schedule (R13)

d. Uniquenesses

SSN, RoomNo, Discipline (R14)

e. Other restrictions:

“no room may accommodate more than one class simultaneously” (R15)

“classes may not end before starting” (R16)

1. Apply the algorithm for translating E-RDs and restriction lists into

(elementary) mathematical schemes.

2. Refine the above obtained math scheme, by applying the algorithm

for assisting sets, functions, and constraints design.

3. Further refine the above obtained math scheme, by applying the al-

gorithm for assisting keys discovery.

4. Apply the algorithm for translating (elementary) mathematical

schemes into relational ones and non-relational constraint lists;

Page 277: Laborator Baze date

271

provide a plausible data instance for the obtained rdb with at least

two rows per table.

Solution:

1. Obviously, the corresponding initial (elementary) mathematical

scheme is the following:

STUDENTS (The set of all enrolled students since Oct. 1st 2010)

x NAT(5), total

SSN [1, 999999999], total

FName ASCII(64), total

LName ASCII(64), total

ROOMS (The set of all available classrooms of interest)

x NAT(3), total

RoomNo ASCII(8), total

TEACHERS (The set of all teachers teaching since at least Oct. 1st 2010)

x NAT(3), total

SSN [1, 999999999], total

FName ASCII(64), total

LName ASCII(64), total

DISCIPLINES (The set of all disciplines for which, since Oct. 1st 2010, there

were enrolled students)

x NAT(3), total

Discipline ASCII(64), total

Credits [1, 20], total

COMPETENCES = (TEACHERS, DISCIPLINES) (The set of pairs <t, d> of

interest storing the fact that, since at least Oct. 1st 2010, teacher t

teaches discipline d)

x NAT(4), total

SCHEDULES = (COMPETENCES, ROOMS) (The set of pairs <c, r> of

interest storing the fact that, since at least Oct. 1st 2010, teacher t

teaches discipline d, where c = <t, d>, in room r)

x NAT(4), total

Weekday [1, 5], total

Page 278: Laborator Baze date

272

StartH [8, 19], total

EndH [9, 20], total

SchedulesC: (x SCHEDULES)(StartH(x) < EndH(x)) (as per R16)

CLASSES (The set of all scheduled classes)

x NAT(3), total

Date [1 Oct. 2010, 30 May Year(SysDate()) + 1], total

Schedule : CLASSES SCHEDULES, total

ATTENDANCES = (STUDENTS, CLASSES) (The set of all student attendan-

ces of scheduled classes)

x NAT(6), total

Mark [1, 20]

2. Here are the results of applying the design assistance algorithm for:

a. Sets

a.1 No set is semantically overloaded (so no structural refinements are ne-

eded from this point of view). Please review chapter 2, where this sub-uni-

verse modeling is discussed too contrastively, as compared to a poorer so-

lution!

a.2 No set is a subset of another set (so no inclusion constraints need to be

added to the scheme).

a.3 No association-type set has arity greater than two (so none has to be re-

placed by its equivalent entity-type set and explicit structural keys and

functions corresponding to its canonical Cartesian projections).

a.4 All binary associations are non-functional:

- COMPETENCES is not functional, because there are teachers that

may teach several disciplines, as well as disciplines that may be

taught by several teachers.

- SCHEDULES is not functional, because there are teacher competen-

ces that may be taught in several rooms, as well as rooms that may

accommodate teaching of several teacher competences.

- ATTENDANCES is not functional, because there are students attend-

ing several classes, as well as classes attended by several students.

Page 279: Laborator Baze date

273

a.5 No association-type set is ill-defined, except SCHEDULES: for example,

our db labs are held in the same room (CJ201), in the same week day (Tues-

days), but at different hours (from 8h to 10h with group 1232E and from 10h

to 12h with subgroup 1231aE); consequently, the product of its two

canonical Cartesian projections Room Competence is not one-to-one, so

this is not a mathematic relation.

As such, you should replace it by an entity-type object set (and correspond-

ingly correct the E-RD):

SCHEDULES (The set of schedule entries since Oct. 1st 2010)

x NAT(4), total

Weekday [1, 5], total

StartH [8, 19], total

EndH [9, 20], total

Room : SCHEDULES ROOMS, total

Competence : SCHEDULES COMPETENCES, total

On the contrary, COMPETENCES is well defined as Teacher Discipline is

minimally one-to-one (it would be senseless to store more than once a same

pair <t, d>) and the same goes for ATTENDANCES, as Student Class is

minimally one-to-one too (it would be senseless to store more than once a

same pair <s, c>).

a.6 No association is homogeneous (so that we need not investigate reflexi-

vity, irreflexivity, symmetry, anti-symmetry, etc.).

b. Functions

b.1 All functions are well defined:

- people (be them students or teachers) have only one SSN, first, and last

name;

- classrooms, disciplines, and classes have only one number, name, credit

points, and calendar date, respectively;

- schedule entries have only one associated week day, start, and end hour;

Page 280: Laborator Baze date

274

- finally, in this simplified model, students may get only one mark for each

attended class (e.g. the average of all ones, if several are possible).

b.2 No other function (except for the unique ones) is one-to-one:

- FName : there may be several students/teachers having same first name.

- LName : there may be several students/teachers having same last name.

- Mark : there may be several students getting same mark for a same class

(and even a same student may get a same mark for different classes).

- Date: there may be several classes scheduled in a same room, even in a

same day (but at different start/end hours)

- Weekday: there may be several classes scheduled in a same week day, even

in a same classroom (but at different start/end hours)

- StartH: there may be several classes scheduled to start at a same hour (but

in different classrooms)

- EndH: there may be several classes scheduled to end at a same hour (but in

different classrooms)

- Credits: there may be several disciplines having same number of credit

points

- Schedule: there may be several classes scheduled in a same room for a

same discipline, held by a same teacher (typically, one per week,

during a semester).

On the contrary, all those declared as one-to-one are really one-to-one:

- SSN: there may not be two persons having same SSN

- Discipline: there may not be two disciplines having same name

- RoomNo: there may not be two classrooms having same number.

Page 281: Laborator Baze date

275

b.3 No function is onto, except for Schedule:

- Schedule is onto, because for any entry in the schedule there should

be at least one corresponding class (generally, there are one per

semester week). Consequently, the following constraint has to be

added to this db scheme:

Schedule : CLASSES SCHEDULES, total, onto

- Obviously, FName, LastName, Discipline, and RoomNo are not, as

not all possible ASCII character combinations of maximum 64/8

characters should be first or last person, disciplines, or room

names/numbers.

- SSN is not either, as not all possible combination of 9 digits is an

actual SSN.

- Mark and Credits are not either, as it is not compulsory that all pos-

sible marks/credits (i.e. all naturals between 1 and 20) be granted for

student class activities or crediting disciplines, respectively.

- Date is not either, as generally there are no classes during week-ends

or holidays.

- StartH is not either, as not all possible daily hour should be an actual

class start one.

- EndH is not either, as not all possible daily hour should be an actual

class end one.

- Weekday is not either, as not all possible week days should have

scheduled classes.

b.4 There are no bijective functions.

b.5 There are no auto-functions (so that we need not investigate reflexivity,

irreflexivity, symmetry, anti-symmetry, etc.).

b.6 There are no canonical surjections (representative systems).

b.7 There are no object sets having no totally defined functions.

c. Constraints

c.1 R15 (“no room may accommodate more than one class simultaneously”),

the only not formalized constraint left (as R16 was formalized by Sche-

Page 282: Laborator Baze date

276

dulesC above) has the following formalization (no two classes may overlap

in a same week day and same room):

C15: (x,ySCHEDULES)(Weekday(x) = Weekday(y) Room(x) =

Room(y)) (StartH(y) EndH(x) StartH(x) EndH(y))

Note that C15 also implies the following key constraints:

KC15a: Weekday Room StartH key (there may not be two schedules en-

tries having same week day, room, and start hour) and its dual

KC15b: Weekday Room EndH key (there may not be two schedules en-

tries having same week day, room, and end hour)

c.2 There are other constraints that apply in this sub-universe too, but are

missing from this model: C15 (which corresponds to the non-quantum phy-

sics law “no two objects may occupy the same space in the same time”) has

an obvious dual (corresponding to the non-quantum physics law of non-ubi-

quity: “no object may simultaneously occupy two distinct space slots”), as no

student/teacher may simultaneously attend more than one scheduled class.

Consequently, the following two constraints have to be added to this math

scheme:

C16: (x,ySCHEDULES)(Weekday(x) = Weekday(y) Competence(x) =

Competence(y)) (StartH(y) EndH(x) StartH(x) EndH(y)) (“no tea-

cher may teach simultaneously in several classrooms”)

C17: (<s,c>,<s,c’>ATTENDANCES) Date(Class(c)) = Date(Class(c’))

(StartH(Class(c’) EndH(Class(c)) StartH(Class(c)) EndH( Class(c’)))

(“no student may simultaneously attend several classes”)

Obviously, just like for C15, C16 also implies the following two key con-

straints:

KC16a: Weekday Competence StartH key (there may not be two sche-

dules entries having same week day, teaching competence, and start hour)

and its dual

Page 283: Laborator Baze date

277

KC16b: Weekday Competence EndH key (there may not be two sche-

dules entries having same week day, teaching competence, and end hour).

3. Applying the assistance algorithm for keys discovery yields the follow-

ing:

STUDENTS and TEACHERS

n = 2, as there are two not one-to-one mappings defined on it, both being

non-prime in this context (FName LName is not one-to-one, as

there may be several distinct persons having same first and last

names) no other semantic key exist.

ROOMS and COMPETENCES

n = 0 no other semantic key exist.

DISCIPLINES and ATTENDANCES

n = 1 (nothing to do, as according to b.2 above, neither Credits, nor Mark are

one-to-one) no other semantic key exist.

SCHEDULES

n = 5, as there are five not one-to-one mappings defined on it, all of them

being prime (see KC15a, KC15b, KC16b, and KC16b above): Week-

day, StartH, EndH, Competence, and Room.

i = 2:

- Weekday StartH key? No, because several classes may be scheduled in a

same week day to start at a same hour.

- Weekday EndH key? No, because several classes may be scheduled in a

same week day to end at a same hour.

- Weekday Competence key? No, because several classes may be scheduled

in a same week day for a same teacher and discipline.

- Weekday Room key? No, because several classes may be scheduled in a

same week day and in a same classroom.

- StartH EndH key? No, because several classes may be scheduled (even in

a same week day) to start and end at same hours.

- StartH Competence key? No, because several classes may be scheduled to

start at a same hour for a same teaching competence (but in different

week days).

Page 284: Laborator Baze date

278

- StartH Room key? No, because several classes may be scheduled to start

at a same hour in a same classroom (but in different week days).

- EndH Competence key? No, because several classes may be scheduled to

end at a same hour for a same teaching competence (but in different

week days).

- EndH Room key? No, because several classes may be scheduled to end at

a same hour in a same classroom (but in different week days).

- Competence Room key? No, because several classes may be scheduled in

a same classroom and for same teaching competences (but either in

different week days or in a same week day, but at different start and

end hours).

i = 3:

- Weekday StartH EndH key? No, because several classes may be sche-

duled in a same week day to start and end at same hours.

- Weekday StartH Competence key? Yes, according to KC16a.

- Weekday StartH Room key? Yes, according to KC15a.

- Weekday EndH Competence key? Yes, according to KC16b.

- Weekday EndH Room key? Yes, according to KC15b.

- Weekday Competence Room key? No, because several classes may be

scheduled in a same classroom for a same teaching competence (but

at different start and end hours).

- StartH EndH Competence key? No, because several classes may be

scheduled for same start and end hours, and for a same teaching com-

petence (but in different week days).

- StartH EndH Room key? No, because several classes may be scheduled

for same start and end hours, in a same classroom (but in different

week days).

- EndH Competence Room key? No, because several classes may be

scheduled for same end hours, in a same classroom, for a same tea-

ching competence (but in different week days).

i = 4:

The only non-superkey on this level is:

StartH EndH Competence Room key? No, because several classes may

be scheduled for same start and end hours, for a same teaching com-

petence, in a same classroom (but in different week days).

Page 285: Laborator Baze date

279

CLASSES

n = 2, as there are two not one-to-one mappings defined on it, both being

prime: Date Schedule is one-to-one, as there may not be several

distinct classes having same date and schedule and, as, according to

b.2 above, neither of them is one-to-one, this product is minimally

one-to-one, so this key has to be added to the model:

KClasses: Date Schedule key (there may not be several distinct classes

having same date and schedule entry)

4. Applying the algorithm for translating (elementary) mathematical

schemes into relational ones and non-relational constraint lists yields the

following rdb (to which a small plausible instance has also been added)

and non-relational constraints list:

STUDENTS (x, SSN)

x SSN FName LName

Auton(5) [1, 999999999] ASCII(64) ASCII(64)

NOT NULL NOT NULL NOT NULL NOT NULL

1 123456789 Ion Popescu

2 987654321 Pop Ionescu

TEACHERS (x, SSN)

x SSN FName LName

Auton(3) [1, 999999999] ASCII(64) ASCII(64)

NOT NULL NOT NULL NOT NULL NOT NULL

1 135792468 Dumitru Georgescu

2 975318642 George Dumitrescu

DISCIPLINES (x, Discipline)

x Discipline Credits

Auton(3) ASCII(64) [1, 20]

NOT

NULL

NOT

NULL

NOT

NULL

1 Algebra 12

2 Logic 16

ROOMS (x, RoomNo)

x RoomNo

Auton(3) ASCII(8)

NOT NULL NOT NULL

1 CB105

2 CJ201

Page 286: Laborator Baze date

280

COMPETENCES (x, Teacher Discipline)

x Teacher Discipline

Auton(3) Im(TEACHERS.x) Im(DISCIPLINES.x)

NOT NULL NOT NULL NOT NULL

1 2 1

2 1 2

SCHEDULES (x, Weekday StartH Competence, Weekday EndH

Competence, Weekday StartH Room, Weekday EndH Room)

StartH < EndH

x Competence Room Week-

day

StartH EndH

Auton(4) Im(COMPETEN-

CES.x)

Im(ROOMS.x) [1, 5] [8, 19] [9, 20]

NOT

NULL

NOT NULL NOT NULL NOT

NULL

NOT

NULL

NOT

NULL

1 1 1 1 10 12

2 1 2 2 8 10

CLASSES (x, Date Schedule)

x Schedule Date

Auton(3) Im(SCHEDULES.x) [1 Oct. 2010, 30 May Year(SysDate())

+ 1]

NOT NULL NOT NULL NOT NULL

1 1 Oct. 7, 2013

2 1 Oct. 14, 2013

ATTENDANCES (x, Student Class)

x Student Class Mark

Auton(6) Im(STUDENTS.x) Im(CLASSES.x) [1, 20]

NOT NULL NOT NULL NOT NULL

1 1 1

2 1 2 20

Page 287: Laborator Baze date

281

The associated non-relational constraints list is the following:

C15: (x,ySCHEDULES)(Weekday(x) = Weekday(y) Room(x) =

Room(y)) (StartH(y) EndH(x) StartH(x) EndH(y))

C16: (x,ySCHEDULES)(Weekday(x) = Weekday(y) Competence(x) =

Competence(y)) (StartH(y) EndH(x) StartH(x) EndH(y))

C17: (<s,c>,<s,c’>ATTENDANCES) Date(Class(c)) = Date(Class(c’))

(StartH(Class(c’) EndH(Class(c)) StartH(Class(c)) EndH(Class(c’)))

C18: Schedule : CLASSES SCHEDULES, onto

8.2 Best practice rules

8.3 Homework H8.1 Modify the above model on all three levels (E-R, mathematical, and re-

lational) accordingly, such as to:

a. abstract a single PERSONS set instead of STUDENTS and TEACHERS

b. consider that some classes may not be hold weekly, but only once in every

two weeks, either in the odd or in the even ones

c. consider that students may get several marks for any class, but only one

per type (e.g. homework, test, etc.)

d. add buildings, campuses, classroom types (e.g. computer science, physics,

chemistry, etc.), and teacher availabilities (per odd/even/weekly days and

time intervals)

e. implement the above obtained rdb by using a RDBMS version of your

choice.

H8.2 Design and develop (in any high level programming language you

choose) a software application based on the above db for managing it (which

includes enforcing of all non-relational constraints), as well as for assisting

class scheduling.

Page 288: Laborator Baze date

282

Chapter 9. 9th Lab: Analyzing E-RD cycles

9.1 Exercises

Consider the GeografieBD / GeographyDB db.

P9.1 Analyze the following autofunctions:

a. SuperSea : SEAS SEAS27

(y = SuperSea(x) means that sea y includes

sea x; for example, the Ionic, Adriatic, Aegean, etc. seas are included in the

Mediterranean one)

b. OrbitCenter : ASTRONOMIC_BODIES ASTRONOMIC_BODIES28

(y

= OrbitCenter(x) means that astronomic body y orbits around astronomic bo-

dy x; for example, all 67 Jupiter’s moons are orbiting around it, while it or-

bits around the Sun, which orbits around the center of the Milky Way, which

is the supermassive black hole called Sagittarius A, etc.)

Solution:

a. SuperSea

The corresponding E-RD cycle is shown in figure 9.1:

SEAS SuperSea

Figure 9.1: E-RD of the autofunction SuperSea : SEAS SEAS

Obviously, SuperSea models a tree-like hierarchy of seas, so it should be

acyclic29

: no sea may be included in itself, neither directly or indirectly

the SuperSea acyclic constraint has to be added to the corresponding db

scheme.

b. OrbitCenter

The corresponding E-RD cycle is shown in figure 9.2:

27

SuperMare : MARI MARI in the Romanian version. 28

CentruOrbita : CORPURI_CERESTI CORPURI_CERESTI in the Romanian version. 29

Which obviously means (see homework H6.1 and H6.2) that SuperSea is also irreflexive,

anti-symmetric, anti-transitive, and anti-idempotent.

Page 289: Laborator Baze date

283

ASTRONOMIC_BODIES OrbitCenter

Figure 9.2: E-RD of the autofunction OrbitCenter : ASTRONOMIC_BODIES

ASTRONOMIC_BODIES

As there are, for example, binary star systems (in which each star is orbiting

around the other: for example, in the binary system J0806, situated at about

1,600 light-years away from Earth, two white dwarf stars orbit one another e-

very 321 seconds), this autofunction does not model a tree-like hierarchy (i.e.

cycles in the OrbitCenter ‘s graph are not only possible, but cannot be pre-

vented without loss of information).

- reflexive? No, as, trivially, no astronomic body may orbit around itself.

- irreflexive? Yes, as such implausibilities should be banned from db storing

the OrbitCenter irreflexive constraint has to be added to the cor-

responding db scheme.

- symmetric? No, as there are, for example, planets (e.g. Earth) orbiting

around stars (e.g. Sun) that are not orbiting around their planets.

- anti-symmetric? No, as there are, for example, binary star systems (in

which each star is orbiting around the other).

- transitive? Yes, physically: as we’ve already seen above, any astronomic

body x orbiting around y that is orbiting round z is also orbiting

around z; but, as this information is computable (moreover, even

easily), it should not be stored (especially as there are myriads of

celestial bodies and the corresponding transitive closure would take a

tremendous amount of disk storage).

- anti-transitive? Yes, see transitivity above why the OrbitCenter anti-

transitive constraint has to be added to the corresponding db scheme.

P9.2 Analyze the following homogeneous binary association: DISTANCES =

(CITIES, ALL_CITIES)30

(where ALL_CITIES is a synonym for CITIES:

ALL_CITIES = CITIES) (The set of interesting pairs <c, c’> storing the aerial

minimum distance, in km, between cities c and c’).

Solution:

The corresponding E-RD cycle is shown in figure 9.3:

30

DISTANTE = (LOCALITATI, TOATE_LOCALITATILE) in the Romanian version.

Page 290: Laborator Baze date

284

DISTANCES

CITIES

Figure 9.3: E-RD of the homogeneous binary association DISTANCES

- reflexive? No, although, trivially, the distance between any city and itself is

perfectly defined and always 0 km, but this is computable, so there is

no need to store it.

- irreflexive? Yes, as such trivialities should be banned from db storing

the DISTANCES irreflexive constraint has to be added to the corres-

ponding db scheme.

- symmetric? No, although, trivially, the distance between any two cities is

perfectly defined in both ways and corresponding values are always

equal between them, but, once one of them is stored, the other

(symmetric) one is (very easily!) computable, so there is no need to

store it too.

- anti-symmetric? Yes, as, generally, computable data should be banned from

db storing the DISTANCES anti-symmetric constraint has to be

added to the corresponding db scheme.

- transitive? It depends, as, obviously, on one hand, given distances between

any two pairs of cities <x, y> and <y, z>, the distance between x and z

is perfectly defined (and one possible value for it, not necessarily the

minimum one, is, trivially, the sum of them); on the other, the

following three implementation solution types are possible, each of

them with its advantages and disadvantages:

as even if not that easy (because all existing paths between two cities

have to be discovered, their corresponding distances computed, and

the minimum one of them chosen, which is an instance of the well-

known problem of finding the least expensive path between two

nodes in a weighted graph), computing minimum distances between x

and z is always possible, so it should be banned from db storing; ob-

viously, this means that a DISTANCES anti-transitive constraint has

to be added to the corresponding db scheme and that the db size is

kept to the minimum, but both updating (because of the overhead for

enforcing this constraint) and querying data are slowed down;

in order to speedup querying (at the expense of a larger db size, but

not that important), we might dually opt for enforcing the DISTAN-

CES transitive constraint instead: of course that this should be tran-

sparent to users, as it can be automatically done by the application

managing the db (at each insertion of a new pair, update of an exist-

Page 291: Laborator Baze date

285

ing distance, and deletion of an existing pair, an intelligent algorithm

may automatically insert new corresponding pairs or delete existing

ones, in order to keep the graph transitive, as well as automatically

update computed distances; note that this imply also storing, for each

pair, a computed Boolean indicating whether or not the pair is a cal-

culated one or not and preventing users from deleting computed pairs

or updating their elements; on the contrary, users should have the

right to update computed distances, which, trivially, should trigger

changing the corresponding status of the corresponding pairs from

“computed” to “fundamental” and re-computing all other involved

computed distances); obviously, the overhead for enforcing this con-

straint is more expensive than for its above dual one;

a mixed solution is also possible and is, most probably, the best: none

of the above two constraints is enforced, i.e. users may store both

computable and not computable pairs; querying is first searching for

an existing stored pair and is computing desired value (when possi-

ble!) only when such data is not stored; this type of solution obvious-

ly is a compromise between the above two ones, as db size is larger,

but not as large as in the previous case, querying time is faster than in

the first case, but not that fast as in the second, and there is no con-

straint enforcing overhead; if db size is not a concern (which, gene-

rally, should not be the case for such a table), but querying speed is

(which is almost the rule), this solution might be greatly improved by

running after updates, during idle periods (e.g. night-time, week-

ends), a program for computing the transitive closure of this graph, as

well as corresponding minimum distances (but without any distinc-

tions between “fundamental” and “computed” pairs and no constraint

whatsoever on users’ rights on computed data).

P9.3 Analyze the following conventional commutative-type cycles:

a. Region : STATES REGIONS,31

StateCapital : STATES CI-

TIES,32

and RegionCapital : REGIONS CITIES.33

b. Country : ISLANDS COUNTRIES,34

and ISLANDS_SHARING =

(ISLANDS, COUNTRIES)35

, where Country : ISLANDS COUN-

TRIES stores the country which owns the whole island or the majori-

ty part of it.

31

Regiune : JUDETE REGIUNI in the Romanian version. 32

Capitala : REGIUNI LOCALITATI in the Romanian version. 33

Resedinta : JUDETE LOCALITATI in the Romanian version. 34

Tara : INSULE TARI in the Romanian version. 35

OCUPARE_INSULE = (INSULE, TARI) in the Romanian version.

Page 292: Laborator Baze date

286

c. Continent : STATES CONTINENTS,36

Country : STATES

COUNTRIES,37

and Continent: COUNTRIES CONTINENTS.38

Solution:

a. The corresponding E-RD cycle is shown in figure 9.4:

REGIONS

Region RegionCapital

STATES CITIES

StateCapital

Figure 9.4: E-RD of a (conventional) commutative-type function diagram

Obviously, the associated commutativity problem is RegionCapital Region

?= StateCapital, that is “should any state capital also be the capital of the re-

gion to which that state belongs (if any)?”.

Trivially, this is not the case, as, on one hand, regions are generally

made out of several states (and there is only one region capital) and, on the

other, region capitals are not always state capitals too. Consequently, this

diagram should not commute.

The associated anti-commutative problem is (xSTATES)(Region-

Capital Region(x) ? StateCapital(x)), that is “should never a state capital

also be the capital of the region to which that state belongs (if any)?”.

Trivially too, this is not the case either, as (in fact, very often) region

capitals are also state capitals.

Consequently, this cycle is uninteresting, as it should not either com-

mute or anti-commute: no constraints are involved.

b. The corresponding E-RD cycle is shown in figure 9.5:

Country Island

COUNTRIES ISLANDS_SHARING ISLANDS

Country

Figure 9.5: E-RD of a (conventional) commutative-type function diagram

36

No such function exists in the dbs (neither in the English Oracle one, nor in the Romanian

Access one, for reasons that are explained in the solution of this exercise). 37

Tara : JUDETE TARI in the Romanian version. 38

Continent : TARI CONTINENTE in the Romanian version.

Page 293: Laborator Baze date

287

Obviously, the associated commutativity problem is Country Island ?=

Country (where Country : ISLANDS_SHARING COUNTRIES and Island

: ISLANDS_SHARING ISLANDS are the canonical Cartesian projections

of ISLANDS_SHARING), that is “should any country (also) sharing an island

be the one that owns the whole island or the majority part of it?”.

Trivially, this is not the case, as there are islands shared by several

countries (e.g. Ireland, split between the Irish Republic, owning more than

three quarters of it, and the U.K., owning its Northern Ireland).

The associated anti-commutative problem is (xISLANDS_SHAR-

ING)(Country Island(x) ? Country(x)), that is “should never a country that

owns the whole island or the majority part of it also be stored as sharing a

part of it?”.

Trivially, this is the case, as no same data should be stored more

than once in a db.

Consequently, this diagram should anti-commute and the corres-

ponding (xISLANDS_SHARING)(Country Island(x) Country(x)) con-

straint should be added to the db scheme.

c. The corresponding E-RD cycle is shown in figure 9.6:

CONTINENTS

Continent Continent

STATES COUNTRIES

Country

Figure 9.6: E-RD of a (conventional) commutative-type function diagram

Obviously, the associated commutativity problem is Continent Country ?=

Continent, that is “should any state belong to the continent to which belongs

the country to which that state belongs?”.

Trivially, this should always be the case: this diagram conventionally

commutes (that is Continent Country = Continent). But, as Continent :

STATES CONTINENTS is computable from the other two functions, the

best data modeling solution is to eliminate it from the db scheme, thus break-

ing this cycle.39

39

Obviously, if querying speed is a concern, as this data is almost static once entered and as

additional disk space is not that important, a computed function *Continent = Continent

Continent Country might be added to the db for storing in STATES corresponding conti-

nent names (provided that it is implemented as a controlled data redundancy: either invisible

or read-only for users, and immediately re-computed by the managing applications or

RDBMS triggers whenever involved data is updated).

Page 294: Laborator Baze date

288

P9.4 Analyze the following unidirectional cycle: State : CITIES

STATES,40

Region : STATES REGIONS, and RegionCapital : REGIONS

CITIES.

Solution:

The corresponding E-RD cycle is shown in figure 9.7:

REGIONS 1REGIONS

Region RegionCapital

1STATES STATES CITIES 1CITIES

State

Figure 9.7: E-RD of a unidirectional (local commutative-type) function

diagram

Trivially, as this cycle has three nodes, we have to investigate all correspond-

ing three possible local commutativities:

1. RegionCapital Region State ?= 1CITIES (should any city be the capital

of the region from which makes part the state to which the city belongs?)

Obviously, this is not possible, as regions include several states, each

one having several cities, whereas they only have one capital.

2. Region State RegionCapital?= 1REGIONS (should the capital of any re-

gion belong to a state belonging to that region?)

Obviously this is true, as no region may have as its capital a city be-

longing to another region (dually, all region capitals belong to the corres-

ponding regions).

Consequently, the corresponding local commutativity constraint Re-

gion State RegionCapital = 1REGIONS should be added to this db scheme.

3. State RegionCapital Region ?= 1STATES (should any state include the ca-

pital of the region to which belongs?)

Obviously no, as there is only one region capital per region and as

any city belongs to only one state.

P9.5 Analyze the following cycle: Ocean : HARBORS CONTINENTS,41

City : HARBORS CITIES,42

State : CITIES STATES, Country :

NEIGHBORSOC COUNTRIES,43

Ocean : NEIGHBORSOC CONTI-

40

Judet : LOCALITATI JUDETE in the Romanian version. 41

Ocean : PORTURI_OCEANICE CONTINENTE in the Romanian version. 42

Localitate : PORTURI_OCEANICE LOCALITATI in the Romanian version. 43

Tara : VECINATATIOT TARI in the Romanian version.

Page 295: Laborator Baze date

289

NENTS44

, where NEIGHBORSOC is the set of interesting pairs of the form

<o,c> storing the fact that country c is neighbor to ocean o (note that CONTI-

NENTS ‘ instance is partitioned into two blocks by the values of its Boolean

function Ocean?: (land) continents and oceans (“water continents”)), where

Country : NEIGHBORSOC COUNTRIES and Ocean : NEIGHBORSOC

CONTINENTS are the canonical Cartesian projections of NEIGH-

BORSOC.

Solution:

The corresponding E-RD cycle is shown in figure 9.8:

Ocean

CONTINENTS HARBORS

Ocean City

NEIGHBORSOC CITIES

Country State

COUNTRIES STATES

Country

Figure 9.8: E-RD of a (generalized commutative-type) function diagram

The cycle has two source (HARBORS and NEIGHBORSOC) and two desti-

nation (CONTINENTS and COUNTRIES) nodes, so it is of the third type.

Let us consider any two elements of its sources: h HARBORS and n

NEIGHBORSOC; the (generalized commutativity) question is: in what cir-

cumstances should Ocean(h) = Ocean(n) and/or Country(n) = Country(State(

City(h)))?

Obviously, in order for a country to have an oceanic harbor, it has to be

neighbor to the corresponding ocean, which means that, for any harbor h,

there always should be a pair n such that both above equalities hold; conse-

quently, this diagram has the following generalized commutativity that

should be added to the db scheme:

OceanHarborsConstraint: (hHARBORS)(nNEIGHBORSOC)(Ocean(

h) = Ocean(n) Country(n) = Country State City(h)).

44

Ocean : VECINATATIOT CONTINENTE in the Romanian version.

Page 296: Laborator Baze date

290

9.2 Best practice rules 0. Do not ignore, but enforce any existing constraint of the modeled sub-

universe (as not enforcing it allows storing implausible data).

1. Do not enforce any constraint that does not apply to the modeled sub-

universe (as enforcing it prevents from storing plausible data).

2. When enforcing both an existing constraint P or its dual not P (anti-P)

is possible, always choose the best alternative from the users’ point of

view (which is, generally, best possible overall db application speed); some-

times, especially when it is possible to run additional programs during idle

periods (e.g. computing transitive closures), the best solution is to not en-

force either of them.

3. For any autofunction f or homogeneous binary association (math

relation) r that model a tree-like hierarchy, add constraint f / r acyclic to

the corresponding db scheme.

4. For acyclic autofunction or homogeneous binary association (or math

relation) corresponding irreflexivity, anti-symmetry, anti-transitivity,

and/or anti-idempotency should not also be added to the db scheme, as

they are all implied by acyclicity.

5. Generally, do not add to your db scheme any implied constraint.

6. For any autofunction or homogeneous binary association (or math

relation) that are not acyclic, corresponding reflexivity, irreflexivity,

symmetry, anti-symmetry, transitivity, anti-transitivity, idempotency,

and/or anti-idempotency should be investigated.

7. Trivially, if any object set has a constraint P, then it cannot also have con-

straint not P (anti-P); consequently, if P was discovered, not P should not

be investigated anymore.

8. Do not store in dbs computable data; if storing it might significantly

help (for increasing overall processing speed), then store it as a controlled

redundancy (i.e. read-only for users and automatically re-computed imme-

diately after its value changed).

9. Do not allow storing same data more than once in a same db.

Page 297: Laborator Baze date

291

10. Whenever an E-RD function diagram should commute and one of

the involved functions is computable out of all others, break the corres-

ponding cycle by eliminating from your model the computable one.45

11. Whenever a commutative-type function diagram is not commutative,

you should investigate whether or not it should anti-commute.

12. For any unidirectional E-RD cycle, you should look for possible local

commutativities in all of its nodes.

13. Do not ignore any E-RD cycle: they have to be declared uninterest-

ing (constraint free) only after thorough investigations, done according

to the algorithm for assisting E-RD cycles analysis.

9.3 Homework H9.1 Using the algorithm for assisting E-RD cycles analysis, discover and

analyze all the

a. remaining cycles of the GeografieBD / GeographyDB db;

b. cycles in all remaining examples from both chapter 2, as well as pre-

vious lectures and labs.

45

Obviously, when significant faster processing speed is possible and critical, controlled re-

dundancy might be used in such cases too – see the eighth best practice rule above.

Page 298: Laborator Baze date

292

Chapter 10. 10th Lab: Enforcing non-relational constraints Recall that RDBMSs are generally providing only the following 5 types of

(relational) constraints:

1. (co-)domain (range)

2. NOT NULL (mandatory, required) (totality)

3. Keys (uniqueness) (minimal one-to-oneness)

4. Foreign keys (referential integrity) (typed inclusion dependencies)

5. Tuple (check)

All other constraint types have to be enforced either by extended SQL trig-

gers or/and by event-driven high-level programming (generally, embedding

SQL) methods.

10.1 Prerequisites in Access: Forms and Event-Driven Methods Natively, Access does not provide extended SQL: only programmatically,

through ADO, may triggers (more generally, stored procedures and func-

tions) be declared and used, which, unfortunately, is very difficult to main-

tain and debug.

Fortunately, Access provides an event-driven embedding SQL high-level pro-

gramming language called VBA (Visual Basic for Applications), as well as

(Windows) forms and a reports generator.

Forms and reports are bi-dimensional objects, to which data sources (tables

or queries) may be attached, made out of a GUI and an associated VBA class.

The GUI mainly displays and allows users to modify data, but also provides

menus, (linked) sub-forms/reports, buttons, etc. Associated VBA classes pro-

vide both event-driven and ordinary methods (subroutines and functions) that

are used for enforcing constraints, performing calculations, implementing

business logic, etc.

For example, in order to create a datasheet type form on the COUNTRIES ta-

ble from our lab db containing all of its columns, click on the Form Wizard

icon from the Create ribbon tab, then select table COUNTRIES (see figure

10.1), then click on the “>>” button to select all columns (see figure 10.2),

then on Next; then click on the Datasheet radio button (see figure 10.3), click

on Next, and finally on Finish (see figure 10.4).

Page 299: Laborator Baze date

293

Figure 10.1 Selecting the data source of an Access form

Figure 10.2 Selecting the columns from the data source of an Access form

Page 300: Laborator Baze date

294

Figure 10.3 Selecting the GUI type of a standard Access form

Figure 10.4 Naming, saving, and opening of a newly created Access form

Page 301: Laborator Baze date

295

Figure 10.5 shows the newly created form COUNTRIES:

Figure 10.5 The COUNTRIES datasheet form

10.1.1 Forms/reports GUI: controls and properties

From the GUI point of view, forms and reports are collections of controls of

various types, having lot of attached properties. The most used control types

are the labels, text, list, and check boxes, sub-forms/reports, tabs, buttons

(both ordinary and radio), charts, hyperlinks, lines, rectangles, images, and

attachments. Figure 10.6 shows the design view of form COUNTRIES.

Properties are partitioned into four categories: data, event, format, and other.

As usual, the implicit property of any control is its value. Forms and reports

themselves have associated properties, just like their controls. From the data

events point of view, db instance rows are associated to forms/reports,

whereas their cells (corresponding column values for the current row) are

associated to controls.

Data properties include the db table/column (data source), table-type proper-

ties (e.g. default values, validation rules and texts, combo boxes lookup ones,

input masks, etc.)46

, concurrency access locking type (current record, all re-

cords, none), access rights (read-only, insert, update, delete, filtering), filters,

ordering, etc. Figure 10.7 shows the data properties of the COUNTRIES

form; for getting properties, right-click on the upper-left corner of the form.

46

generally the same as those of the corresponding tables, but not necessarily, case in which

they take precedence over table ones

Page 302: Laborator Baze date

296

Figure 10.6 The COUNTRIES datasheet form design view

Figure 10.7 The COUNTRIES form data properties

Page 303: Laborator Baze date

297

In order to make a (generally, computed, but not only) column read-only, set

(either statically or programmatically) its data Locked property to Yes.

Format properties include visibility (i.e. controls may be hidden), fonts, si-

zes, colors, alignments, special effects, etc.

Other properties include control names and captions, control tips and status

bar texts, popup, modal, menu bars, help files, etc.

Event properties store associated event procedures or embedded macros

handlers. Event chaining should be mastered; for example, the most usual

chain is form/report open, data load, followed by a loop of cursor positioning

on the current rows, an inner loop for the current controls, associated key-

board and mouse events, before and after control (cell) data in-

sert/update/delete, end of controls loop, before and after form (row) data in-

sert/update/delete, end of rows loop, data unload, and form/open close.

Event types are specific to control types. Figure 10.8 shows how to attach an

event-driven procedure to the On Current event of form COUNTRIES.

Figure 10.8 Attaching an event procedure to the COUNTRIES form

Page 304: Laborator Baze date

298

The most important and frequently used event types are the following:

10.1.1.1 Forms/reports associated event types

1. Open

Occurs whenever form/report opening is asked for, either through GUI or

programmatically (more precisely, when the corresponding object is instan-

tiated).

Can be cancelled.

Used mainly for denying opening or passing parameters, dynamically speci-

fying associated data source, filtering, and/or sorting.

2. Load

Occurs whenever forms/reports successfully open and have associated data

to load.

Cannot be cancelled.

Used mainly for filtering and sorting the data source and giving dynamically

computed titles to reports.

3. Current (Row)

Occurs whenever the cursor arrives on another data source row.

Cannot be cancelled.

Used mainly for storing initial row data into memory variables.

4. Before Insert

Occurs whenever user types for the first time something in a data control and

the current row is the new, blank one.

Can be cancelled.

Used mainly for dynamically rejecting undesired inserts into the data source.

Page 305: Laborator Baze date

299

5. After Insert

Occurs whenever a new row is appended in virtual memory to the data

source.

Cannot be cancelled.

Used mainly for retrieving corresponding auto-number value just generated

for the newly inserted row.

6. Before Update

Occurs whenever user modified at least one control data and asks for saving

current row values into the db (either explicitly, through GUI or programma-

tically, or implicitly, by trying to leave the current row).

Can be cancelled.

Used mainly for enforcing non-relational constraints involving at least two

columns of the data source.

7. After Update

Occurs whenever saving current row values into the db finished successfully.

Cannot be cancelled.

Used mainly for re-computing data sources, combo boxes, and programmati-

cally computed controls, as well as for any other data synchronizations bet-

ween simultaneously opened forms.

8. Delete

Occurs whenever user asks (either through GUI or programmatically) dele-

tion of the current row (or several selected rows).

Can be cancelled.

Used mainly for asking users context-sensitive deletion confirmations,

checking whether or not deletion is relationally possible (i.e. no referential

integrity would be violated), displaying corresponding context-sensitive error

messages when not, and enforcing non-relation constraints.

Page 306: Laborator Baze date

300

9. Before Delete Confirmation

Occurs whenever deletion request was not canceled by the Delete event (see

8 above).

Can be cancelled.

Used mainly for asking Access not to ask for user’s delete confirmation

(when this was already done by the Delete event).

10. After Delete Confirmation

Occurs whenever Access finishes to process a row(s) delete request.

Cannot be cancelled.

Used mainly for finding out whether or not the row(s) were actually deleted

and, in the affirmative case, for re-computing data sources, combo boxes,

and programmatically computed controls, as well as for any other data syn-

chronizations between simultaneously opened forms.

11. Click / Double-click

Occurs whenever user is clicking/double-clicking anywhere on the form, ex-

cept for its controls.

Can be cancelled for Double-Click, but cannot for Click.

Used mainly for triggering methods (for data synchronization, navigation,

etc.) in datasheet (tabular) forms (because buttons cannot be placed on them)

or rejecting corresponding request (for Double-Click).

12. Error

Occurs whenever a run-time error occurs.

Cannot be cancelled.

Used mainly for distinguishing between different possible causes of an error

(e.g. between different keys that would have been violated, as Access is only

indicating that a key violation was rejected, but not exactly for which key),

Page 307: Laborator Baze date

301

for managing errors, and/or for replacing context-independent standard sys-

tem errors with context-dependent ones.

13. No Report Data

Occurs whenever the data source of a report is an empty set.

Can be cancelled.

Used mainly for denying empty report preview/print.

14. Close

Occurs whenever form/report closing is asked for, either through GUI or pro-

grammatically.

Can be cancelled.

Used mainly for denying closing or asking a request confirmation.

10.1.1.2 Controls associated event types

1. Enter

Occurs whenever the cursor arrives on another control.

Cannot be cancelled.

Used mainly for storing initial control data into a memory variable.

2. Before Update

Occurs whenever user modified corresponding control data and tries to move

to another control of the same form/report or to another source data row.

Can be cancelled.

Used mainly for enforcing non-relational constraints involving correspond-

ing column of the data source.

3. After Update

Occurs whenever saving current control value into the virtual memory buffer

associated to the current row finished successfully.

Page 308: Laborator Baze date

302

Cannot be cancelled.

Used mainly for re-computing data sources, combo boxes, and programmati-

cally computed controls, as well as for any other data synchronizations bet-

ween simultaneously opened forms.

4. Click and Double-Click

Occurs whenever user is clicking/double-clicking on the corresponding con-

trol.

Can be cancelled for Double-Click, but cannot for Click.

Used mainly for triggering methods (for data synchronization, navigation,

etc.) or rejecting corresponding request (for Double-Click).

10.1.1.3 Combo boxes associated Not In List event type

Occurs whenever the associated Limit to List property has the value Yes and

user is entering in the corresponding control another value than the ones pro-

vided by the combo box values set.

Cannot be cancelled.

Used mainly for dynamically accepting new values in the corresponding

combo box and saving them into the db.

10.1.1.4 Invisible properties

Besides the above four property categories that are visible through the forms/

reports GUI, there also exists invisible control properties.

One of the most frequently used such property is the OldValue one, which

stores the initial value of any data bounded control (the one still stored in the

db during updates, up to after saving into the db the newly updated corres-

ponding ones).

Another one, also heavily used, is the NewRecord one, which is associated

only to forms that have associated data sources and which is True only when

the current row is the distinguished blank one (used for adding new rows to

the current data source instance) and False otherwise.

Page 309: Laborator Baze date

303

10.1.2 Forms/reports VBA classes: event-driven and ordinary methods

Only the VBA classes that are attached to forms or reports (and which have

names of the type Form_formName or Report_reportName, respectively)

may contain event-driven methods; such methods should have names of the

form Form_eventTypeName, Report_eventTypeName, or controlName_e-

ventTypeName, respectively; they are automatically launched whenever a

corresponding event occurs, but they may be called by any method too, just

like the ordinary ones; no other method is launched automatically. All event-

driven methods are of subroutine type. Some have no parameter, others have

input, output, and/or input-output ones. Ordinary methods47

may also be

functions.

10.1.2.1 The Cancel parameter of event-driven methods

Methods corresponding to event types that are cancelable have a distin-

guished Cancel integer (but used as Boolean) input-output parameter; when

such a method is automatically launched, the system is passing False as its

value; when the method ends and relinquishes control to the system, if Can-

cel remained False then the system goes on with normal processing of the

current event; otherwise, the current event is aborted and, moreover, the form

/report cursor is blocked in the current control and on the current data source

row. Consequently, assigning True to Cancel is the only way to deny form/

report opening/closing and reject undesired inserts/deletes/updates.

Here are the corresponding methods: Form_Open, Form_BeforeInsert, Form

_BeforeUpdate, Form_Delete, Form_BeforeDelConfirm, Form_DblClick,

controlName_DblClick, controlName_BeforeInsert, controlName_BeforeUp-

date, Report_NoData, Form_Close.

10.1.2.2 Other parameters of event-driven methods

Obviously, signatures of event-driven methods should match exactly corres-

ponding system’s requirements. The best thing to do is to always let Access

automatically generate such signatures.

Here are the names, types, contexts, semantics, and most used values of the

rest of the event-driven methods’ parameters:

47

Classes not associated to forms or controls, as well as modules (libraries) only contain or-

dinary methods.

Page 310: Laborator Baze date

304

1. Response As Integer

Type: Output

Most frequently used values:

- acDataErrContinue: for event cancelling (in comboBoxName_NotIn-

List rejects adding NewEntry in the combo box’s instance; in Form_

BeforeDelConfirm cancels system deletion confirmation message dis-

play; in Form_ Error cancels current error)

- acDataErrAdded: accepts adding NewEntry in the combo box’s in-

stance (in comboBoxName_NotInList)

2. Status As Integer

Type: Input

Most frequently used value: acDeleteOK, which signals that at least

one row has been deleted from the data source (in Form_AfterDel-

Confirm)

3. NewData As String

Type: Input

Values: entered by user in the corresponding combo box and which

does not belong to the combo box’s instance (in comboBoxName_

NotInList)

4. DataErr As Integer

Type: Input

Values: corresponding system error codes (in Forms_Error).

10.1.3 VBA programming techniques and tips

The VBA environment can be opened by typing Alt+F11. Variables are de-

clared just like in the legacy programming language Basic, with the Dim(en-

sion) keyword. Comments are introduced by an apostrophe and displayed in

green; keywords are displayed in blue; the rest of the correct code is dis-

played in black; erroneous code is displayed in red. To continue code on ano-

ther line, finish the current one with “ _” (a space followed by an under-

score); comments cannot be continued. VBA is not case sensitive; tip: always

write in lower case; if your code is correct, when you finish your line, the

system will automatically change in blue all recognized keywords and to up-

percase all db object, class, constant, variable, method, etc. referenced

names’ letters, as per their corresponding definitions.

Page 311: Laborator Baze date

305

10.1.3.0 Methods and variables scope

Procedures and variables that are declared with the keyword Private or

without any scope keyword are known only locally, in the corresponding

class or library (module); those declared with the keyword Public are known

to all classes and modules.

10.1.3.1 The Variant data type

The distinguished data type Variant can accommodate any value type and is

the only one that can store nulls too. Consequently, you can actually work

only with variant variables, which is, however, highly unadvisable, as it

takes lot of memory and significantly slows down the interpretation speed;

only use it temporarily when nulls are possible; then, any not value should be

moved to a correspondingly typed variable.

Note that any non-declared variable is assigned the Variant type and that the

default operating mode of the VBA environment in this respect is not to re-

quire variable declarations. As a best practice rule, do not forget to turn this

feature on for every project since the beginning: click on the Tools menu op-

tion, then on Options from the corresponding sub-menu, on Require Variable

Declaration check-box, and, finally on the OK button of the Options window

(see figure 10.9).

Figure 10.9 Turning on the Require Variable Declaration VBA option

Page 312: Laborator Baze date

306

10.1.3.2 The programming errors system

The programming errors system is not activated by default; except for excep-

tional cases (to be introduced below), you should activate it explicitly at the

beginning of any method and immediately after you don’t need it to be sus-

pended anymore (in the exceptional cases) with the statement On Error

GoTo err_point, where err_point should be the label of an errors pro-

cessing section of the method (generally, the last one, which has to be prece-

ded by an Exit Sub/Function statement and should contain at least, for

displaying the errors’ messages, the following statement: MsgBox Err.

Source & "->" & Err.Description, vbCritical, "Error

in method currentMethodName of class currentClass-

Name..."). Figure 10.10 shows the VBA class associated to form COUN-

TRIES, after adding the error system to the Form_Current method.

Figure 10.10 The VBA programming environment

Note that the error object Err is a stack of occurred runtime error codes

whose implicit property is the code of the most recently encountered error;

its Source property contains the name of the processor that discovered the er-

ror (e.g. the SQL engine, ADO, the VBA interpreter, etc.); its Description pro-

perty contains the corresponding error description. The assignment Err = 0

pops the stack. The stack is empty when Err = 0.

Page 313: Laborator Baze date

307

You can ignore all errors immediately after executing On Error Resume

Next and up to the next On Error GoTo in the sequence or the end of

the method. Use Resume Next in the exceptional cases when browsing

object collections (e.g. open tables, queries forms, reports, etc.) to decide

whether or not a particular object is opened or not.

10.1.3.3 Message and input boxes

You can display messages by using the statement or function MsgBox (see

the example above for displaying error messages); both of them have the fol-

lowing three parameters, in this order:48

- a text to be displayed in the center of the message box;

- a numeric code for the icons and buttons to be displayed in the upper left

corner of the message box and below the above test, respectively;

- a text to be displayed in the title of the message box (if you don’t provide it,

“Microsoft Access” is displayed as title).

Note that you always should use system predefined constants for the numeric

code; for example, vbQuestion + vbOkCancel + vbDefault-

Button2 asks for displaying the question mark icon, an Ok button, and a

Cancel default one.

A best practice programming rule is to always consistently use icons as fol-

lows (note that displaying an icon is not mandatory):

- vbQuestion for questions

- vbCritical for critical errors

- vbExclamation for warnings (not critical errors)

- vbInfo for all other information.

You have the following seven possible button combinations:

- vbOkOnly or no button constant Ok

- vbMsgBoxHelpButton Ok and Help

- vbOkCancel Ok and Cancel

48

Actually, there are other two parameters as well for specifying associated custom help and

context.

Page 314: Laborator Baze date

308

- vbRetryCancel Retry and Cancel

- vbYesNo Yes and No

- vbYesNoCancel Yes, No, and Cancel

- vbAbortRetryIgnore Abort, Retry, and Ignore.

By default, the first button is the default one; when displaying the Cancel or

No buttons as well, a good practice is to always make them the default one

by also adding to the numeric parameter the constant vbDefaultButton2;

obviously, constant vbDefaultButton3 is making the third one be the default;

trivially, you don’t need either vbDefaultButton1 or vbDefaultButton4; note

that if you use a constant that references a non-existing button position (e.g.

vbDefaultButton4), then the first one is made the default.

Besides icons, buttons, and their positions, through the numeric constant you

can also set other properties of the message box (e.g. make application or

even the system modal while the message box is displayed, display the mes-

sage box from right to left, etc.).

When only the Ok button is displayed, you don’t need to know which button

has been pressed, so you may use the MsgBox statement; when several but-

tons are displayed you may find out which one has been pressed by using the

MsgBox function instead: the code of this button is returned; corresponding

associated constants (e.g. vbOk, vbCancel, vbYes, vbNo, etc.) should be used

instead of hard-coded codes.

For example, the following statement is displaying the message box from fi-

gure 10.11 and then, depending on the button that was pressed, displays ei-

ther True or False (note that, just like in SQL, & is the strings concatenation

operator):

if vbCancel = MsgBox(“Are you sure you want to delete the “ _

& “ selected persons from the PEOPLE table?”,

vbQuestion + vbOKCancel + vbDefaultButton2,

“Please confirm or cancel your request…”) then

MsgBox “True”

else

MsgBox “False”

Page 315: Laborator Baze date

309

Figure 10.11 Example of a message box

Whenever you need to get from users only one data value, you may use the

InputBox function, which displays a window similar to the MsgBox one, but

only with the buttons OK and Cancel and a text box for inputting data, takes

as first parameter the text box label string, the title as the second, and the de-

fault value as the third,49

and returns a string containing the entered value; if

no value is entered and there is no default one, or when the Cancel button is

pressed instead of OK, it returns an empty string.

For example, the following statement is displaying the message input box

from figure 10.12; if user modifies 2013 in 2014 (see figure 10.13) and then

presses OK, string variable v will be assigned the value “2014”:

v = InputBox("Year:", "Please specify desired year ..." _,

2013)

10.1.3.4 ADO DB recordsets

Sometimes, you need to process programmatically sets of db data values,

either only by reading them from and/or writing them to dbs. ADO DB

recordsets are the best way to store and process in main memory rdb table

and query instances.

10.1.3.4.1 ADODB connections

In order to connect to a db through ADO from high-level programming lan-

guages you need to declare and instantiate an ADODB connection. In VBA,

declaration of such a connection (say conn) is as follows:

49

Besides these three ones there are other optional four: two for specifying (in pixels) the

absolute position on the screen of the upper left corner of the input message window (by

default, this window is automatically centered) and the last two for specifying associated

custom help and context (just like for MessageBox above).

Page 316: Laborator Baze date

310

Dim conn As ADODB.Connection

Corresponding instantiation statement (which also opens conn) is very sim-

ple if the db is the current one (if not, just like in any other language, you

have to provide a connection string containing the name of the corresponding

data processor, your credentials, etc.):

Set conn = Application.CurrentProject.Connection

As soon as you (temporarily or definitively) don’t need such a connection

anymore, be sure to close it with:

conn.Close

You can re-open it anytime with:

conn.Open

As soon as you definitively don’t need such a connection anymore, be sure

not only to close it first, but also to free corresponding memory then with:

Set conn = Nothing

10.1.3.4.2 ADODB recordsets

In order to store db data into main memory and/or write main memory data

to dbs through ADO, you have to declare an ADODB recordset, instantiate,

and populate it with data. In VBA, declaration of such a recordset (say rs) is

as follows:

Dim rs As ADODB.Recordset

Corresponding instantiation statement is as follows:

Set rs = New ADODB.Recordset

Corresponding populating statement with data from an ADODB connection

(say conn), according to a SQL SELECT … statement is as follows:

rs.open “SELECT …”, conn

Among other properties, recordsets have a BOF (Begin Of File) and a EOF

(End Of File) ones; when both are true, the recordset is empty; if it is not

Page 317: Laborator Baze date

311

empty, you are generally processing it sequentially, in a forward manner, in a

While Not rs.EOF … rs.MoveNext Wend loop, where MoveNext

moves the recordset cursor to the following row (if any).

You can reference the value of the cell stored in the current recordset rs row

in its column c with rs!c.

Note that there are many other recordset methods and properties; for exam-

ple: MovePrevious, MoveFirst, MoveLast, AddNew, Bookmark, CancelUp-

date, Clone, CompareBookmark, Delete, EditMode, Filter, Find, GetRows,

GetString, Index, NextRecordSet, Requery, Resync, Save, Seek, Sort, Update,

UpdateBatch.

As soon as you (temporarily or definitevely) don’t need such a recordset any-

more, be sure to close it with:

rs.Close

Note that closing (de-populating) is compulsory before re-opening (that is re-

cordset overwriting is not allowed). You can re-open it anytime (not necessa-

rily from the same connection and/or the same populating SQL SELECT

statement) with another or the same rs.Open

As soon as you definitively don’t need such a recordset anymore, be sure not

only to close it first, but also to free corresponding memory then with:

Set rs = Nothing

10.1.3.5 ADO objects hierarchy: Me and Parent

ADO objects are structured in a hierarchy rooted in the Application object

node. Separators between nodes of a same branch are either dots or exclama-

tion marks; as dots are also used as separators between objects and their pro-

perties and methods, a best practice rule is to rather use exclamation marks.

There is an ADO objects collection that you will use the most frequently of

them all: Forms, the collection of all currently open forms. For example, the

path to a control C from (open) form F is Forms!F!C; the path to a control C’

from subform S of F is Forms!F!S!C’.

Page 318: Laborator Baze date

312

In (and only in) classes associated to forms or reports, you can abbreviate all

path prefixes up to the current (sub-)form/report with Me (the equivalent of

Java’s this), whereas those up to the parent one with Parent; for example,

from class Form_F, Forms!F!C can be abbreviated as Me!C, whereas Forms!

F!S!C’ as Me!S!C’; from class Form_S, Forms!F!C can be abbreviated as

Parent!C, whereas Forms!F!S!C’ as Me!C’.

10.1.3.6 Miscellanea

SQL is embedded in VBA not only for ADODB recordsets; for example, you

can run INSERT, UPDATE, and DELETE queries against the current db by

using the DoCmd.RunSQL command, which accepts as its only parameter a

string (containing such a DML statement) and passes it to the Access relatio-

nal engine for execution.

Note that, generally, the DoCmd (Do Command) object has very many other

methods (e.g. open/close dbs, tables, queries, forms, reports, web pages,

functions, stored procedures; set object properties; beep; apply filters;

select/copy/delete/save objects, dbs, files; runs programs/commands; etc.).

Another way of embedding SQL into VBA is offered by the Execute state-

ment and methods. For example, only with the Execute metod of an ADODB

connection object is possible to define explicit transactions, to commit, and

rollback them.

10.1.4 VBA and SQL Functions

10.1.4.1 Data access functions

When you need to read data cells from the db, the simplest and fastest way is

to use VBA’s data access functions, which can also be used in SQL. You

were already taught (see problem P2.1 from section 2.2.2 above) how to use

the most frequently used one of them, namely DLookup:

DLookup(“ expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT TOP 1 expr FROM tbl/query_name [WHERE criteria];

Recall that whenever the corresponding SELECT statement returns an empty

set, DLookup returns null.

Page 319: Laborator Baze date

313

Figure 10.12 Example of an input message box

Figure 10.13 Entering data into an input message box

Other frequently used ones are the following:

DMin(“expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT Min(expr) FROM tbl/query_name [WHERE criteria];

DMax(“expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT Max(expr) FROM tbl/query_name [WHERE criteria];

Note that both above functions are applicable only on numeric, alphanume-

ric, and date data sets.

DSum(“expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT Sum(expr) FROM tbl/query_name [WHERE criteria];

DAvg(“expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT Avg(expr) FROM tbl/query_name [WHERE criteria];

Note that both above functions are applicable only on numeric data sets.

DCount(“expr”, “tbl/query_name”[, “criteria”]) is equivalent to: SELECT Count(expr) FROM tbl/query_name [WHERE criteri-

a];

Page 320: Laborator Baze date

314

DCount doesn't count rows that contain Null values in the column referenced

by expr, unless expr is the wildcard character (* - asterisk). If you use an as-

terisk, the DCount function calculates the total number of rows, including

those that contain Null fields.

If expr contains several columns, separate their names with a concatenation

operator: either the ampersand (&) or the addition (+) ones. If you use the

ampersand to separate columns, the DCount function returns the number of

rows containing data in any of the mentioned columns. If you use the addi-

tion operator,50

the DCount function returns only the number of rows con-

taining data in all of the mentioned columns.

For all above functions:

expr includes the column(s) for which you want to apply the corres-

ponding function; it can be a string expression mentioning columns in

a table or query, or it can be an expression that performs a calculation

on data in those columns; besides names of columns from a table or

query, expr also accepts form controls, constants, and functions;

functions can be either built-in or user-defined, but not domain or

SQL aggregate ones;

tbl/query_name is a string expression identifying the set of rows that

constitutes the data set (domain); it can be or evaluable to a table or a

query name; queries that require parameters are not accepted;

they return null if the corresponding instance is empty, or none of its

data set (domain) rows are satisfying criteria, or if at least one co-

lumn from criteria is not one from tbl/query_name;

DMin, DMax, DSum, and DAvg ignore Null values in the column referenced

by expr.

Note that if you use DCount, DMin, DMax, DSum, or DAvg in SQL, values

are evaluated before data is grouped; if you use corresponding Count, Min,

Max, Sum, or Avg instead, data is grouped before values in the column(s) ex-

pression are evaluated.

50

The ampersand is the preferred operator for performing string concatenation: you should

avoid using the addition operator for anything other than numeric addition, unless you speci-

fically wish to propagate Nulls through an expression.

Page 321: Laborator Baze date

315

10.1.4.2 Other libraries functions

Note that all above library functions (as well as much more others – see Ap-

pendix 2) belong to the Access standard libraries Visual Basic for Applica-

tions, Microsoft Access Object Library, and Microsoft Office Access data-

base engine Object Library. Additionally, you may use functions from very

many other available libraries by simply including them into your project:

click on the Tools menu option, then on References from the corresponding

sub-menu, on desired library check-boxes, and, finally on the OK button of

the References window (see figure 10.14). In cases where several selected li-

braries have common functions you can set the search priority between libra-

ries by using the up and down Priority arrow buttons.

Note that ADO functions are not available by default and that there are three

such libraries: Microsoft ActiveX Data Objects, Microsoft ActiveX Data Ob-

jects Recordset, and Microsoft ADO ext. for DDL and Security. This allows

keeping project sizes to the minimum possible (e.g. if you don’t need to pro-

grammatically create or alter tables, constraints, users, and/or groups of

users, etc., then you don’t need the third one).

Figure 10.14 Adding libraries to your project

Page 322: Laborator Baze date

316

10.2 Exercises in Access Consider the Geografie db; using VBA, enforce the following non-relational

constraints:

P10.1 Any country should have as its capital a city from that country (dually:

no country may have as its capital a city of another country).51

Solution:

First, note that cities (LOCALITATI) belong to states (JUDETE) and these

belong to countries (TARI). Currently, the corresponding lookup RowSource

property of the combo-box Capitala from TARI reads:

SELECT LOCALITATI.[#L], [Loc] & " " & [Judete].[Judet]

AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

ORDER BY [Loc] & " " & [Judete].[Judet];

Obviously, this is computing all world’s cities, for any of its countries. The

best solution is the following preventing-type one: when the current country

changes, filter cities so that the combo-box contain only those of the current

country (which is stored in the [#T] control of the Form_TARI and Form_

TARIperTara forms). The corresponding modified SQL statement is:

SELECT LOCALITATI.[#L], [Loc] & " " & [Judete].[Judet]

AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

WHERE Tara = Me![#T]

ORDER BY [Loc] & " " & [Judete].[Judet];

In order to modify in VBA the RowSource property with this new value, the

corresponding Form_Current event-driven methods have to contain the fol-

lowing statement (note that all quotes in the SELECT statement have to be

replaced by apostrophes or double-quotes and that Me![#T] should be kept

outside the string, in order to be computed dynamically: otherwise, it would

be considered as a parameter and Access will ask users for its values on each

row!):

Me!Capitala.RowSource =

51

Formally, this a local commutativity constraint: Capitala Tara Judet = 1TARI (see P9.4)

Page 323: Laborator Baze date

317

"SELECT LOCALITATI.[#L], [Loc] & ‘ ‘ & [Judete].[Judet]

AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

WHERE Tara = " & Me![#T] &

" ORDER BY [Loc] & ‘ ‘ & [Judete].[Judet];"

For example, when the cursor arrives in any of these forms on the row cor-

responding to Romania (for which [#T] = 1), Capitala.RowSource will have

the value:

SELECT LOCALITATI.[#L], [Loc] & " " & [Judete].[Judet] AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

WHERE Tara = 1

ORDER BY [Loc] & " " & [Judete].[Judet];

When the cursor arrives in any of these forms on the row corresponding to

U.S.A. (for which [#T] = 4), Capitala.RowSource will have the value:

SELECT LOCALITATI.[#L], [Loc] & " " & [Judete].[Judet] AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

WHERE Tara = 4

ORDER BY [Loc] & " " & [Judete].[Judet];

For accordingly requerying the Capitala combo-box, the following statement

has to be added next:

Me!Capitala.Requery

In conclusion, enforcing this local commutativity constraint only needs two

VBA statements (with the first one embedding a SQL statement); but, before

jumping to actual coding, let’s not ever forget that any instance also has a

distinguished blank row (for inserting a new row into the corresponding in-

stance); obviously, as [#T] is null for this line, the execution of the corres-

ponding statement, which is:

SELECT LOCALITATI.[#L], [Loc] & " " & [Judete].[Judet]

AS [Loc Judet]

FROM JUDETE INNER JOIN LOCALITATI

ON JUDETE.[#J] = LOCALITATI.Judet

WHERE Tara =

ORDER BY [Loc] & " " & [Judete].[Judet];

Page 324: Laborator Baze date

318

would result in a runtime error, as the syntax … WHERE Tara = ORDER

BY … is not acceptable!

Obviously, as a new country cannot have cities belonging to it, Capitala

should be empty on the blank row (which is identifiable by the True value of

the NewRecord property of any form having a data source, whereas, for any

other of its rows, this property has value False); a very simple way to obtain

the empty set from any table/view is to add in the WHERE clause P and

NOT P, for any predicate P; consequently, for the blank line, the Capitala.

RowSource could have the following value:

SELECT [#L]

FROM LOCALITATI

WHERE Judet = 0 AND Judet <> 0;

By also adding comments and the error system, the Form_Current method of

both Form_TARI and Form_ TARIperTara forms should be the following:

'*************************

Private Sub Form_Current()

'*************************

'enforces constraint "No country may have as its capital a

'city of another country"

On Error GoTo err_point

If Me.NewRecord Then

Me!Capitala.RowSource = "SELECT [#L] FROM LOCALITATI " _

& " WHERE Judet = 0 AND Judet <> 0;"

Else

Me!Capitala.rowSource = "SELECT [#L], Loc, JUDETE.Judet " _

& "FROM JUDETE INNER JOIN LOCALITATI ON JUDETE.[#J]=" _

& "LOCALITATI.Judet WHERE Tara=" & Me![#T] _

& " ORDER BY Loc, JUDETE.Judet;"

End If

Me!Capitala.Requery

Exit Sub

err_point: MsgBox Err.Source & "-->" & Err.Description, _

vbExclamation, _

"Error in class Form_TARI . method Form_Current..."

End Sub

Page 325: Laborator Baze date

319

P10.2 In order for a country to have an oceanic harbor, it has to be neighbor

to the corresponding ocean (see the generalized commutativity constraint

OceanHarborsConstraint from P9.5 above).52

Solution:

First of all, obviously, the involved form is Form_PorturiOceanice, having

as data source the table PorturiOceanice, which stores the corresponding

pairs <[#PO], Ocean>; as OceanicHarbors (PorturiOceanice) is a subset of

CITIES (LOCALITATI), its primary key [#PO] is a foreign key too, referenc-

ing the primary key [#L]; Ocean is also a foreign key, referencing the prima-

ry key [#C] of CONTINENTE.

Unfortunately, as this constraint involves both of these columns, preventive-

type solutions are not applicable, so that we have to devise a cure-type one:

users will be free to choose any city in [#PO] and any ocean in Ocean, and,

before saving such a pair (either after updating an existing one or inserting a

new one), we will verify whether or not a corresponding pair <c, o> exists in

the VECINATATIOT (NEIGHBORSOceansCountries) table, where c is the

country to which city having id Me![#PO] belongs and o = Me!Ocean.

Obviously, if such a pair exists, then we do not have anything to do (as

OceanHarborsConstraint is not violated by this new pair); if not, in order to

enforce OceanHarborsConstraint, we could either reject this pair and ask

user to first add a corresponding pair <c, o> in the VECINATATIOT table,

which is not “nice” or add that pair automatically, with a user prior approval.

Also note that the PorturiOceanice table also has another column, called

PunctCardinal; this means that users might update only it, so that the Ocean-

HarborsConstraint should be enforced only when at least one of the two in-

volved columns, [#PO] and Ocean, are actually updated (that is they have

other values than their corresponding previous ones).

Consequently, here is the corresponding Form_BeforeUpdate method (note

that c is declared as Long and not as Variant because both Judet from LOCA-

LITATI and Tara from JUDETE are totally defined (do not accept nulls);

also note that, for any cancelable event, your errors processing section

52

Formally, (hHARBORS)(nNEIGHBORSOC)(Ocean( h) = Ocean(n) Country(n) =

Country State City(h))

Page 326: Laborator Baze date

320

should generally also include a Cancel = True statement, for canceling cor-

responding event in case of errors):

'***********************************************

Private Sub Form_BeforeUpdate(Cancel As Integer)

'***********************************************

'enforces the OceanHarborsConstraint: In order for a country

'to have an oceanic harbor, it has to be neighbor to the

'corresponding ocean.

Dim c As Long

On Error GoTo err_point

If Not Me.NewRecord And Me![#PO] = Me![#PO].OldValue And _

Me!Ocean = Me!Ocean.OldValue Then

GoTo exit_sub

End If

c = DLookup("Tara", "JUDETE", "[#J]=" & _

DLookup("Judet", "LOCALITATI", "[#L]=" & Me![#PO]))

If IsNull(DLookup("[#VM]", "VECINATATIOT", "TaraVecina=" & _

c & " AND Ocean=" & Me!Ocean)) Then

If vbCancel = MsgBox("Would you like to add neighborhood" _

& " data for this ocean and corresponding country?", _

vbQuestion + vbOKCancel + vbDefaultButton2, _

"Corresponding country is not neighbor with this " _

& "ocean...") Then

Cancel = True

MsgBox "Please change either the harbor or the ocean!", _

vbCritical, "Impossible to save this pair..."

Else

DoCmd.RunSQL "INSERT INTO VECINATATIOT(TaraVecina, " _

& "Ocean) VALUES (" & c & ", " & Me!Ocean & ")"

MsgBox "Succesfully added corresponding neighborhood " _

& "data!", vbInformation, "This pair will be saved..."

End If

End If

exit_sub: Exit Sub

err_point: MsgBox Err.Source & "-->" & Err.Description, _

vbExclamation, "Error in class Form_PorturiOceanice " _

& ". method Form_BeforeUpdate..."

Cancel = True

End Sub

Page 327: Laborator Baze date

321

10.3 Prerequisites in Oracle: Triggers

10.4 Exercises in Oracle

10.5 Best practice rules

1. Whenever possible, enforce constraints preventively rather than by

curing.

2. Always enforce generalized commutativity constraints by automati-

cally adding missing rows (at most asking for users’ confirmations), rather

than by rejecting violating updates/inserts.

10.6 Homework H10.1 Design and develop, in any high-level programming language or in

any extended SQL of your choice (preferably embedding SQL) necessary

methods / triggers for enforcing all remaining non-relational constraints from

lab 9 exercises, as well as those discovered in H9.1 above.

Page 328: Laborator Baze date

322

Chapter 11. 11th Lab: Reporting in Access & 2nd DB test

training

11.1 Reporting in Access

11.1.1 Prerequisites

Access also provides a Report Generator and Manager (ARGM). Reports are

very similar to forms, except that they are designed for outputting data, in-

stead of inputting and managing it and prepared for printing, rather than for

displaying (although reports may also be previewed before or even instead of

printing); their main enhacement is (nested) grouping of data, with associa-

ted totals (for cardinalities, sums, averages, etc.). Access reporting facilities

are not that powerful as, for example, Crystal Reports’ ones, but they are

comparable with MS Reporting Services for SQL Server ones.

Although ARGM wizard is also able to help with the subjacent query design

too, it is a best practice to first design, test, and save independently its sub-

jacent query and give to ARGM its name; then you can embed it in the report

(for easing project management), by replacing the query name with its body.

Just like for forms, you can design reports either from scratch or using the

Report Wizard (ARW). To create a report from scratch, click on the Report

Design or Blank Report icons of the Create tab of the Ribbon. If you click on

the Report one, a datasheet-type report is automatically created for the cur-

rently selected table (see figure 11.1 for an example); then, you can use the

Report Layout Tools (ARLT) for enhancing your report. Note that for printing

labels (a particular type of reports), there is a specialized Label Wizard that

you can launch by clicking on the Labels icon of the Create tab of the Rib-

bon (see figure 11.2).

Generally, the most productive way to produce any other types of reports is

first using ARW and then enhancing it with ARLT. To start ARW, click on

the Report Wizard icon of the Create tab of the Ribbon.

Figure 11.3 shows its first window, where you may choose the desired subja-

cent query name or start designing one, by choosing desired tables and co-

lumns. When clicking on Next, a second window is displayed (see figure

11.4) for adding (up to four levels of) grouping, by clicking on the > button

Page 329: Laborator Baze date

323

(see figure 11.5); you can remove groups by clicking on <; you can also

change groups hierarchy by clicking on the Priority’s up and down buttons.

Figure 11.1 An example of a datasheet-type report generated by ARGM

Figure 11.2 The first screen of the Label Wizard

Page 330: Laborator Baze date

324

Figure 11.3 ARW’s first screen: chosing/designing the subjacent query

Figure 11.4 ARW’s second screen: specifying groups

Page 331: Laborator Baze date

325

Figure 11.5 ARW’s second screen: specifying groups hierarchy

By clicking on the Grouping Options button, you can specify grouping (for

the current group) either normally (i.e. on whole corresponding column va-

lues) or by using only a prefix of the corresponding column values (made out

of 1, 2, …, or 5 characters, see figure 11.6); you should click on either OK or

Cancel in order to close this modal window and get back to the ARW’s se-

cond screen.

When you finished grouping, click on Next for advancing to the ARW’s third

screen, where you can define (up to four levels of) sorting (see figure 11.7).

By clicking on the Summary Options button, you can add (groups and over-

all) summaries on any report’s numeric column (see figure 11.8): you can al-

so choose whether you would like to print the detail and summary or only

summary corresponding values, as well as including or not percent of totals

for sums; click on OK or Cancel in order to close this modal window and get

back to the ARW’s third screen.

When you finished sorting, click on Next for advancing to the ARW’s fourth

screen, where you can define both layout and orientation (see figure 11.9).

For wide reports, choose Landscape instead of the default Portrait orienta-

Page 332: Laborator Baze date

326

tion. Depending on your customers’ or/and personal’s taste, choose one of

the three available layouts: Stepped, Block, or Outline (note that the left icon

changes accordingly in order to help you choosing).

When you finished specifying layout and orientation, click on Next for ad-

vancing to the ARW’s fifth screen, where you can change the default report

name suggested automatically (the name of the subjacent query, for exam-

ple) and save and preview or continue with manually modifying its design

(see figure 11.10).

After specifying the desired report name, click on Finish, with the default

option Preview, for inspecting the generated report (see figure 11.11 for its

first page and 11.12 for its last one). By using the footnote bar Page you can

inspect all of the corresponding report pages.

Generally, for reports having many columns, due to the limitations imposed

by paper sizes, the effect of the default option Adjust the field width so all

fields fit on page from ARW’s fourth screen is that some field sizes are too

small for the corresponding column values, so that ‘#’’s are displayed in-

stead. Consequently, manual design adjustments are necessary.

Figure 11.6 ARW’s second screen: specifying grouping options

Page 333: Laborator Baze date

327

Figure 11.7 ARW’s third screen: specifying sorting options

Figure 11.8 ARW’s third screen: specifying summary options

Page 334: Laborator Baze date

328

Figure 11.9 ARW’s fourth screen: specifying layout and orientation

Figure 11.10 ARW’s fifth screen: specifying report title

Page 335: Laborator Baze date

329

Figure 11.11 An example of ARW automatically generated report first page

Figure 11.12 An example of ARW automatically generated report last page

Page 336: Laborator Baze date

330

In order to modify a report design, just like for forms, open it in Design view:

Figure 11.13 An example of a report Design View

Besides pure graphics (like centering the report’s title, changing fonts, sizes,

colors, etc.), you can also modify everything else, from the source data to

grouping, from sorting to layout, etc. For example, in order to ease db mana-

gement, you can replace the subjacent query name by its body: open the que-

ry in SQL design mode (see chapters 2 to 6 above), select and copy its body,

and then, just like for forms, right-click the upper-left corner of the report de-

sign view, click on Report Properties, then on the Data tab, paste in the Re-

cord Source property the query’s body (see figure 11.14), and, finally, close

the Properties window and save the report design.53

Figure 11.14 Replacing the name of the subjacent query with its body

53

Unfortunately, I just discovered that Access 2010 behaves unexpectedly after such a re-

placement: it replaces the City names with the corresponding country Capital ones!! More-

over, even if you delete Capital and replace it with City, when saving Access replaces again

City with Capital!!! Moreover, calculated cardinals are no more correctly computed either!!!

Page 337: Laborator Baze date

331

Next, attach a method to the No Data event, for not printing the report when

its data source is empty: just like for forms, re-open the Report Properties,

click on the Event tab, choose Event Procedure from the On No Data com-

bo-box (see figure 11.15), click on the “…” button, and then enter the corres-

ponding VBA code into the automatically generated method signature (see fi-

gure 11.16); save, compile the project, and then get back to the design view

for closing the Properties window.

Figure 11.15 Attaching an event procedure to the No Data report event

Figure 11.16 Cancelling printing of empty reports

Finally, we have to take care of all data which is not displayed correctly, be-

cause of the lack of space; first, note (see figure 11.3 above) that all data is

displayed on only one (detail) row, with the corresponding header displayed

on each page, whilest both country and state group headers are empty. This

is why, for example, country and state names (but also corresponding popu-

Page 338: Laborator Baze date

332

lations, capitals, etc.) are repeatedely printed for each city (see figures 11.11

and 11.12).

For factoring out all country data, first enlarge the Country Header and then

drag and drop all labels and corresponding data (in this particular case, name,

code, population, states’ designation, and capital) into it (see figure 11.17).

Save your work and switch to the preview mode to check that all of your si-

zes and alignements are ok (see figure 1.18).

Then, similarly, factorize state data (in this particular case, name, code, po-

pulation, and capital - see figure 11.19), save, and check it too (see figure

1.20).

Next, re-arranging detail data will allow it too to be correctly printed (see fi-

gures 11.21 and 11.22). Finally, re-arranging totals completes the manual ad-

justments of the report (see figures 11.23 and 11.24).

Figure 11.17 Factorizing outer group data

Page 339: Laborator Baze date

333

Figure 11.18 Checking factorizing outer group data

Figure 11.19 Factorizing inner group data

Page 340: Laborator Baze date

334

Figure 11.20 Checking factorizing inner group data

Figure 11.21 Arranging detail data

Page 341: Laborator Baze date

335

Figure 11.22 Checking re-arranged detail data

Figure 11.23 Arranging sums

Page 342: Laborator Baze date

336

Figure 11.24 Checking re-arranged sums

Note that you can also check/modify grouping and sorting (see figure 11.25),

totals, tab order, page numbers, logos, titles, date and times, subreports, etc.

For both grouping and sorting, you can add printing properties by clicking on

the corresponding More button: you can the grouping prefix length to any

natural number, add/remove groups titles, headers, and/or footers, and, espe-

cially, add/remove page breaks either before any new corresponding group

values or such that any new group value header is followed on the same page

by at least the first row of it (see figure 11.26).

You may also use all other available report and control events (see figure

11.27), just like for forms, for canceling opening or closing, dynamically

changing/filtering data sources, passing parameters, changing colors/fonts/si-

zes dynamically, on a row or cell basis, etc.

Page 343: Laborator Baze date

337

Figure 11.25 Checking and/or modifying grouping and sorting

Figure 11.26 Adding grouping and/or sorting printing properties

Page 344: Laborator Baze date

338

Figure 11.27 Available report events

11.1.2 Exercises

P11.1 Design and implement for the lab db a report for printing country

names, codes, populations, state designations, and capitals (on an outer

group, ascendingly on names), state names, codes, capitals, and population

(on an inner group, ascendingly on names), and city names and populations

(in the descending order of population and then ascending on name), with to-

tals of number of cities and sum of their population per state and country, of

number of states and sum of their population per country, as well as grand

totals of all of this data.

Solution:

Obviously, needed data is stored in tables COUNTRIES, STATES, and CI-

TIES (see figures 2.7, 2.2, and 2.4 respectively); note that three instances of

CITIES are necessary, one for the cities themselves, a second one for the

country capitals, and a third one for the state capitals; also note that both

country and state capitals are not required, so outer joins are needed for this

two latter instances in order not eliminate countries and/or states for which

corresponding capitals are not known.

Consequently, here is the needed subjacent query (saved it as ReportQ):

Page 345: Laborator Baze date

339

SELECT COUNTRIES.Country, COUNTRIES.CountryCode,

COUNTRIES.Population, COUNTRIES.StateDesignation,

CAPITALS.City AS Capital, STATES.State,

STATES.StateCode, STATES.Population AS StatePopulation,

STATE_CAPITALS.City AS StateCapital, CITIES.City,

CITIES.Population AS CityPopulation

FROM (COUNTRIES LEFT JOIN CITIES AS CAPITALS

ON COUNTRIES.Capital = CAPITALS.x) INNER JOIN ((STATES

LEFT JOIN CITIES AS STATE_CAPITALS

ON STATES.StateCapital = STATE_CAPITALS.x) INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country;

Then, by following exactly the steps from sub-section 11.1.1, the requested

report is obtained, whose output is (partially) presented in figure 11.24.

P11.2 Design and implement for the GeografieDB db a report for printing

oceans, continents, and archipels names, all of them being (normal) groups,

in this order, islands ant their main countries names, as the fourth group, and

countries names and island area sizes that they occupy, in descending order

of the occupied area size and then ascending on country name, with totals

(both absolute and percentage) of both island and countries occupied areas

on all groups, as well as grand totals of all of this data.

Solution:

Needed data is stored in the following 4 tables: INSULE (ISLANDS, figure

11.28), CONTINENTE (CONTINENTS, figure 11.29), TARI (COUNTRIES,

figure 11.30), ARHIPELAGURI (ARCHIPELS, figure 11.31), and Ocupare-

Insule (IslandsOccupants, figure 11.32). First of all please note that the area

occupied by the main country on an island is not stored, as it is computable

from the island area and the sum of the areas occupied by all other countries

that are co-occupying it (if any); consequently, these values need to be com-

puted too. The following query (TotIslandsOccupiedAreas) is computing the

total areas occupied by the countries in OcupareInsule (IslandsOccupants),

per island:

SELECT Insula, Sum(Suprafata) AS TotOccupiedArea

FROM OcupareInsule

GROUP BY Insula;

Then, based on these values and on the total island area, the following query

(MainIslandsCountriesAreas) computes areas occupied by main countries:

Page 346: Laborator Baze date

340

SELECT [#I], Tara,

IIf(IsNull([TotOccupiedArea]),[Suprafata],[Suprafata]-

[TotOccupiedArea]) AS MainCountryArea

FROM TotIslandsOccupiedAreas RIGHT JOIN INSULE

ON TotIslandsOccupiedAreas.Insula = INSULE.[#I];

As for the “core” report query, note that two instances of CONTINENTE are

needed (one for the ocean and the other for the continent to which islands be-

long); similarly, two instances of TARI are also needed (one for the main

country and the other for the rest of other islands’ occupants); also note that,

as not every island belongs to an archipel, Arhipelag from INSULE accepts

nulls, so that an outer join is needed in order not to eliminate such islands; si-

milarly, as not every island is shared among several countries, another outer

join is needed between INSULE and OcupareInsule, in order not to eliminate

islands that are occupied by only one country. Consequently, this core query

(save it as IslandsWithTheirCountries0) has the following SQL expression

(see figure 11.33 for its QBE/design view one):

SELECT [#I], OCEANS.Continent AS Ocean, CONTINENTE.Continent,

ARHIPELAGURI.Archipel, INSULE.Island, INSULE.Suprafata

AS IslandArea, MainCountries.Country AS MainCountry,

TARI.Country, OcupareInsule.Suprafata AS CountryArea

FROM (((((INSULE LEFT JOIN OcupareInsule

ON INSULE.[#I] = OcupareInsule.Insula) INNER JOIN

CONTINENTE ON INSULE.Continent = CONTINENTE.[#C])

LEFT JOIN ARHIPELAGURI

ON INSULE.Arhipelag = ARHIPELAGURI.[#A]) INNER JOIN

TARI AS MainCountries

ON INSULE.Tara = MainCountries.[#T]) LEFT JOIN TARI

ON OcupareInsule.Tara = TARI.[#T]) INNER JOIN

CONTINENTE AS OCEANS ON INSULE.Ocean = OCEANS.[#C];

Finally, we have to also add areas occupied by main countries (computed by

the MainIslandsCountriesAreas query above; save the result as IslandsWith-

TheirCountries):

SELECT IslandsWithTheirCountries0.*, MainCountryArea

FROM IslandsWithTheirCountries0 INNER JOIN

MainIslandsCountriesAreas

ON IslandsWithTheirCountries0.[#I] =

MainIslandsCountriesAreas.[#I];

By following exactly the steps from sub-section 11.1.1, the requested report

is obtained, whose first and last design view screens are presented in figures

11.34 and 11.35, while the corresponding running ones in 11.36 and 11.37.

Page 347: Laborator Baze date

341

Figure 11.28 The GeografieBD INSULE (ISLANDS) table

Figure 11.29 The GeografieBD CONTINENTE (CONTINENTS) table

Page 348: Laborator Baze date

342

Figure 11.30 The GeografieBD TARI (COUNTRIES) table

Figure 11.31 The GeografieBD ARHIPELAGURI (ARCHIPELS) table

Page 349: Laborator Baze date

343

Figure 11.32 The GeografieBD OcupareInsule (IslandsOccupants) table

Figure 11.33 The IslandsWithTheirCountries0 core report query design view

Page 350: Laborator Baze date

344

Figure 11.34 The IslandsWithTheirCountries report’s first design view

screen

Figure 11.35 The IslandsWithTheirCountries report’s last design view screen

Page 351: Laborator Baze date

345

Figure 11.36 The IslandsWithTheirCountries report’s first screen

Figure 11.37 The IslandsWithTheirCountries report’s last screen

Page 352: Laborator Baze date

346

11.2 2nd DB test training Consider the files (managed by file management subsystems for operating

systems like Windows, Unix, Linux, etc.) of any disk partition, for which are

of interest (in this simplified subuniverse) only name, extension, folder, logic

drive (identified by an ASCII capital letter), start (storing) address, size, and

whether or not they are folders. Hint: recall that, by convention, the name of

root folders (and only of root folders) is “\” and that they do not have exten-

sions. Design the db fragment needed for storing this data and implement it

on the platform of your choice; also add at least two plausible rows per table.

Solution:

Folders are zero-length (meta-)files, stored in the file management system’s

tables, structured, for such operating systems, as trees (one per logic drive);

any file belongs to a folder, except for the root folders, which do not belong

to anything; any file belongs to a logic drive and any formatted logic drive

has only one root folder (wheres there’s none for unformatted ones).

Consequently, the corresponding E-RD and restrictions list are the following

(8 + 14 = 22 points):

Name Ext StartAddress Size Folder?

Folder FILES

LogicDrive RootFolder

LOGIC_DRIVES LogicDriveLetter

FILES (The set of all existing files, including folders)

Max. cardinality: 1024

(for example, Win 2012 Server accepts HDDs of

18EB each; with VHDX Hyper-V, it has much more than that) (R0)

Ranges:

- Name and Ext: ASCII(255) (R1)

- StartAddress and Size: [0, …, 1024

-1] (R2)

- Folder?: {True, False} (R3)

Mandatory: Name, Size, Folder? (R4)

Uniqueness: there may not be two files having same name and

same extension in a same folder (R5)

Page 353: Laborator Baze date

347

Other restrictions:

- all files having Size > 0 should have a not null start address (R6)

- any folder has Size = 0 (R7)

- any file having Size = 0 has no start address (R8)

LOGIC_DRIVES (The set of all existing logic drives)

Max. cardinality: 27 (R9)

Ranges: LogicDriveLetter: [‘A’, …, ‘Z’] (R10)

Mandatory: LogicDriveLetter (R11)

Uniqueness: LogicDriveLetter (R12)

Other restrictions:

- any file belongs to a logic drive (R13)

- unformatted logic drives do not have root folders; formatted

ones do have one (R14)

- all files, except for root folders, belong to a folder (R15)

- any root folder has name “\” and no extension (R16)

The result of applying the translation algorithm from E-RDs and restriction

lists to mathematical schemes is the following (15 points):

FILES

x NAT(24), total (according to R0)

Name ASCII(255), total (according to R1 and R4)

Ext ASCII(255) (according to R1)

StartAddress [0, …, 1024

-1] (according to R2)

Size [0, …, 1024

-1], total (according to R2 and R4)

Folder? BOOLE, total (according to R3 and R4)

Folder : FILES FILES (according to R15)

LOGIC_DRIVES

x NAT(2), total (according to R9)

LogicDriveLetter [‘A’, …, ‘Z’], total (according to R10, R11, and R12)

LogicDrive : FILES LOGIC_DRIVES, total (according to R13)

RootFolder : LOGIC_DRIVES FILES (according to R14)

C5: Name Ext Folder LogicDrive key (according to R5)

C6: (xFILES)(Size(x) > 0 StartAddress(x) NULLS)

(according to R6)

C7: (xFILES)(Folder?(x) Size(x) = 0) (according to R7)

C8: (xFILES)(Size(x) = 0 StartAddress(x) NULLS)

(according to R8)

Page 354: Laborator Baze date

348

C15: (xFILES)(Name(x) = “\” Ext(x) NULLS

Folder(x) NULLS) (according to R15)

C16: (xFILES)(yLOGIC_DRIVES)

((Folder(x) NULLS Name(x) = “\” Ext(x) NULLS)

(x = RootFolder(y) Folder(x) NULLS)) (according to R16)

Results of applying the first refinement algorithm (for assisting sets, func-

tions, and constraints design) are the following (40 points):

a. Sets: both FILES and LOGIC_DRIVES are atomic type object sets not

semantically overloaded.

b. Functions:

- Name is well defined as any file has a name and only one name;

one-to-oneness: there may be several files having same name even in

a same folder (provided they have different extensions);

ontoness: it is not mandatory that all possible ASCII strings of at

most 255 characters be file names on a same partition (moreover,

there are even special characters not allowed in file names);

- Ext is well defined as any file may also have an extension and only

one extension;

one-to-oneness: there may be several files having same extension e-

ven in a same folder (provided they have different names);

ontoness: it is not mandatory that all possible ASCII strings of at

most 255 characters be file extensions on a same partition (more-

over, there are even special characters not allowed in file exten-

sions);

- LogicDrive is well defined as any file belongs to a logic drive and on-

ly one logic drive;

one-to-oneness: there may be several files belonging to a same logic

drive;

ontoness: it is not mandatory that all possible ASCII capital letters be

assigned to logic drives on a same partition;

- StartAddress is well defined as any file having Size > 0 is stored on a

physical drive starting from an address and only one address;

one-to-oneness: there may not be several files starting from a same

address in a same partition (in fact, not even on a same physical

drive, regardless of partitions) StartAddress is one-to-one;

Page 355: Laborator Baze date

349

ontoness: it is not mandatory that all possible integers between 0

and1024

-1 be file start addresses on a same partition;

- Size is well defined as any file has a size and only one size;

one-to-oneness: there may be several files having a same size on any

partition;

ontoness: it is not mandatory that all possible integers between 0

and1024

-1 be file sizes on a same partition;

- Folder? is well defined as any file is either a folder or an ordinary

file;

one-to-oneness: there may be several ordinary as well as folder files

on any partition;

ontoness: all files may be empty folders in any partition;

- Folder is well defined as any file, except for root folders, belongs to a

folder and only one folder;

one-to-oneness: there may be several files belonging to a same folder

on any partition;

ontoness: there may be empty folders in any partition;

acyclicity: no folder may belong to itself, either directly or indirectly

(generally, any tree is free of cycles) Folder acyclic should be ad-

ded to the db scheme;

- LogicDriveLetter is well defined as any logic drive has an operating

system assigned letter and only one letter;

one-to-oneness: there may not be several logic drives having assigned

a same letter on any partition;

ontoness: it is not mandatory that all partitions have always 27 logic

drives each;

- LogicDrive is well defined as any file belongs to a logic drive and

only to one logic drive;

one-to-oneness: there may not be several logic drives having assigned

a same letter on any partition;

ontoness: it is not mandatory that all logic drives of a partition be

always formatted;

- RootFolder is well defined as any formatted logic drive has one root

folder and only one root folder;

one-to-oneness: no folder may be the root folder of several logic

drives (regardless of partitioning) RootFolder is one-to-one;

Page 356: Laborator Baze date

350

ontoness: it is not mandatory that all files be root folders.

c. Constraints:

- trivially, files only belong to folders, not to ordinary files the con-

straint (xFILES)(Folder?(Folder(x))) should be added to the db

scheme;

- unfortunately, C5 only covers files having not-null extensions: addi-

tionally, there may not be two files in a folder having same names

and no extensions C5 has to be replaced by the following stronger

constraint (which is implying R5):

(x,yFILES)((Ext(x) NULLS Ext(y) NULLS) Name

Ext Folder? LogicDrive(x) Name Ext Folder?

LogicDrive(y)) (Ext(x) NULLS Ext(y) NULLS) Name

Folder? LogicDrive(x) Name Folder? LogicDrive(y)));

- trivially, any root folder should be a folder, but the corresponding

constraint ((xLOGIC_ DRIVES)(Folder?(RootFolder(x)))) is im-

plied by C16;

- trivially too, any file should belong to a folder from a same logic

drive the constraint (xFILES)(LogicDrive(Folder(x)) = Logic-

Drive(x)) should be added to the db scheme too;

- trivially too, no file may be stored on a logic drive, unless that drive

is formatted (i.e. it has a root folder) the constraint (xFILES)

((Name(x) “\” Ext(x) NULLS) RootFolder(LogicDrive(x)

NULLS) should be added to the db scheme too.

Results of applying the second refinement algorithm (for assisting keys

discovery) are the following (7 points):

FILES:

n = 6 (as StartAddress is a key, only Name, Ext, Size, Folder?, Folder,

and LogicDrive remain to be considered), K = {StartAddress, Name Ext

Folder LogicDrive};

non-primeness:

- Name, Ext, Folder, and LogicDrive are prime, as they already consti-

tute a key;

Page 357: Laborator Baze date

351

- Size is trivially non-prime: file size cannot participate in unique files

identification;

- Folder? is trivially non-prime: file type (ordinary or folder) cannot

participate in unique files identification.

Consequently, n’ = 4 (only Name, Ext, Folder, and LogicDrive remain to be

considered); as all of them are making up a key, no subproduct may be a key,

so there is nothing to do!.

In conclusion, FILES have no other keys than those in K = {StartAddress,

Name Ext Folder LogicDrive}.

LOGIC_DRIVES:

K = {LogicDriveLetter, RootFolder}, n = 0 (as LogicDriveLetter and Root-

Folder are both keys) nothing to do.

Results of applying the third refinement algorithm (for assisting E-RD cycles

analysis) are the following (3 points):

There are two cycles: Folder, which has been analyzed already in the first re-

finement step above, and the uni-directional binary one made out of Logic-

Drive : FILES LOGIC_DRIVES and RootFolder : LOGIC_DRIVES

FILES.

- RootFolder LogicDrive =? 1FILES (should any file be the root folder

of the logic drive to which it belongs?) – trivially no, as not all files

are folders (and only one folder per logic drive is a root one)

- LogicDrive RootFolder =? 1LOGIC_DRIVES (should any root folder of a

logic drive be a file of that logic drive?) – trivially yes LogicDrive

RootFolder = 1LOGIC_DRIVES has to be added too.

Page 358: Laborator Baze date

352

To conclude with, here is the final mathematical scheme obtained (28

points):

FILES

x NAT(24), total

Name ASCII(255), total

Ext ASCII(255)

StartAddress [0, …, 1024

-1]

Size [0, …, 1024

-1], total

Folder? BOOLE, total

Folder : FILES FILES, acyclic

C6: (xFILES)(Size(x) > 0 StartAddress(x) NULLS)

C7: (xFILES)(Folder?(x) Size(x) = 0)

C8: (xFILES)(Size(x) = 0 StartAddress(x) NULLS)

C17: (xFILES)(Folder?(Folder(x)))

LOGIC_DRIVES

x NAT(2), total

LogicDriveLetter [‘A’, …, ‘Z’], total

LogicDrive : FILES LOGIC_DRIVES, total

RootFolder : LOGIC_DRIVES FILES

C5: (x,y FILES)((Ext(x) NULLS Ext(y) NULLS) Name Ext

Folder LogicDrive(x) Name Ext Folder LogicDrive(y))

(Ext(x) NULLS Ext(y) NULLS)

Name Folder LogicDrive(x) Name Folder LogicDrive(y)))

C15: (xFILES)(Name(x) = “\” Ext(x) NULLS

Folder(x) NULLS)

C16: (xFILES)(yLOGIC_DRIVES)

((Folder(x) NULLS Name(x) = “\” Ext(x) NULLS)

(x = RootFolder(y) Folder(x) NULLS))

C18: (xFILES)(LogicDrive(Folder(x)) = LogicDrive(x))

C19: (xFILES) ((Name(x) “\” Ext(x) NULLS)

RootFolder(LogicDrive(x) NULLS)

C20: LogicDrive RootFolder = 1LOGIC_DRIVES

Applying the algorithm for translating mathematical schemes into relational

ones (24 points) and non-relational constraint lists (12 points) yields the

following:

Page 359: Laborator Baze date

353

FILES(x, StartAddress, Name Ext Folder LogicDrive)

x Name Ext Fol-

der

Fol-

der?

Size StartAd-

dress

LogicDrive

au-

ton.

(24)

ASCII

(255)

ASCII

(255)

Im

(x)

BO-

OLE

[0, …,

1024

-

1]

[0, …,

1024

-1]

Im(LOGIC

_DRIVES.x)

NO

T

NU

LL

NOT

NULL

NOT

NUL

L

NOT

NUL

L

NOT NULL

1 \ T 0 1

2 boot ini 1 F 35 128 1

LOGIC_DRIVES(x, LogicDriveLetter, RootFolder)

x LogicDriveLetter RootFolder

auton.(2) [‘A’, …, ‘Z’] Im(FILES.x)

NOT NULL NOT NULL

1 C 1

2 D

Non-relational constraints are:

C5’: (x,y FILES) ((Ext(x) NULLS Ext(y) NULLS)

Name Folder LogicDrive(x) Name Folder LogicDrive(y)))

(note that C5 C5’ Name Ext Folder LogicDrive key)

C6: (xFILES)(Size(x) > 0 StartAddress(x) NULLS)

C7: (xFILES)(Folder?(x) Size(x) = 0)

C8: (xFILES)(Size(x) = 0 StartAddress(x) NULLS)

C15: (xFILES)(Name(x) = “\” Ext(x) NULLS

Folder(x) NULLS)

C16: (xFILES)(yLOGIC_DRIVES)

((Folder(x) NULLS Name(x) = “\” Ext(x) NULLS)

(x = RootFolder(y) Folder(x) NULLS))

C17: (xFILES)(Folder?(Folder(x)))

C18: (xFILES)(LogicDrive(Folder(x)) = LogicDrive(x))

C19: (xFILES)((Name(x) “\” Ext(x) NULLS)

RootFolder(LogicDrive(x) NULLS)

C20: LogicDrive RootFolder = 1LOGIC_DRIVES

C21: Folder : FILES FILES, acyclic

Page 360: Laborator Baze date

354

11.2.1 Access implementation

Applying the algorithm for translating relational schemes into Access dbs,

the following three DDL SQL statements are needed (20 points):

createFILES:

CREATE TABLE FILES (x COUNTER PRIMARY KEY, Name

VARCHAR(255) NOT NULL, Ext VARCHAR(255), Folder

Long, CONSTRAINT fkFolder FOREIGN KEY (Folder)

REFERENCES FILES, Size Double NOT NULL, [Folder?]

BIT NOT NULL, StartAddress Double UNIQUE,

LogicDrive Long NOT NULL, CONSTRAINT skFILES UNIQUE

(Name, Ext, Folder, LogicDrive));

createLOGIC_DRIVES:

CREATE TABLE LOGIC_DRIVES (x COUNTER PRIMARY KEY,

LogicDriveLetter CHAR(1) NOT NULL UNIQUE,

RootFolder Long UNIQUE, CONSTRAINT fkRootFolder

FOREIGN KEY (RootFolder) REFERENCES FILES);

alterFILES:

ALTER TABLE FILES ADD CONSTRAINT fkLogicDrive

FOREIGN KEY (LogicDrive) REFERENCES LOGIC_DRIVES;

Through Access’ GUI, the following has to to be added to this db (29

points):

- For all text columns (Name, Ext, and LogicDriveLetter) correspond-

ing Allow zero length property should be turned to No (for rejecting

dirty nulls).

- For all numeric ones (Size, StartAddress), as well as text ones that

have as (co-)domains subsets of Access’ data types (LogicDriveLet-

ter), their Validation Rule and Text properties should be filled accor-

dingly:

LogicDriveLetter: Between “A” and “Z” (“Valid logic

drive letters are between A and Z!”) (alternatively, and even

better, you might turn this text box into a combo one and

attach to it a value list containing all capital letters between

“A” and “Z”);

Page 361: Laborator Baze date

355

Size and StartAddress: Between 0 and 10^24-1 (“Va-

lid file size/start address values are between 0 and 10^24 –

1!”);

- For all columns for which default values might help insertions, the

corresponding Default properties should be added too:

Size: 0

Folder?: False

- For all foreign keys (Folder, LogicDrive, RootFolder), corresponding

text boxes should be replaced by combo ones, for hiding pointers and

displaying instead corresponding semantic key values:

Folder: SELECT FILES.x, [LogicDriveLetter] & ":\..." &

IIf(IsNull([FILES].[Folder]),"\",[FOLDERS].[Name] &

IIf(IsNull([FOLDERS].[Ext]),"","." &

[FOLDERS].[Ext]) & "\") & [FILES].[Name] &

IIf(IsNull([FILES].[Ext]),"","." & [FILES].[Ext])

AS Path

FROM LOGIC_DRIVES INNER JOIN (FILES LEFT JOIN FILES

AS FOLDERS ON FILES.Folder = FOLDERS.x)

ON LOGIC_DRIVES.x = FILES.LogicDrive

WHERE FILES.[Folder?]

ORDER BY [LogicDriveLetter] & ":\..." &

IIf(IsNull([FILES].[Folder]),"\",[FOLDERS].[Name] &

IIf(IsNull([FOLDERS].[Ext]),"","." &

[FOLDERS].[Ext]) & "\") & [FILES].[Name] &

IIf(IsNull([FILES].[Ext]),"","." & [FILES].[Ext]);

LogicDrive: SELECT x, LogicDriveLetter FROM LOGIC_DRIVES

ORDER BY LogicDriveLetter;

RootFolder: SELECT FILES.x, [LogicDriveLetter] & ":\..." &

IIf(IsNull([FILES].[Folder]),"\",[FOLDERS].[Name] &

IIf(IsNull([FOLDERS].[Ext]),"","." &

[FOLDERS].[Ext]) & "\") & [FILES].[Name] &

IIf(IsNull([FILES].[Ext]),"","." & [FILES].[Ext])

AS Path

FROM LOGIC_DRIVES INNER JOIN (FILES LEFT JOIN FILES

AS FOLDERS ON FILES.Folder = FOLDERS.x)

ON LOGIC_DRIVES.x = FILES.LogicDrive

WHERE FILES.[Folder?] AND IsNull(FILES.Folder)

ORDER BY [LogicDriveLetter] & ":\..." &

IIf(IsNull([FILES].[Folder]),"\",[FOLDERS].[Name] &

IIf(IsNull([FOLDERS].[Ext]),"","." &

[FOLDERS].[Ext]) & "\") & [FILES].[Name] &

IIf(IsNull([FILES].[Ext]),"","." & [FILES].[Ext]);

Page 362: Laborator Baze date

356

For populating the two tables with their demos rows the following five SQL

DML statements are needed (3 points):

INSERT INTO LOGIC_DRIVES(LogicDriveLetter) VALUES ("C");

INSERT INTO LOGIC_DRIVES(LogicDriveLetter) VALUES ("D");

INSERT INTO FILES(Name, Size, [Folder?], LogicDrive)

VALUES ("\", 0, True, 1);

INSERT INTO FILES(Name, Ext, Folder, Size, StartAddress,

LogicDrive) VALUES ("boot", "ini", 1, 35, 128, 1);

UPDATE LOGIC_DRIVES SET RootFolder = 1 WHERE x = 1;

According to the algorithm for assisting enforcement of non-relational con-

straints in Access, in order to enforce the above non-relational constraints we

first have to create (by using the Form Wizard) the two corresponding data-

sheet forms LOGIC_ DRIVES and FILES (and preferably embed the latter as

a subform of the former, linked on LOGIC_DRIVES.x = FILES.LogicFile).54

- C5’: (x,y FILES) ((Ext(x) NULLS Ext(y) NULLS)

Name Folder LogicDrive(x) Name Folder LogicDrive(y)))

Obviously, it has to be enforced in class Form_FILES; as three of its co-

lumns are involved, the needed event is Form_BeforeUpdate (14 points):

'***********************************************

Private Sub Form_BeforeUpdate(Cancel As Integer)

'***********************************************

On Error GoTo err_point

'enforces constraint C5'

If IsNull(Me!Ext) Then

If Not IsNull(Me!Folder) Then

If Not IsNull(DLookup("x", "FILES", "Name='" & Me!Name _

& "' AND Ext Is Null AND Folder=" & Me!Folder & _

" AND LogicDrive=" & Me!LogicDrive & " AND x<>" & _

Me!x)) Then

Cancel = True

End If

Else

If Not IsNull(DLookup("x", "FILES", "Name='" & Me!Name _

& "' AND Ext Is Null AND Folder Is Null AND x<>" _

& Me!x & " AND LogicDrive=" & Me!LogicDrive)) Then

Cancel = True

End If

End If

If Cancel Then

MsgBox "Please change either Name, Ext, or Folder!", _

vbCritical, "There exists a file with same name " _

54

2 points

Page 363: Laborator Baze date

357

& "and no extension in this folder..."

End If

End If

Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_FILES.Form_BeforeUpdate..."

Cancel = True

End Sub

- C6: (xFILES)(Size(x) > 0 StartAddress(x) NULLS)

Obviously, it has to be enforced in class Form_FILES; as two of its columns

are involved, the needed event is Form_BeforeUpdate too, so the following

code should be added to the above method before Exit Sub (5 points):

'enforces constraint C6

If Me!Size > 0 And IsNull(Me!StartAddress) Then

Cancel = True

MsgBox "Please either change Size or specify the " & _

"StartAddress!", vbCritical, _

"StartAddress is compulsory when Size > 0..."

End If

- C7: (xFILES)(Folder?(x) Size(x) = 0)

Obviously, it has to be enforced in class Form_FILES; as two of its columns

are involved, the needed event is Form_BeforeUpdate too, so the following

code should be added to the above method before Exit Sub (5 points):

'enforces constraint C7

If Me![Folder?] And Me!Size <> 0 Then

Cancel = True

MsgBox "Please change Size to 0!", vbCritical, _

"Folders should have Size = 0..."

End If

- C8: (xFILES)(Size(x) = 0 StartAddress(x) NULLS)

Obviously, it has to be enforced in class Form_FILES; as two of its columns

are involved, the needed event is Form_BeforeUpdate too, so the following

code should be added to the above method before Exit Sub (5 points):

'enforces constraint C8

If Me!Size = 0 And Not IsNull(Me!StartAddress) Then

Cancel = True

MsgBox " Please either change Size or delete the " & _

"StartAddress!", vbCritical, _

"When Size = 0 there should not be StartAddress..."

End If

- C15: (xFILES)(Name(x) = “\” Ext(x) NULLS

Folder(x) NULLS)

Page 364: Laborator Baze date

358

Obviously, it has to be enforced in class Form_FILES; as three columns are

involved, the needed event is Form_BeforeUpdate, so the following code

should be added to the above method before Exit Sub (5 points):

'enforces constraint C15

If IsNull(Me!Folder) And (Me!Name<>"\" Or Not IsNull(Ext)) _

Then

Cancel = True

MsgBox "Please specify the folder to which this file" _

& " belongs!", vbCritical, "Only root folders do " _

& "not belong to any folder..."

End If

- C16: (xFILES)(yLOGIC_DRIVES)

((Folder(x) NULLS Name(x) = “\” Ext(x) NULLS)

(x = RootFolder(y) Folder(x) NULLS))

Obviously, the first half ((xFILES) (Folder(x) NULLS Name(x) =

“\” Ext(x) NULLS)) has to be enforced in class Form_FILES; as two of

its columns are involved, the needed event is Form_BeforeUpdate too, so the

following code should be added to the above method before Exit Sub (8

points):

'enforces constraint C16

If IsNull(Me!Folder) Then

If Me!Name <> "\" Or Not IsNull(Me!Ext) Then

Cancel = True

MsgBox "Please change Name and/or Ext!", vbCritical, _

"Root folder Name should be '\' and Ext should be " _

& "null…"

End If

Else

If Me!Name = "\" And IsNull(Me!Ext) Then

Cancel = True

MsgBox "Please change Name, Ext, and/or Folder!", _

vbCritical, _

"Only root folders may have Name = '\' and Ext null…"

End If

End If

Its second half ((yLOGIC_DRIVES)(x = RootFolder(y) Folder(x)

NULLS)) has already been enforced by the Lookup SELECT statement for

RootFolder (see above, the AND IsNull(FILES.Folder)second half of

the WHERE clause) (2 points).

- C17: (xFILES)(Folder?(Folder(x)))

Page 365: Laborator Baze date

359

This constraint has already been enforced by the Lookup SELECT statement

for Folder (see above, the WHERE FILES.[Folder?]clause) (2 points).

- C18: (xFILES)(LogicDrive(Folder(x)) = LogicDrive(x))

Obviously, it has to be enforced in class Form_FILES; as two of its columns

are involved, the needed event is Form_BeforeUpdate too, so the following

code should be added to the above method before Exit Sub (5 points):

'enforces constraint C18

If Not IsNull(Me!Folder) Then

If Me!LogicDrive <> DLookup("LogicDrive", "FILES", "x=" _

& Me!Folder) Then

Cancel = True

Me!Folder.SetFocus

MsgBox "Please change Folder!", vbCritical, _

"Chosen folder belongs to a different logic drive..."

End If

End If

- C19: (xFILES) ((Name(x) “\” Ext(x) NULLS)

RootFolder(LogicDrive(x) NULLS)

Obviously, it has to be enforced in class Form_FILES; as only column is

involved (LogicDrive), apparently, the needed event is LogicDrive_Before-

Update; in fact, as form FILES is used as a linked subform of LOGIC_

DRIVES, LogicDrive values are automatically filled-in by the system, so that

enforcement of this constraint has to be postponed up to the Form_Before-

Update moment; consequently, the following code should be added to the

above method before Exit Sub (6 points):

'enforces constraint C19

If Me!Name <> "\" Or Not IsNull(Me!Ext) Then

If IsNull(DLookup("RootFolder", "LOGIC_DRIVES", "x=" & _

Me!LogicDrive)) Then

Cancel = True

MsgBox "Please first specify the root folder for this " _

& "logic drive!", vbCritical, _

"Unformatted logic drive..."

End If

End If

- C20: LogicDrive RootFolder = 1LOGIC_DRIVES

Obviously, this constraint may be easily enforced in the Form_Current me-

thod of the class Form_LOGIC_DRIVES, by adding a corresponding dyna-

mic filter to the SELECT statement of the combo box RootFolder (for elimi-

nating from the set of all existing root folders all those that belong to other

logical drives than the current one) and then requerying it (note that on the

blank line, the empty set should be computed instead) (7 points):

Page 366: Laborator Baze date

360

'*************************

Private Sub Form_Current()

'*************************

On Error GoTo err_point

'enforces constraint C20

If Me.NewRecord Then

Me!RootFolder.RowSource = "SELECT x, x FROM FILES WHERE " _

& "x <> x"

Else

Me!RootFolder.RowSource = _

"SELECT FILES.x, [LogicDriveLetter] & ':\...' & " & _

"IIf(IsNull([FILES].[Folder]),'\',[FOLDERS].[Name] & " _

& "IIf(IsNull([FOLDERS].[Ext]),'','.' & " & _

" [FOLDERS].[Ext]) & '\') & [FILES].[Name] & " & _

"IIf(IsNull([FILES].[Ext]),'','.' & [FILES].[Ext]) " & _

"AS Path " & _

"FROM LOGIC_DRIVES INNER JOIN (FILES LEFT JOIN FILES " _

& "AS FOLDERS ON FILES.Folder = FOLDERS.x) " & _

"ON LOGIC_DRIVES.x = FILES.LogicDrive " & _

"WHERE FILES.[Folder?] And IsNull(FILES.Folder) " & _

"AND FILES.LogicDrive=" & Me!x & _

" ORDER BY [LogicDriveLetter] & ':\...' & " & _

"IIf(IsNull([FILES].[Folder]),'\',[FOLDERS].[Name] & " _

& "IIf(IsNull([FOLDERS].[Ext]),'','.' & " & _

" [FOLDERS].[Ext]) & '\') & [FILES].[Name] & " & _

"IIf(IsNull([FILES].[Ext]),'','.' & [FILES].[Ext])"

End If

Me!RootFolder.Requery

Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_LOGIC_DRIVES.Form_Current..."

End Sub

- C21: Folder : FILES FILES, acyclic

In order to may able to compute the transitive closure of Folder’s graph, we

first need to create the corresponding results table (1.5 points):

createFolderTransClosure: CREATE TABLE FolderTransClosure(x Long, Folder Long, [Level]

Long);

Then, obviously, this last non-relational constraint has to be enforced in class

Form_FILES; although, apparently, only column Folder is involved, for new

lines the corresponding logic drive might not be yet specified; consequently,

the needed event for enforcing this constraint is Form_BeforeUpdate, where

the following code should be added before Exit Sub (30.5 points):

'enforces constraint C21

If Not Me.NewRecord And Me!Folder = Me!Folder.OldValue Then _

GoTo exit_point

If Me!Folder = Me!x Then 'irreflexivity

Page 367: Laborator Baze date

361

Cancel = True

Me!Folder.Undo

MsgBox "Please change Folder!", _

vbCritical, "No folder may belong to itself..."

Else 'acyclicity

Dim level As Integer

Dim oldcard, card As Double

DoCmd.RunSQL "DELETE FROM FolderTransClosure"

oldcard = 0

DoCmd.RunSQL "INSERT INTO FolderTransClosure(x, Folder, " _

& "[Level]) SELECT x, Folder, 0 FROM FILES WHERE " & _

"[Folder?] AND LogicDrive=" & Me!LogicDrive

If Me.NewRecord Then

If IsNull(Me!Folder) Then

DoCmd.RunSQL "INSERT INTO FolderTransClosure(x, Fol" _

& "der, [Level]) VALUES (" & Me!x & ", NULL, 0)"

Else

DoCmd.RunSQL "INSERT INTO FolderTransClosure(x, Fol" _

& "der, [Level]) VALUES (" & Me!x & ", " & _

Me!Folder & ", 0)"

End If

Else

If IsNull(Me!Folder) Then

DoCmd.RunSQL "UPDATE FolderTransClosure SET Folder=" _

& "NULL WHERE x=" & Me!x

Else

DoCmd.RunSQL "UPDATE FolderTransClosure SET Folder=" _

& Me!Folder & " WHERE x=" & Me!x

End If

End If

card = DCount("*", "FolderTransClosure")

level = 1

While oldcard <> card And Not Cancel

oldcard = card

DoCmd.RunSQL "INSERT INTO FolderTransClosure(x, Folder" _

& ", [Level]) SELECT FolderTransClosure.x, FILES." _

& "Folder, " & level & _

" FROM FolderTransClosure INNER JOIN FILES " & _

"ON FolderTransClosure.Folder = FILES.x " & _

"WHERE [Folder?] AND LogicDrive=" & Me!LogicDrive & _

" AND [Level]=" & level - 1

If Not IsNull(DLookup("x", "FolderTransClosure", _

"x = Folder")) Then

Cancel = True

Me!Folder.Undo

MsgBox "Please change Folder as this one would " _

& "create a cycle!", vbCritical, _

"Folders tree hierarchy should be cycle-free..."

Else

card = DCount("*", "FolderTransClosure")

level = level + 1

Page 368: Laborator Baze date

362

End If

Wend

End If

Total points with Access implementation: 200.

11.2.2 Oracle implementation

Applying the algorithm for translating relational schemes into Oracle dbs,

the following three DDL SQL statements are needed:

Total points with Oracle implementation: 200.

11.3 Best practice rules BPRR1. For any Access report, first design, test, and save independently

its subjacent query; then you can embed it in the report, by replacing the

query name with its body.

BPRR2. For any Access report, do not order the subjacent query: report

grouping and sorting might conflict with your initial order and, anyhow,

ARGM sorts as fast as the ORDER BY clause.

BPRR3. For any Access report, do not forget to program the No Data

event, such that empty reports are replaced by corresponding information

messages.

11.4 Homework H11.1 Modify the report from P11.1 above such that:

- Countries and states are printed first in the descending order of their

population and only then ascendingly on their names.

- The following new computed data is added (both in absolute and per-

centage values): unaccounted cities populations per states, unaccoun-

ted states populations per countries, and unaccounted world popula-

tion.

H11.2 Consider the following E-RD (on mountains) from the GeografieBD

db (where VÂRFURI = PEAKS, MASIVE = MOUNTAINS, GRUPE_MUNTI

= MOUNTAIN_GROUPS, SUBLANTURI = SUBCHAINS, LanturiMuntoase

Page 369: Laborator Baze date

363

= MOUNTAIN_CHAINS, CONTINENTE = CONTINENTS, Suprafata =

Area, Lungime = Length, Altitudine = Altitude, AltPunctCulminant = High-

estAltitude, LantMuntos = MountainChainName, Vârf = PeakName, Tara =

Country, DenLocala = LocalPeakName):

Figure 11.38 GeografieBD mountains chain

Design, implement in Access, and test a report for printing continents names,

area, total mountain area (absolute and percent of the continent area), and

highest altitude (as the outer group, sorted by names), mountain chains

names and areas (second group, sorted by area descendingly and then by

names ascendingly), mountain sub-chains names, length, and areas (third

group, sorted by area and length descendingly and then by names ascending-

ly), mountain groups names, length, and areas (fourth group, sorted by area

and length descendingly and then by names ascendingly), mountains names,

length, and areas (fifth group, sorted by area and length descendingly and

then by names ascendingly), and peaks names, local names, altitude and

country (sorted descendingly by altitude and then ascendingly by country

and peak name), only for peaks having at least 2,000m altitude, with totals of

number of peaks and average of their altitude per country, mountain, group,

sub-chain, chain, and continent, totals of sum of length per group, sub-chain,

and chain, totals of sum of area per group, sub-chain, chain, and continent, as

well as a grand total of all of this data.

NOTE: Do not forget that next week you will have to pass your second

DB test, on db scheme design and implementation!

Page 370: Laborator Baze date

364

Chapter 12. 12th Lab: Second Test (DB Design &

Implementation)

12.1 Subject 1 Consider the countries and territories of the world, for which only English

name, official name, suzerain power, capital city (name and country), GDP,

population, and area are of interest. Hint: only very big cities are of interest.

Design the db fragment needed for storing this data and implement it on the

platform of your choice; also add at least two plausible rows per table. Total

points: 180, 2h.

Solution:

Obviously, the corresponding E-RD (10 points) and restrictions list (8

points) are the following:

EnglishName OfficialName GDP Population Area

Suzerain COUNTRIES

Capital Country

CITIES City

COUNTRIES (The set of all existing countries and territories of interest)

Max. cardinality: 250 (R0)

Ranges:

- EnglishName and OfficialName: ASCII(255) (R1)

- Population: [100,…, 2,000,000] (R2)

- GDP (US$ billions) and Area (square km.): [0.1, …, 20,000,000] (R3)

Mandatory: EnglishName (R4)

Uniqueness: Capital (no city may simultaneously be the capital of more

than one country) (R5)

CITIES (The set of all world cities of interest)

Max. cardinality: 1,000,000 (R6)

Ranges: City: ASCII(255) (R7)

Mandatory: City and Country (R8)

Uniqueness: there may not be two (very big) cities of a same country

Page 371: Laborator Baze date

365

having same names (R9)

The result of applying the translation algorithm from E-RDs and restriction

lists into mathematical schemes is the following (12 points):

COUNTRIES

x NAT(3), total (according to R0)

EnglishName ASCII(255), total (according to R1 and R4)

OfficialName ASCII(255) (according to R1)

GDP [0.1; 20,000,000] (according to R2)

Area [0.1; 20,000,000] (according to R2)

Population [10; 2,000,000,000] (according to R3)

Suzerain : COUNTRIES COUNTRIES

CITIES

x NAT(6), total (according to R6)

City ASCII(255), total (according to R7 and R8)

Capital : COUNTRIES CITIES (according to R5)

Country : CITIES COUNTRIES, total (according to R8)

C9: City Country key (according to R9)

The results of applying the first refinement algorithm (for assisting sets,

functions, and constraints design) are the following (18 points):

a. Sets: both COUNTRIES and CITIES are atomic type object sets not

semantically overloaded.

b. Functions:

- EnglishName is well defined as any country has an English name and

only one;

one-to-oneness: there may no be two countries having same English

name constraint EnglishName key should be added to the db

scheme;

ontoness: not any combination of 255 ASCII characters should be a

country English name;

- OfficialName is well defined as any country has an official name and

only one;

one-to-oneness: there may no be two countries having same official

name constraint OfficialName key should be added to the db

scheme;

Page 372: Laborator Baze date

366

ontoness: not any combination of 255 ASCII characters should be a

country official name;

- GDP is well defined as any country has one associated GDP and only

one;

one-to-oneness: there may be two countries having same GDP;

ontoness: not any number between 0.1 and 20,000,000 should be the

GDP of a country;

- Population is well defined as any country has one associated total

population number and only one;

one-to-oneness: there may be two countries having same population;

ontoness: not any number between 10 and 20,000,000,000 should be

the population of a country;

- Area is well defined as any country has one associated area and only

one;

one-to-oneness: there may be two countries having same area;

ontoness: not any number between 0.1 and 20,000,000 should be the

area of a country;

- Suzerain is well defined as any subordinated country (territory) has

one suzerain power and only one;

one-to-oneness: there may be two countries having same suzerain;

ontoness: not any country is a suzerain power;

homogeneous binary relationship constraints: no country may be its

own suzerain power, either directly or indirectly constraint Suze-

rain acyclic should be add to the db scheme;

- Capital is well defined as any country has one capital city and only

one;

one-to-oneness: no city may simultaneously be the capital of more

than one country;

ontoness: not any city should be a country capital;

- City is well defined as any city has one name and only one;

one-to-oneness: there may be two cities having same name (but in

different countries);

ontoness: not any combination of 255 ASCII characters should be a

city name;

- Country is well defined as any city belongs to one country and only

one;

Page 373: Laborator Baze date

367

one-to-oneness: there may be two cities belonging to a same country;

ontoness: not any country should have a city (in the db’s instance);

c. Constraints: no other constraints apply to this subuniverse.

The results of applying the second refinement algorithm (for assisting keys

discovery) are the following (8 points):

COUNTRIES

n = 4 (GDP, Population, Area, Suzerain), K = {Capital, EnglishName,

OfficialName};

nonprimeness: obviously, GDP, Population, and Area are all nonprime, as

they might not contribute to countries’ unique identification;

n’ = 1 (Suzerain) nothing to do as Suzerain is not one-to-one.

CITIES

n = 2 (City, Country), K = {City Country};

nothing to do as neither City, nor Country is not one-to-one.

Consequently, neither COUNTRIES, nor CITIES have other semantic keys.

The results of applying the third refinement algorithm (for assisting analysis

of E-RD cycles) are the following (6 points):

There are two cycles in this E-RD: Suzerain (that was already investigated

above) and the unidirectional one made out of Capital : COUNTRIES

CITIES and Country : CITIES COUNTRIES. For this latter one, possible

local commutativities should be investigated in both of its nodes:

- Capital Country =? 1CITIES (should any city be the capital of the

country to which belongs?); obviously no, as not every city is a capi-

tal of its country;

- Country Capital =? 1COUNTRIES (should any capital city of a country

belong to that country?); obviously yes, as no country may have as its

capital a city from another country constraint Country Capital =

1COUNTRIES should be added to the db scheme.

The finally obtained mathematical scheme is the following (15 points):

COUNTRIES

Page 374: Laborator Baze date

368

x NAT(3), total

EnglishName ASCII(255), total

OfficialName ASCII(255)

GDP [0.1; 20,000,000]

Area [0.1; 20,000,000]

Population [10; 2,000,000,000]

Suzerain : COUNTRIES COUNTRIES, acyclic

CITIES

x NAT(6), total

City ASCII(255), total

Capital : COUNTRIES CITIES

Country : CITIES COUNTRIES, total

C9: City Country key

C10: Country Capital = 1COUNTRIES

Applying the algorithm for translating mathematical schemes into relational

ones (23 points) and non-relational constraint lists (2 points) yields the fol-

lowing:

COUNTRIES (x, Capital, EnglishName, OfficialName)

x English-

Name

Official-

Name

GDP Area Popu

la-

tion

Suze

rain

Capi-

tal

auton(

3)

ASCII(255) ASCII(255) [0.1,

2*107

]

[0.1,

2*107

]

[10;

2*109]

Im

(x)

Im(CI-

TIES.x

)

NOT

NULL

NOT

NULL

1 U.K. United

Kindom

1

2 Canada Canada 1 3

Page 375: Laborator Baze date

369

CITIES (x, City Country)

x City Country

auoton(6) ASCII(255) Im(COUNTRIES.x)

NOT NULL NOT NULL NOT NULL

1 London 1

2 Toronto 2

3 Ottawa 2

The corresponding non-relational constraint list is the following (2 points):

C10: Country Capital = 1COUNTRIES

C11: Suzerain : COUNTRIES COUNTRIES, acyclic

12.2.1 Access implementation

Applying the algorithm for translating relational schemes into Access dbs,

the following three DDL SQL statements are needed (18 points):

createCOUNTRIES:

CREATE TABLE COUNTRIES (x COUNTER PRIMARY KEY,

EnglishName VARCHAR(255) NOT NULL UNIQUE,

OfficialName VARCHAR(255) UNIQUE, GDP Double, Area

Double, Population Double, Capital Long UNIQUE,

Suzerain LONG, CONSTRAINT fkSuzerain FOREIGN KEY

(Suzerain) REFERENCES COUNTRIES);

createCITIES:

CREATE TABLE CITIES (x COUNTER PRIMARY KEY, City

VARCHAR(255) NOT NULL, Country Long NOT NULL,

CONSTRAINT fkCountry FOREIGN KEY (Country)

REFERENCES COUNTRIES, CONSTRAINT kCITIES UNIQUE

(City, Country));

alterCOUNTRIES:

ALTER TABLE COUNTRIES ADD CONSTRAINT fkCapital

FOREIGN KEY (Capital) REFERENCES CITIES;

Through Access’ GUI, the following has to to be added to this db (14

points):

Page 376: Laborator Baze date

370

- For all text columns (EnglishName, OfficialName, and Country) cor-

responding Allow zero length property should be turned to No (for

rejecting dirty nulls).

- For all numeric ones (GDP, Area, Population) that have as (co-)do-

mains subsets of Access’ data types, their Validation Rule and Text

properties should be filled accordingly:

GDP and Area: Between 0.1 and 2*10^7 (“Valid

GDP/Area values are between 0.1 and 2*10^7!”);

Population: Between 10 and 2*10^9 (“Valid Popula-

tion values are between 10 and 2*10^9!”);

- For all foreign keys (Suzerain, Capital, Country), corresponding text

boxes should be replaced by combo ones, for hiding pointers and dis-

playing instead corresponding semantic key values:

Suzerain and Country: SELECT x, EnglishName FROM COUNTRIES

ORDER BY EnglishName;

Capital: SELECT CITIES.x, [City] & ", " & [EnglishName] AS Capital FROM COUNTRIES INNER JOIN CITIES

ON COUNTRIES.x = CITIES.Country

ORDER BY [City] & ", " & [EnglishName];

For populating the two tables with their demos rows the following seven

SQL DML statements are needed (7.5 points): INSERT INTO COUNTRIES(EnglishName, OfficialName)

VALUES ("U.K.", "United Kingdom");

INSERT INTO COUNTRIES(EnglishName, OfficialName, Suzerain)

VALUES ("Canada", "Canada", 1);

INSERT INTO CITIES(City, Country) VALUES ("London", 1);

INSERT INTO CITIES(City, Country) VALUES ("Toronto", 2);

INSERT INTO CITIES(City, Country) VALUES ("Ottawa", 2);

UPDATE COUNTRIES SET Capital = 1 WHERE x = 1;

UPDATE COUNTRIES SET Capital = 3 WHERE x = 2;

According to the algorithm for assisting enforcement of non-relational con-

straints in Access, in order to enforce the above non-relational constraints we

first have to create (by using the Form Wizard) the datasheet form COUN-

TRIES (1 point).

- C10: Country Capital = 1COUNTRIES

Page 377: Laborator Baze date

371

Obviously, this constraint may be easily enforced in the Form_Current me-

thod of the class Form_COUNTRIES, by adding a corresponding dynamic

filter to the SELECT statement of the combo box Capital (for eliminating

from the set of all existing cities all those that belong to other countries than

the current one) and then requerying it (note that on the blank line, the empty

set should be computed instead) (5 points):

'*************************

Private Sub Form_Current()

'*************************

On Error GoTo err_point

'enforces constraint C10

If Me.NewRecord Then

Me!Capital.RowSource = "SELECT x, x FROM COUNTRIES WHERE" _

& " x <> x;"

Else

Me!Capital.RowSource = _

"SELECT CITIES1.x, [City] & ', ' & [EnglishName] " & _

"AS Capital FROM COUNTRIES1 INNER JOIN CITIES1 " & _

"ON COUNTRIES1.x = CITIES1.Country " & _

"WHERE COUNTRIES1.x=" & Me!x & _

" ORDER BY [City] & ', ' & [EnglishName];"

End If

Me!Capital.Requery

Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_COUNTRIES.Form_Current..."

End Sub

- C11: Suzerain : COUNTRIES COUNTRIES, acyclic

In order to may able to compute the transitive closure of Suzerain’s graph,

we first need to create the corresponding results table (1.5 points):

createSuzerainTransClosure: CREATE TABLE FolderTransClosure(x Long, Suzerain Long,

[Level] Long);

Then, obviously, this last non-relational constraint has to be enforced in class

Form_COUNTRIES; as only column Suzerain is involved, the needed event

for enforcing this constraint is Suzerain_BeforeUpdate: the following code

should be added to this class (31 points):

'***************************************************

Private Sub Suzerain_BeforeUpdate(Cancel As Integer)

'***************************************************

On Error GoTo err_point

'enforces constraint C11

If Not Me.NewRecord And Me!Suzerain = Me!Suzerain.OldValue _

Then GoTo exit_point

If Me!Suzerain = Me!x Then 'irreflexivity

Page 378: Laborator Baze date

372

Cancel = True

Me!Suzerain.Undo

MsgBox "Please change Suzerain!", _

vbCritical, "No country may be its own suzerain..."

Else 'acyclicity

Dim level As Integer

Dim oldcard, card As Double

DoCmd.RunSQL "DELETE FROM SuzerainTransClosure"

oldcard = 0

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, Suze" _

& "rain, [Level]) SELECT x, Suzerain, 0 FROM COUNTRIES"

If Me.NewRecord Then

If IsNull(Me!Suzerain) Then

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain, [Level]) VALUES (" & Me!x & ", NULL, 0)"

Else

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain, [Level]) VALUES (" & Me!x & ", " & _

Me!Suzerain & ", 0)"

End If

Else

If IsNull(Me!Suzerain) Then

DoCmd.RunSQL "UPDATE SuzerainTransClosure " _

& " SET Suzerain = NULL WHERE x=" & Me!x

Else

DoCmd.RunSQL "UPDATE SuzerainTransClosure " _

& "SET Suzerain =" & Me!Suzerain & " WHERE x=" & Me!x

End If

End If

card = DCount("*", "SuzerainTransClosure")

level = 1

While oldcard <> card And Not Cancel

oldcard = card

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain,[Level]) SELECT SuzerainTransClosure.x," _

& "COUNTRIES.Suzerain, " & level & _

" FROM SuzerainTransClosure INNER JOIN COUNTRIES " & _

"ON SuzerainTransClosure.Suzerain = COUNTRIES.x " & _

"WHERE [Level]=" & level - 1

If Not IsNull(DLookup("x", "SuzerainTransClosure", _

"x = Suzerain")) Then

Cancel = True

Me!Suzerain.Undo

MsgBox "Please change Suzerain as this one would " _

& "create a cycle!", vbCritical, "Suzerains " _

& "tree hierarchy should be cycle-free..."

Else

card = DCount("*", "SuzerainTransClosure")

level = level + 1

End If

Wend

Page 379: Laborator Baze date

373

End If

exit_point: Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_COUNTRIES.Capital_BeforeUpdate..."

Cancel = True

End Sub

12.1.2 Oracle implementation

Applying the algorithm for translating relational schemes into Oracle dbs,

the following three DDL SQL statements are needed:

12.2 Subject 2

12.2.1 Access implementation

Applying the algorithm for translating relational schemes into Access dbs,

the following three DDL SQL statements are needed:

12.2.2 Oracle implementation

Applying the algorithm for translating relational schemes into Oracle dbs,

the following three DDL SQL statements are needed:

Page 380: Laborator Baze date

374

Chapter 13. 13th Lab: Test Redoing (SQL or DB Design &

Implementation)

13.1 SQL test redoing

90 minutes, 45 points, open book, individual, no electronic devices

a. (7p.)

Consider the following table:

RIVERS(x, River)

x River Length

auton(8) ASCII(64) [1, 7000]

NOT NULL NOT NULL

1 Danube 2850

2 Olt

3 Lotru

Design and develop a SQL script for creating this table including its instance

and then for also adding to it the rivers “Paraguay” and “Parana” (Hint: do

not let the system to automatically name the semantic key, but name it your-

self!).

b. (14p.) Design and develop a SQL script for adding the function Tributa-

ryTo : RIVERS RIVERS, for changing the key to River TributaryTo, and

then storing the facts that “Olt” is tributary to the “Danube”, “Lotru” to

“Olt”, and “Paraguay” to “Parana”, but without using the x values for none

of them.

c. (Only in Access)(6p.) Describe needed steps for converting TributaryTo to

a lookup combo-box, without using the Lookup Wizard.

c. (Only in Oracle) (3.5p.)

d. (18p Access/18p Oracle) Compute in SQL, without using subqueries, the

set of triples <River, TributariesNo, GrandTributariesNo> (Hint: “Lotru” is

a great tributary to the “Danube”, for example), in the descending order of

TributariesNo and GrandTributariesNo, and then ascending on River, for all

rivers that have at least k tributary ones, each of which having at least n

Page 381: Laborator Baze date

375

tributaries (k and n being natural parameters). Which is the result for the

above RIVERS instance when k = 1, n = 0; k = n = 1; and k = 1, n = 2?

6.1.1 Access solution

a. CREATE TABLE RIVERS(x COUNTER PRIMARY KEY, River VARCHAR(64)

NOT NULL, Length LONG, CONSTRAINT kRIVERS UNIQUE (River));

(4.5p) INSERT INTO RIVERS(River, Length) VALUES ("Danube", 2850);

(0.5p)

INSERT INTO RIVERS(River) VALUES ("Olt"); (0.5p)

INSERT INTO RIVERS(River) VALUES ("Lotru"); (0.5p)

INSERT INTO RIVERS(River) VALUES ("Paraguay"); (0.5p)

INSERT INTO RIVERS(River) VALUES ("Parana"); (0.5p)

b.

ALTER TABLE RIVERS ADD COLUMN TributaryTo LONG; (1.5p)

ALTER TABLE RIVERS ADD CONSTRAINT fkTributaryTo FOREIGN KEY (TributaryTo) REFERENCES RIVERS; (2p)

ALTER TABLE RIVERS DROP CONSTRAINT kRIVERS; (1p)

ALTER TABLE RIVERS ADD CONSTRAINT kRIVERS UNIQUE (River,

TributaryTo)); (2p) UPDATE RIVERS SET TributaryTo = DLookup("x", "RIVERS",

"River='Danube'") WHERE River = "Olt"; (2.5p) UPDATE RIVERS SET TributaryTo = DLookup("x", "RIVERS",

"River='Olt'") WHERE River = "Lotru"; (2.5p)

UPDATE RIVERS SET TributaryTo = DLookup("x", "RIVERS",

"River='Parana'") WHERE River = "Paraguay"; (2.5p)

c.

- open RIVERS in Design mode; (0.5p)

- on the TributaryTo line, in the Lookup tab, switch the Display Control

property from Text to Combo box; (0.5p)

- in the Row Source property, type:

SELECT x, River FROM RIVERS ORDER BY River; (2p)

- set the Column Count property to 2; (0.5p)

- set the Column Width property to 0”;4”; (0.5p)

- set the List Rows property to 32; (0.5p)

- set the List Width property to 4”; (0.5p)

Page 382: Laborator Baze date

376

- set the Limit to List property to Yes; (0.5p)

- save and close the table scheme window. (0.5p)

d.

- step 1: rivers with at least k tributary ones

RiversHavingAtLeastkTributaries: (5p)

SELECT RIVERS.x, Count(CHILDREN.x) AS TributariesNo

FROM RIVERS AS CHILDREN INNER JOIN RIVERS

ON CHILDREN.TributaryTo = RIVERS.x

GROUP BY RIVERS.x

HAVING Count(CHILDREN.x) >=

[Enter desired minimum number of tributaries:];

- step 2: rivers with at least k tributary ones, each of which having n

tributaries

RiversHavingAtLeastkTributariesAndnGrandTributaries: (7p)

SELECT RiversHavingAtLeastkTributaries.x,

RiversHavingAtLeastkTributaries.TributariesNo,

Count(GrandChildren.x) AS GrandTributariesNo

FROM RIVERS AS GrandChildren INNER JOIN (RIVERS AS CHILDREN

INNER JOIN RiversHavingAtLeastkTributaries

ON CHILDREN.TributaryTo =

RiversHavingAtLeastkTributaries.x)

ON GrandChildren.TributaryTo = CHILDREN.x

GROUP BY RiversHavingAtLeastkTributaries.x,

RiversHavingAtLeastkTributaries.TributariesNo

HAVING Count(GrandTributariesNo.x) >=

[Enter desired minimum number of grand tributaries:];

- step 3: getting names and sorting

Test-1redo: (3p)

SELECT River, TributariesNo, GrandTributariesNo

FROM RIVERS INNER JOIN

RiversHavingAtLeastkTributariesAndnGrandTributaries

Page 383: Laborator Baze date

377

ON RIVERS.x =

RiversHavingAtLeastkTributariesAndnGrandTributaries.x

ORDER BY ChildrenNo DESC, GrandChildrenNo DESC, River;

Result of query Test-1redo for k = 1, n = 0 (1p)

River TributariesNo GrandTributariesNo

Danube 1 1

Olt 1 0

Parana 1 0

Result of query Test-1redo for k = 1, n = 1 (1p)

River TributariesNo GrandTributariesNo

Danube 1 1

Result of query Test-1redo for k = 1, n = 2 (1p)

River TributariesNo GrandTributariesNo

6.1.2 Oracle solution

a.

INSERT INTO STATES (State, Country)

VALUES ('Prahova', 1); (0.5p)

INSERT INTO CITIES (City, State)

SELECT 'Sinaia', x FROM STATES

WHERE State = 'Prahova' AND Country = 1; (1.5p)

b.

ALTER TABLE PEOPLE ADD BirthPlace NUMBER(6,0);

(0.5p)

ALTER TABLE PEOPLE ADD CONSTRAINT fkBPlace

FOREIGN KEY (BirthPlace) REFERENCES CITIES;

(1.25p)

Page 384: Laborator Baze date

378

UPDATE PEOPLE SET BirthPlace = (SELECT x FROM

CITIES WHERE City='Sinaia') WHERE x IN (7, 12);

(1.75p)

c.

-------------------------------------------------

-- DDL for View CITIES_STATES_CONTRIES

-------------------------------------------------

CREATE OR REPLACE FORCE VIEW

"LAB_DB"."CITIES_STATES_CONTRIES"

("X", "City, State, Country") AS

SELECT CITIES.x, City || ', ' || STATES.State ||

', ' || COUNTRIES.Country "City, State, Country"

FROM COUNTRIES INNER JOIN (STATES INNER JOIN

CITIES ON STATES.x = CITIES.State)

ON COUNTRIES.x = STATES.Country

ORDER BY City || ', ' || STATES.State || ', ' ||

COUNTRIES.Country; (3.5p)

d.

- step 0: create a temporary table for storing fathers with at least k children

(1p)

-------------------------------------------------

-- DDL for Table TMPPHLKC

-------------------------------------------------

CREATE TABLE "LAB_DB"."TMPPHLKC"

( "X" NUMBER(6,0),

"CHILDRENNO" NUMBER(2,0)

) SEGMENT CREATION IMMEDIATE

PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255

NOCOMPRESS LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1

MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1

BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT

CELL_FLASH_CACHE DEFAULT)

TABLESPACE "USERS";

Page 385: Laborator Baze date

379

- step 1: add to the LAB_DB_PL_SQL package the following procedure:

procedure AtLeastkChildrennGrandChildren

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType);

procedure AtLeastkChildrennGrandChildren

(Min_no_of_children in integer,

Min_no_of_grand_children in integer,

rc out GenericCursorType) is

begin

--0. initialize tmpPHLkC (0.5p) DELETE FROM tmpPHLkC;

--1. compute and store into it fathers with at least k

--children (4.5p) INSERT INTO tmpPHLkC

SELECT PEOPLE.x, Count(CHILDREN.x) ChildrenNo

FROM PEOPLE CHILDREN INNER JOIN PEOPLE

ON CHILDREN.Father = PEOPLE.x

GROUP BY PEOPLE.x

HAVING Count(CHILDREN.x) >= Min_no_of_children;

--2. compute and return grandfathers with at least k

--children, each of which has n children (9p) OPEN rc FOR

SELECT NAMES.Name, ChildrenNo,

Count(GrandChildren.x) GrandChildrenNo

FROM (PEOPLE GrandChildren INNER JOIN (PEOPLE CHILDREN INNER

JOIN tmpPHLkC

ON CHILDREN.Father = tmpPHLkC.x)

ON GrandChildren.Father = CHILDREN.x) INNER JOIN PEOPLE

NAMES ON tmpPHLkC.x = NAMES.x

GROUP BY NAMES.Name, tmpPHLkC.ChildrenNo

HAVING Count(GrandChildren.x) >= Min_no_of_grand_children

ORDER BY ChildrenNo DESC, Count(GrandChildren.x) DESC,

NAMES.Name;

end AtLeastkChildrennGrandChildren;

- step 3: test for k = n = 1, respectively 2

var c refcursor;

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildren(1,1,:c);

print c;

Page 386: Laborator Baze date

380

Figure 6.3 Result of stored procedure AtLeastkChildrennGrandChildren

for k = n = 1 (1p)

Page 387: Laborator Baze date

381

exec LAB_DB_PL_SQL.AtLeastkChildrennGrandChildren(2,2,:c);

print c;

Figure 6.4 Result (empty set) of stored procedure

AtLeastkChildrennGrandChildren for k = n = 2 (1p)

Page 388: Laborator Baze date

382

13.2 DB design and implementation test redoing Consider the countries and territories of the world, for which only English

name, official name, suzerain power, capital city (name and country), GDP,

population, and area are of interest (Hint: only very big cities are of interest;

note that the world is a tree of states and territories, rooted in the U.N.,

including superstates like the E.U. or the C.I.S., ordinary states, and “sub-

states” like colonies, protectorates, etc.; for example, the E.U. is the suzerain

power of France, which, in its turn, is the suzerain power of the Kerguelen

Islands). Design the db fragment needed for storing this data and implement

it on the platform of your choice; also add at least two plausible rows per

table. Total points: 180, 2h.

Solution:

Obviously, the corresponding E-RD (10 points) and restrictions list (8

points) are the following:

EnglishName OfficialName GDP Population Area

Suzerain COUNTRIES

Capital Country

CITIES City

COUNTRIES (The set of all existing countries and territories of interest)

Max. cardinality: 250 (R0)

Ranges:

- EnglishName and OfficialName: ASCII(255) (R1)

- Population: [100,…, 2,000,000] (R2)

- GDP (US$ billions) and Area (square km.): [0.1, …, 20,000,000] (R3)

Mandatory: EnglishName (R4)

Uniqueness: Capital (no city may simultaneously be the capital of more

than one country), EnglishName (there may not be two countries

having same English name), and OfficialName (there may not be

two countries having same official name) (R5)

CITIES (The set of all world cities of interest)

Max. cardinality: 1,000,000 (R6)

Page 389: Laborator Baze date

383

Ranges: City: ASCII(255) (R7)

Mandatory: City and Country (R8)

Uniqueness: there may not be two (very big) cities of a same country

having same names (R9)

The result of applying the translation algorithm from E-RDs and restriction

lists into mathematical schemes is the following (12 points):

COUNTRIES

x NAT(3), total (according to R0)

EnglishName ASCII(255), total (according to R1 and R4)

OfficialName ASCII(255) (according to R1)

GDP [0.1; 20,000,000] (according to R2)

Area [0.1; 20,000,000] (according to R2)

Population [10; 2,000,000,000] (according to R3)

Suzerain : COUNTRIES COUNTRIES

CITIES

x NAT(6), total (according to R6)

City ASCII(255), total (according to R7 and R8)

Capital : COUNTRIES CITIES (according to R5)

Country : CITIES COUNTRIES, total (according to R8)

C9: City Country key (according to R9)

The results of applying the first refinement algorithm (for assisting sets,

functions, and constraints design) are the following (18 points):

d. Sets: both COUNTRIES and CITIES are atomic type object sets not

semantically overloaded.

e. Functions:

- EnglishName is well defined as any country has an English name and

only one;

one-to-oneness: there may no be two countries having same English

name constraint EnglishName key should be added to the db

scheme;

ontoness: not any combination of 255 ASCII characters should be a

country English name;

- OfficialName is well defined as any country has an official name and

only one;

Page 390: Laborator Baze date

384

one-to-oneness: there may no be two countries having same official

name constraint OfficialName key should be added to the db

scheme;

ontoness: not any combination of 255 ASCII characters should be a

country official name;

- GDP is well defined as any country has one associated GDP and only

one;

one-to-oneness: there may be two countries having same GDP;

ontoness: not any number between 0.1 and 20,000,000 should be the

GDP of a country;

- Population is well defined as any country has one associated total

population number and only one;

one-to-oneness: there may be two countries having same population;

ontoness: not any number between 10 and 20,000,000,000 should be

the population of a country;

- Area is well defined as any country has one associated area and only

one;

one-to-oneness: there may be two countries having same area;

ontoness: not any number between 0.1 and 20,000,000 should be the

area of a country;

- Suzerain is well defined as any subordinated country (territory) has

one suzerain power and only one;

one-to-oneness: there may be two countries having same suzerain;

ontoness: not any country is a suzerain power;

homogeneous binary relationship constraints: no country may be its

own suzerain power, either directly or indirectly constraint Suze-

rain acyclic should be add to the db scheme;

- Capital is well defined as any country has one capital city and only

one;

one-to-oneness: no city may simultaneously be the capital of more

than one country;

ontoness: not any city should be a country capital;

- City is well defined as any city has one name and only one;

one-to-oneness: there may be two cities having same name (but in

different countries);

Page 391: Laborator Baze date

385

ontoness: not any combination of 255 ASCII characters should be a

city name;

- Country is well defined as any city belongs to one country and only

one;

one-to-oneness: there may be two cities belonging to a same country;

ontoness: not any country should have a city (in the db’s instance);

f. Constraints: no other constraints apply to this subuniverse.

The results of applying the second refinement algorithm (for assisting keys

discovery) are the following (8 points):

COUNTRIES

n = 4 (GDP, Population, Area, Suzerain), K = {Capital, EnglishName,

OfficialName};

nonprimeness: obviously, GDP, Population, and Area are all nonprime, as

they might not contribute to countries’ unique identification;

n’ = 1 (Suzerain) nothing to do as Suzerain is not one-to-one.

CITIES

n = 2 (City, Country), K = {City Country};

nothing to do as neither City, nor Country is not one-to-one.

Consequently, neither COUNTRIES, nor CITIES have other semantic keys.

The results of applying the third refinement algorithm (for assisting analysis

of E-RD cycles) are the following (6 points):

There are two cycles in this E-RD: Suzerain (that was already investigated

above) and the unidirectional one made out of Capital : COUNTRIES

CITIES and Country : CITIES COUNTRIES. For this latter one, possible

local commutativities should be investigated in both of its nodes:

- Capital Country =? 1CITIES (should any city be the capital of the

country to which belongs?); obviously no, as not every city is a capi-

tal of its country;

- Country Capital =? 1COUNTRIES (should any capital city of a country

belong to that country?); obviously yes, as no country may have as its

Page 392: Laborator Baze date

386

capital a city from another country constraint Country Capital =

1COUNTRIES should be added to the db scheme.

The finally obtained mathematical scheme is the following (15 points):

COUNTRIES

x NAT(3), total

EnglishName ASCII(255), total

OfficialName ASCII(255)

GDP [0.1; 20,000,000]

Area [0.1; 20,000,000]

Population [10; 2,000,000,000]

Suzerain : COUNTRIES COUNTRIES, acyclic

CITIES

x NAT(6), total

City ASCII(255), total

Capital : COUNTRIES CITIES

Country : CITIES COUNTRIES, total

C9: City Country key

C10: Country Capital = 1COUNTRIES

Applying the algorithm for translating mathematical schemes into relational

ones (23 points) and non-relational constraint lists (2 points) yields the fol-

lowing:

COUNTRIES (x, Capital, EnglishName, OfficialName)

x English-

Name

Official-

Name

GDP Area Popu

la-

tion

Suze

rain

Capi-

tal

auton(

3)

ASCII(255) ASCII(255) [0.1,

2*107

]

[0.1,

2*107

]

[10;

2*109]

Im

(x)

Im(CI-

TIES.x

)

NOT

NULL

NOT

NULL

1 U.K. United

Kindom

1

2 Canada Canada 1 3

Page 393: Laborator Baze date

387

CITIES (x, City Country)

x City Country

auoton(6) ASCII(255) Im(COUNTRIES.x)

NOT NULL NOT NULL NOT NULL

1 London 1

2 Toronto 2

3 Ottawa 2

The corresponding non-relational constraint list is the following (2 points):

C10: Country Capital = 1COUNTRIES

C11: Suzerain : COUNTRIES COUNTRIES, acyclic

13.2.1 Access implementation

Applying the algorithm for translating relational schemes into Access dbs,

the following three DDL SQL statements are needed (18 points):

createCOUNTRIES:

CREATE TABLE COUNTRIES (x COUNTER PRIMARY KEY,

EnglishName VARCHAR(255) NOT NULL UNIQUE,

OfficialName VARCHAR(255) UNIQUE, GDP Double, Area

Double, Population Double, Capital Long UNIQUE,

Suzerain LONG, CONSTRAINT fkSuzerain FOREIGN KEY

(Suzerain) REFERENCES COUNTRIES);

createCITIES:

CREATE TABLE CITIES (x COUNTER PRIMARY KEY, City

VARCHAR(255) NOT NULL, Country Long NOT NULL,

CONSTRAINT fkCountry FOREIGN KEY (Country)

REFERENCES COUNTRIES, CONSTRAINT kCITIES UNIQUE

(City, Country));

alterCOUNTRIES:

ALTER TABLE COUNTRIES ADD CONSTRAINT fkCapital

FOREIGN KEY (Capital) REFERENCES CITIES;

Through Access’ GUI, the following has to to be added to this db (14

points):

Page 394: Laborator Baze date

388

- For all text columns (EnglishName, OfficialName, and Country) cor-

responding Allow zero length property should be turned to No (for

rejecting dirty nulls).

- For all numeric ones (GDP, Area, Population) that have as (co-)do-

mains subsets of Access’ data types, their Validation Rule and Text

properties should be filled accordingly:

GDP and Area: Between 0.1 and 2*10^7 (“Valid

GDP/Area values are between 0.1 and 2*10^7!”);

Population: Between 10 and 2*10^9 (“Valid Popula-

tion values are between 10 and 2*10^9!”);

- For all foreign keys (Suzerain, Capital, Country), corresponding text

boxes should be replaced by combo ones, for hiding pointers and dis-

playing instead corresponding semantic key values:

Suzerain and Country: SELECT x, EnglishName FROM COUNTRIES

ORDER BY EnglishName;

Capital: SELECT CITIES.x, [City] & ", " & [EnglishName] AS Capital FROM COUNTRIES INNER JOIN CITIES

ON COUNTRIES.x = CITIES.Country

ORDER BY [City] & ", " & [EnglishName];

For populating the two tables with their demos rows the following seven

SQL DML statements are needed (7.5 points): INSERT INTO COUNTRIES(EnglishName, OfficialName)

VALUES ("U.K.", "United Kingdom");

INSERT INTO COUNTRIES(EnglishName, OfficialName, Suzerain)

VALUES ("Canada", "Canada", 1);

INSERT INTO CITIES(City, Country) VALUES ("London", 1);

INSERT INTO CITIES(City, Country) VALUES ("Toronto", 2);

INSERT INTO CITIES(City, Country) VALUES ("Ottawa", 2);

UPDATE COUNTRIES SET Capital = 1 WHERE x = 1;

UPDATE COUNTRIES SET Capital = 3 WHERE x = 2;

According to the algorithm for assisting enforcement of non-relational con-

straints in Access, in order to enforce the above non-relational constraints we

first have to create (by using the Form Wizard) the datasheet form COUN-

TRIES (1 point).

- C10: Country Capital = 1COUNTRIES

Page 395: Laborator Baze date

389

Obviously, this constraint may be easily enforced in the Form_Current me-

thod of the class Form_COUNTRIES, by adding a corresponding dynamic

filter to the SELECT statement of the combo box Capital (for eliminating

from the set of all existing cities all those that belong to other countries than

the current one) and then requerying it (note that on the blank line, the empty

set should be computed instead) (5 points):

'*************************

Private Sub Form_Current()

'*************************

On Error GoTo err_point

'enforces constraint C10

If Me.NewRecord Then

Me!Capital.RowSource = "SELECT x, x FROM COUNTRIES WHERE" _

& " x <> x;"

Else

Me!Capital.RowSource = _

"SELECT CITIES1.x, [City] & ', ' & [EnglishName] " & _

"AS Capital FROM COUNTRIES1 INNER JOIN CITIES1 " & _

"ON COUNTRIES1.x = CITIES1.Country " & _

"WHERE COUNTRIES1.x=" & Me!x & _

" ORDER BY [City] & ', ' & [EnglishName];"

End If

Me!Capital.Requery

Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_COUNTRIES.Form_Current..."

End Sub

- C11: Suzerain : COUNTRIES COUNTRIES, acyclic

In order to may able to compute the transitive closure of Suzerain’s graph,

we first need to create the corresponding results table (1.5 points):

createSuzerainTransClosure: CREATE TABLE FolderTransClosure(x Long, Suzerain Long,

[Level] Long);

Then, obviously, this last non-relational constraint has to be enforced in class

Form_COUNTRIES; as only column Suzerain is involved, the needed event

for enforcing this constraint is Suzerain_BeforeUpdate: the following code

should be added to this class (31 points):

'***************************************************

Private Sub Suzerain_BeforeUpdate(Cancel As Integer)

'***************************************************

On Error GoTo err_point

'enforces constraint C11

If Not Me.NewRecord And Me!Suzerain = Me!Suzerain.OldValue _

Then GoTo exit_point

If Me!Suzerain = Me!x Then 'irreflexivity

Page 396: Laborator Baze date

390

Cancel = True

Me!Suzerain.Undo

MsgBox "Please change Suzerain!", _

vbCritical, "No country may be its own suzerain..."

Else 'acyclicity

Dim level As Integer

Dim oldcard, card As Double

DoCmd.RunSQL "DELETE FROM SuzerainTransClosure"

oldcard = 0

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, Suze" _

& "rain, [Level]) SELECT x, Suzerain, 0 FROM COUNTRIES"

If Me.NewRecord Then

If IsNull(Me!Suzerain) Then

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain, [Level]) VALUES (" & Me!x & ", NULL, 0)"

Else

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain, [Level]) VALUES (" & Me!x & ", " & _

Me!Suzerain & ", 0)"

End If

Else

If IsNull(Me!Suzerain) Then

DoCmd.RunSQL "UPDATE SuzerainTransClosure " _

& " SET Suzerain = NULL WHERE x=" & Me!x

Else

DoCmd.RunSQL "UPDATE SuzerainTransClosure " _

& "SET Suzerain =" & Me!Suzerain & " WHERE x=" & Me!x

End If

End If

card = DCount("*", "SuzerainTransClosure")

level = 1

While oldcard <> card And Not Cancel

oldcard = card

DoCmd.RunSQL "INSERT INTO SuzerainTransClosure(x, " _

& "Suzerain,[Level]) SELECT SuzerainTransClosure.x," _

& "COUNTRIES.Suzerain, " & level & _

" FROM SuzerainTransClosure INNER JOIN COUNTRIES " & _

"ON SuzerainTransClosure.Suzerain = COUNTRIES.x " & _

"WHERE [Level]=" & level - 1

If Not IsNull(DLookup("x", "SuzerainTransClosure", _

"x = Suzerain")) Then

Cancel = True

Me!Suzerain.Undo

MsgBox "Please change Suzerain as this one would " _

& "create a cycle!", vbCritical, "Suzerains " _

& "tree hierarchy should be cycle-free..."

Else

card = DCount("*", "SuzerainTransClosure")

level = level + 1

End If

Wend

Page 397: Laborator Baze date

391

End If

exit_point: Exit Sub

err_point: MsgBox Err.Source & "->" & Err.Description, _

vbCritical, _

"Error in method Form_COUNTRIES.Capital_BeforeUpdate..."

Cancel = True

End Sub

13.2.2 Oracle implementation

Page 398: Laborator Baze date

392

Chapter 14. 14th Lab: Projects Defense

Page 399: Laborator Baze date

393

Conclusion

Page 400: Laborator Baze date

394

References

1. Mancas, C. Databases Lecture Notes, 2014, Bucharest Polytechnic

University.

2. Mancas, C. Conceptual Data Modeling and Database Design: Ana-

lysis, Implementation and Optimization. A Fully Algorithmic Ap-

proach, 2014, Apple Academic Press.

3. Microsoft Corp. Access 2010 Help.

4. IT Services. Microsoft Access 2010 An Essential Guide (Level 1),

2011, The University of Reading (freely downloadable from

http://www.reading.ac.uk/web/files/its/AccessEssen2010.pdf).

5. IT Services. Microsoft Access 2010 An Intermediate Guide (Level 2),

2011, The University of Reading (freely downloadable from

http://www.reading.ac.uk/web/files/its/AccessInter2010.pdf).

6. McDonald, M. Access 2010: The Missing Manual, 2010, O’Reilly

Media (freely downloadable from http://it-ebooks.info/book/104/).

7. Murrey, C. & all. Oracle SQL Developer User’s Guide, Release 3.2,

2012, Oracle Corp. (freely downloadable from

http://docs.oracle.com/cd/E35137_01/appdev.32/e35117.pdf).

8. Lorentz, D. & all. Oracle Database SQL Language Reference 11g,

Release 2, 2013, Oracle Corp. (freely downloadable from

http://docs.oracle.com/cd/E11882_01/server.112/e41084.pdf).

9. Moore, S; Belden, E. Oracle Database PL/SQL Language Reference,

11g Release 2, 2013, Oracle Corp. (freely downloadable from

http://docs.oracle.com/cd/E11882_01/appdev.112/e25519.pdf).

10. Molina, H.G; Ullman, J.D; Widom, J. Database Systems: The Com-

plete Book, 2nd

Edition, 2013, Pearson New International Edition.

11. Mancas, C. Theoretical Foundations of the Relational Data Model,

2007, Ovidius University Press (in Romanian).

12. Mancas, C. Programming in SQL ANSI-92 with examples for MSJet

4.2, 2002, Ovidius University Press (in Romanian).

Page 401: Laborator Baze date

395

Appendix 1: DB Project Example

UNIVERSITY “POLITEHNICA” OF BUCHAREST

FACULTY OF ENGINEERING IN FOREIGN LANGUAGES

COMPUTERS AND INFORMATION TECHNOLOGY ENGLISH STREAM

Databases Project

Design, implementation, and

usage of a Library db

Project coordinator Student:

Assoc. Prof. Dr. Christian Mancas

Bucharest 201x

Page 402: Laborator Baze date

396

Table of Contents

1. Business Analysis

1.0 Description of the sub-universe of discourse

1.1 Entity-Relationship Diagrams

1.2 Associated Restrictions List

2. Mathematical Scheme

2.0 Initial Mathematical Scheme

2.1 First refinement algorithm: Sets, Functions, and Constraints

Design Assistance

2.1.1 Sets

2.1.2 Functions

2.1.3 Constraints

2.2 Second refinement algorithm: Keys Discovery Assistance

2.3 Third refinement algorithm: E-RD Cycles Analysis

2.4 Final Mathematical Scheme

3. Relational Scheme and Associated Non-relational Constraints List

3.1 Relational db scheme

3.2 Non-relational constraints list

4. Database Implementation

4.0 Technology choice

4.1 Access db

4.2 Oracle db

5. Non-relational Constraints Implementation

5.1 Access Solutions

5.2 Oracle Solutions

6. Database Usage

6.1 Access Queries and Reports

6.2 Oracle Views and Stored Procedures

Conclusion

References

Page 403: Laborator Baze date

397

1. Business Analysis

1.0 Description of the sub-universe of discourse The db should store data on books (title, writing year, first author, co-au-

thors, and their order), people (authors and/or library subscribers) e-mail

addresses and first and last names, as well as books copies borrows by

subscribers (borrow, due, and actual return dates).

Books are published by publishing houses, possibly in several editions

even by same publishers (in different years). Each edition may contain se-

veral volumes, each having a number, a title, a price, and an ISBN code.

Volumes may contain several books.

The library owns several copies (uniquely identified by an inventory

code) of any volume and may lend several copies for any borrow; not all

borrowed copies should be returned at a same date; maximum lending pe-

riod is 300 days.

Last names, books titles, first authors, publisher names, editions publi-

shers, first books, and titles, as well as volumes numbers and prices, co-

pies inventory codes, borrows subscribers, dates, and due return dates are

compulsory; for subscribers, first names and e-mail addresses are compul-

sory too.

People are uniquely identified by their first and last names, plus e-mail

address, books by their first author, title, and writing year, publishers by

their names, editions by their first book, publisher, title, and year, vo-

lumes by corresponding edition and volume number.

There may be at most:

- 1,000,000 persons, books, and editions,

- 2,000,000 co-authoring and volumes,

- 10,000 publishers,

- 4,000,000 book editions,

- 32,000,000 copies,

- 100,000,000,000 borrows, and

- 1,000,000,000,000 borrows of interest.

Page 404: Laborator Baze date

398

1.1 Entity-Relationship Diagrams

Fname LName e-mail

PERSONS

BTitle BOOKS BYear

PERSONS CO-AUTHORS BOOKS

PosInList

PUBLISHERS PubName

ETitle EDITIONS EYear

ISBN Title

Number VOLUMES Price

BOOKS VOLUMES_CONTENTS VOLUMES

BookPos

InvNo COPIES

Page 405: Laborator Baze date

399

BORROWS BorrowDate

COPIES BORROWS_LISTS BORROWS

DueReturnDate ActualReturnDate

FirstAuthor

PERSONS BOOKS

Subscriber CO-AUTHORS

BORROWS VOLUMES_CONTENTS

FirstBook

BORROWS_LISTS Volume VOLUMES

Publisher Edition

COPIES PUBLISHERS EDITIONS

Figure A1.1 Structural E-RD

1.2 Associated Restrictions List 1. PERSONS (The set of books (co-)authors and subscribers of inte-

rest to the library.)

a. Cardinality: max(card(PERSONS)) = 1,000,000 (RP0)

b. Data ranges:

FName: ASCII(128) (RP1)

LName: ASCII(64) (RP2)

e-mail: ASCII(255) (RP3)

c. Compulsory data: LName (RP4)

d. Unicity: e-mail FName LName (there may not

be two persons having same first and last name,

as well as same e-mail address) (RP5)

Page 406: Laborator Baze date

400

e. Other types restrictions:

FName and e-mail should be compulsory for subscribers(RP6)

2. BOOKS (The set of written works of interest to the library.)

a. Cardinality: max(card(BOOKS)) = 1,000,000 (RB0)

b. Data ranges:

BTitle: ASCII(255) (RB1)

BYear: [-2500, current year] (RB2)

c. Compulsory data: BTitle, FirstAuthor (RB3)

d. Unicity: FirstAuthor BTitle BYear (no author writes

two books with a same title in a same year) (RB4)

3. CO-AUTHORS = (PERSONS, BOOKS) (The set of pairs

<b, p> storing the fact that book b was (also) written by

person p.)

a. Cardinality: max(card(CO-AUTHORS)) = 2,000,000 (RCA0)

b. Data ranges: PosInList: [2, 16] (p’s position in b’s

co-authors list) (RCA1)

c. Compulsory data: Person, Book, PosInList (RCA2)

d. Unicity: Person Book (no author should appear more

than once in any book co-authors list) (RCA3)

4. PUBLISHERS (The set of publishers of interest to the library.)

a. Cardinality: max(card(PUBLISHERS)) = 10,000 (RPB0)

b. Data ranges: PubName: ASCII(128) (RPB1)

c. Compulsory data: PubName (RPB2)

d. Unicity: PubName (there may not be two publishers

having same name) (RPB3)

5. EDITIONS (The set of books editions of interest to the library.)

a. Cardinality: max(card(EDITIONS)) = 1,000,000 (RE0)

b. Data ranges:

ETitle: ASCII(255) (RE1)

EYear: [-2500, current year] (RE2)

c. Compulsory data: Publisher, FirstBook, ETitle (RE3)

Page 407: Laborator Baze date

401

d. Unicity: Publisher FirstBook EYear (no publis-

her publishes more than one edition with any given

book in any given year) (RE4)

6. VOLUMES (The set of editions volumes of interest to the library.)

a. Cardinality: max(card(VOLUMES)) = 2,000,000 (RV0)

b. Data ranges:

ISBN: ASCII(16) (RV1)

VTitle: ASCII(255) (RV2)

VNo: [1, 255] (RV3)

VPrice: CURRENCY(8) (RV4)

c. Compulsory data: Edition, VNo, VPrice (RV5)

d. Unicity: ISBN (by definition, ISBNs are unique for any

volume) (RV6)

7. VOLUMES_CONTENTS = (BOOKS, VOLUMES) (The set of

pairs <b, v> storing the fact that book b is (also) included in

volume v.)

a. Cardinality: max(card(VOLUMES_ CONTENTS)) =

4,000,000 (RVC0)

b. Data ranges: BookPos: [1, 16] (b’s position in v’s table

of contents) (RVC1)

c. Compulsory data: Book, Volume, BookPos (RVC2)

d. Unicity: Volume Book (no book should be included

more than once in any volume) (RVC3)

e. Other types restrictions:

For any edition, its first book should be the first one

published in its first volume. (RVC4)

No edition may contain same book more than once. (RVC5)

8. COPIES (The set of editions volumes copies that the

library possessed.)

a. Cardinality: max(card(COPIES)) = 32,000,000 (RC0)

b. Data ranges: InvNo: ASCII(32) (RC1)

c. Compulsory data: InvNo, Volume (RC2)

Page 408: Laborator Baze date

402

d. Unicity: InvNo: (by definition, inventory numbers are

unique for any copy) (RC3)

9. BORROWS (The set of editions volumes copies borrows

by subscribers.)

a. Cardinality: max(card(BORROWS)) =

100,000,000,000 (RBR0)

b. Data ranges: BorrowDate: [6/1/2011, SysDate()]

(assuming, for example, that first borrow date of

interest is June 1st, 2011) (RBR1)

c. Compulsory data: BorrowDate, Subscriber (RBR2)

d. Unicity: BorrowDate Subscriber (no subscriber may

simultaneously borrow several times) (RBR3)

10. BORROWS_LISTS = (BORROWS, COPIES) (The set of

pairs <b, c> storing the fact that volume copy c was

(also) borrowed in borrow b.)

a. Cardinality: max(card(BORROWS_ LISTS)) =

1,000,000,000,000 (RBL0)

b. Data ranges:

DueReturnDate: [6/1/2011, SysDate() + 300] (assuming,

for example, that maximum borrow period is 300 days)(RBL1)

ActualReturnDate: [6/1/2011, SysDate()] (RBL2)

c. Compulsory data: Borrow, Copy, DueReturnDate (RBL3)

d. Unicity: Borrow Copy (no copy may be simultaneously

borrowed more than once) (RBL4)

e. Other types restrictions:

No copy may be borrowed less than 0 days or more

than 300 days. (RBL5)

No copy may be simultaneously borrowed to more than

one subscriber. (RBL6)

No copy may be returned before it was borrowed and

after 100 years since corresponding borrow date. (RBL7)

Page 409: Laborator Baze date

403

2. Mathematical Scheme

2.0 Initial Mathematical Scheme By applying the algorithm for translating E-RDDs and restriction lists to

mathematical schemes, the following initial scheme results:

PERSONS

x NAT(6), total

FName ASCII(128)

LName ASCII(64), total

e-mail ASCII(255)

CP5: e-mail FName LName key

BOOKS

x NAT(6), total

BTitle ASCII(255), total

BYear [-2500, Year(SysDate())]

FirstAuthor : BOOKS PERSONS, total

CB4: FirstAuthor BTitle BYear key

CO-AUTHORS = (PERSONS, BOOKS)

x NAT(7), total

PosInList [2, 16], total

PUBLISHERS

x NAT(4), total

PubName ASCII(128), total

EDITIONS

x NAT(6), total

ETitle ASCII(255), total

EYear [-2500, Year(SysDate())]

Publisher : EDITIONS PUBLISHERS, total

FirstBook : EDITIONS BOOKS, total

CE4: Publisher FirstBook EYear key

Page 410: Laborator Baze date

404

VOLUMES

x NAT(7), total

ISBN ASCII(16)

VTitle ASCII(255)

VNo [1, 255], total

VPrice CURRENCY(8), total

Edition : VOLUMES EDITIONS, total

VOLUMES_CONTENTS = (BOOKS, VOLUMES)

x NAT(7), total

BookPos [1, 16], total

COPIES

x NAT(8), total

InvNo ASCII(32), total

Volume : COPIES VOLUMES, total

BORROWS

x NAT(11), total

BorrowDate [6/1/2011, SysDate()], total

Subscriber : BORROWS PERSONS, total

CBR3: BorrowDate Subscriber key

BORROWS_LISTS = (BORROWS, COPIES)

x NAT(12), total

DueReturnDate [6/1/2011, SysDate() + 300], total

ActualReturnDate [6/1/2011, SysDate()]

CBL4: Borrow Copy key

2.1 First refinement algorithm: Sets, Functions, and

Constraints Design Assistance

Here are the results of applying the design assistance algorithm for:

2.1.1 Sets

a.1 No set is semantically overloaded (so no structural refinements are ne-

eded from this point of view). Please review chapter 2, where this sub-

universe modeling is discussed too contrastively, as compared to several

poorer solutions!

Page 411: Laborator Baze date

405

a.2 No set is a subset of another set (so no inclusion constraints need to be

added to the scheme).

a.3 No association-type set has arity greater than two (so none has to be

replaced by its equivalent entity-type set and explicit structural keys and

functions corresponding to its canonical Cartesian projections).

a.4 All binary associations are non-functional:

- CO-AUTHORS is not functional, because there are persons that

wrote several books, as well as books that were written by several

persons.

- VOLUMES_CONTENTS is not functional, because there are vo-

lumes that contain several books, as well as books that span across

several volumes.

- BORROWS_LISTS is not functional, because there are borrows in-

cluding several copies, as well as copies borrowed several times.

a.5 No association-type object set is ill-defined:

- CO-AUTHORS is well defined according to restriction RCA3;

- VOLUMES_CONTENTS is well defined according to restriction

RVC3;

- BORROWS_LISTS is well defined according to restriction RBL4.

a.6 No association is homogeneous (so that we need not investigate refle-

xivity, irreflexivity, symmetry, anti-symmetry, etc.).

2.1.2 Functions

b.1 All functions are well defined:

- people (be them authors or subscribers) have only one e-mail address (of

interest to the library), first, and last name;

- books, editions, and volumes have only one respective title;

- books and editions have only one respective year ();

Page 412: Laborator Baze date

406

- co-authors and volumes contents entries have only one associated res-

pective position;

- publishers have only one name;

- volumes have at most one ISBN value and price, as well as one number;

- copies have only one inventory number;

- borrows have only one associated calendar date;

- borrows lists entries have only one due and actual return dates;

- books have only one first author;

- editions have only one publisher and first book;

- volumes belong to only one edition;

- copies are instances of only one volume;

- finally, borrows are made by only one subscriber.

b.2 No other function (except for the unique ones) is one-to-one:

- FName : there may be several persons having same first name;

- LName : there may be several persons having same last name;

- e-mail : there may be several persons having same e-mail address (for

example children and parents, spouses, etc.);

- BTitle: there may be several books having same title (even wrote by

same authors);

- FirstAuthor: there may be several books having a same first author;

- PosInList: there may be several authors in the same co-authors list

position (in different co-authors lists)

- ETitle: there may be several editions having same title (even published

by same publishers);

Page 413: Laborator Baze date

407

- EYear: there may be several editions published in a same year (even

from a same publisher);

- Publisher: there may be several editions published by a same publisher;

- FirstBook: there may be several editions having same first book (even

from a same publisher);

- VTitle: there may be several volumes having same title (in different edi-

tions);

- VNo: there may be several volumes having same number (in different

editions);

- VPrice: there may be several volumes having same price (even in same

editions);

- Edition: there may be several volumes for a same edition;

- BookPos: there may be several books having same position within vo-

lumes (in different editions);

- Volume: there may be several copies of a same volume;

- BorrowDate: there may be several borrows in a same day (by different

subscribers);

- DueReturnDate: there may be several borrowed books having same due

return day (even for a same borrow);

- ActualReturnDate: there may be several borrowed books having same

actual return day (even for a same borrow).

On the contrary, all those declared as one-to-one are really one-to-one:

- PubName: there may not be two publishers having same name;

- ISBN: there may not be two volumes having same ISBN;

- InvNo: there may not be two copies having same inventory number.

Page 414: Laborator Baze date

408

b.3 No function is onto, except for Edition:

- Edition is onto, because for any edition there should be at least

one corresponding volume. Consequently, the following constraint

has to be added to this db scheme:

Edition: VOLUMES EDITIONS, total, onto

- Obviously, FName, LastName, e-mail, BTitle, PubName, ETitle,

ISBN, VTitle, and InvNo are not, as not all possible ASCII charac-

ter combinations (of maximum 255/128/64/32/16 characters)

should be first or last person, publisher, or ISBN actual values;

- just as no calendar dates (between June 1st 2011 and up to today or

next year) or years (between -2500 and the current one) should (so

BYear, EYear, BorrowDate, DueReturnDate, and ActualReturn-

Date are not onto either);

- just like no naturals (between 1/2 and 16/255) or rationals (betwe-

en 0 and 99,999,999.99) should (so PosInList, VNo, VPrice, and

BookPos are not onto either).

- FirstAuthor is not either, as not only that not all subscribers are

authors too (in fact, most of them are not), but not even all authors

are first authors.

- Publisher and FirstBook are not either, as it is not compulsory that

all possible publishers/books be editing (to the current db instance

knowledge) / edited, respectively.

- Volume is not either, as there might be volumes (in the current db

instance) for which there are no copies.

- Subscriber is not either, as not all known (to the db instance)

persons should have borrowed books from the library (e.g. Homer,

Shakespeare, etc.).

b.4 There are no bijective functions.

b.5 There are no auto-functions (so that we need not investigate reflexi-

vity, irreflexivity, symmetry, anti-symmetry, etc.).

b.6 There are no canonical surjections (representative systems).

Page 415: Laborator Baze date

409

b.7 There are no object sets having no totally defined functions.

2.1.3 Constraints

c.1 There are six not formalized constraints; here are their corresponding

formalizations:

- RP6: FName and e-mail should be compulsory for subscribers.

CP6: (bBORROWS)(FName(Subscriber(b)) NULLS

e-mail(Subscriber(b)) NULLS)

- RVC4: For any edition, its first book should be the first one published in

its first volume.

CVC4: (eEDITIONS)(vcVOLUMES_CONTENTS)

(e = Edition(Volume(vc)) FirstBook(e) = Book(vc) BookPos(vc) = 1)

- RVC5: No edition may contain same book more than once.

CVC5: (eEDITIONS)(vc,vc’VOLUMES_CONTENTS)

(Edition(Volume(vc)) = Edition(Volume(vc’)) Book(vc) Book(vc’))

- RBL5: No copy may be borrowed less than 0 days or more than 300

days.

CBL5: (blBORROWS_LISTS)

(0 DueReturnDate(bl) – BorrowDate(Borrow(bl)) 300)

- RBL6: No copy may be simultaneously borrowed to more than one sub-

scriber.

CBL6: (bl, bl’BORROWS_LISTS) (Copy(bl) = Copy(bl’))

(ActualReturnDate(bl’) NULLS BorrowDate(Borrow(bl)

ActualReturnDate(bl’) ActualReturnDate(bl) NULLS

BorrowDate(Borrow(bl’) ActualReturnDate(bl))

- RBL7: No copy may be returned before it was borrowed and after 100

years since corresponding borrow date.

CBL7: (blBORROWS_LISTS)

(0 ActualReturnDate(bl) – BorrowDate(Borrow(bl)) 36,500)

c.2 There are no other constraints that apply in this sub-universe too, but

are missing from this model.

Page 416: Laborator Baze date

410

2.2 Second refinement algorithm: Keys Discovery

Assistance

Applying the assistance algorithm for keys discovery yields the follow-

ing:

PERSONS and BOOKS

n = 3, as there are three not one-to-one mappings defined on both of them

(FName, LName, and e-mail for PERSONS, and BTitle, BYear,

and FirstAuthor for BOOKS), all being prime in this context and

forming a (semantic) key for each of these two object sets (accord-

ing to CP5 and CB4, respectively) no other (semantic) keys

may exist for either of these sets.

PUBLISHERS

n = 0 no other semantic key exist.

COPIES

n = 1 (nothing to do, as according to b.2 above, Volume is not one-to-one)

no other semantic key exist.

BORROWS

n = 2 (nothing to do, as according to CBR3 above, BorrowDate Subscri-

ber is minimally one-to-one) no other semantic key exist.

CO-AUTHORS

n = 3, as there are three not one-to-one mappings defined on it, all of them

being prime: the two canonical Cartesian projections Author and

Book, plus PosInList. Obviously, K = {Author Book}, as CO-

AUTHORS is a well-defined binary association (see restriction

RCA3).

i = 2:

- Author PosInList key? No, because several authors (and even same

ones) may occupy a same position in different co-author lists.

- Book PosInList key? YES, because in any position of any co-author

list only one co-author may appear.

Consequently, K = {Author Book, Book PosInList}.

Page 417: Laborator Baze date

411

EDITIONS

n = 4, as there are four not one-to-one mappings defined on it, all being

prime: ETitle, Publisher, FirstBook, and EYear. According to

CE4, K = {Publisher FirstBook EYear}, as this product is mi-

nimally one-to-one.

i = 2

- ETitle Publisher key? No, because even a same publisher may publish

several editions, even of a same book (although not necessarily),

having same title.

- ETitle FirstBook key? No, because even a same publisher may publish

several editions, even of a same book (although not necessarily),

having same title and first book.

- ETitle EYear key? No, because even a same publisher may publish se-

veral editions (of different books, generally) in a same year.

i = 3

- ETitle Publisher FirstBook key? No, because even a same publisher

may publish several editions, even of a same book (although not

necessarily), having same title and same first book (in different

years).

- ETitle FirstBook EYear key? No, because even a same publisher

may publish several editions (of different books) having same first

book, in a same year.

- ETitle EYear Publisher key? No, because even a same publisher may

publish several editions (of different books, generally) in a same

year, having same title.

Consequently, EDITIONS does not have any other (semantic) key.

VOLUMES

n = 3, as there are four not one-to-one mappings defined on it: VPrice,

VTitle, VNo, and Edition, but, obviously, VPrice is not prime: pri-

ces of volumes might never contribute to their unique

identification in this context. According to RV4, K = {ISBN}.

i = 2

Page 418: Laborator Baze date

412

- VTitle VNo key? No, because even a same publisher may publish se-

veral editions including volumes having same title and number.

- VTitle Edition key? YES, because no edition may contain several

volumes having same title.

- VNo Edition key? YES, because no edition may contain several vo-

lumes having same number.

Consequently, K = {ISBN, VTitle Edition, VNo Edition}.

VOLUMES_CONTENTS

n = 3, as there are three not one-to-one mappings defined on it, all of them

being prime: the two canonical Cartesian projections Volume and

Book, plus BookPos. Obviously, K = {Volume Book}, as VO-

LUMES_CONTENTS is a well-defined binary association (see res-

triction RVC3).

i = 2:

- Book BookPos key? No, because same book may occupy a same posi-

tion in different volumes (of different editions).

- Volume BookPos key? YES, because in any position of any volume

only one book may appear.

Consequently, K = {Volume Book, Volume BookPos}.

BORROWS_LISTS

n = 4, as there are four not one-to-one mappings defined on it, all of them

being prime: the two canonical Cartesian projections Copy and

Borrow, plus DueReturnDate and ActualReturnDate. Obviously,

K = {Copy Borrow}, as BORROWS_LISTS is a well-defined bi-

nary association (see restriction RBL4).

i = 2:

- Borrow DueReturnDate key? No, because there may be for a same

borrow several books that need to be returned at a same date.

- Borrow ActualReturnDate key? No, because there may be for a same

borrow several books that are returned at a same date.

Page 419: Laborator Baze date

413

- Copy DueReturnDate key? No, because, for example, a same copy

may be borrowed several times within a same day for only some

hours (i.e 0 days).55

- Copy ActualReturnDate key? No, because, for example, a same copy

may be borrowed several times within a same day for only some

hours (i.e 0 days) and actually being returned the same day at least

twice.56

- DueReturnDate ActualReturnDate key? No, because there may be, e-

ven for a same borrow, several books that are both returned at a

same date and due to be returned at a same date.

i = 3:

- Borrow DueReturnDate ActualReturnDate key? No, because there

may be for a same borrow several books that need to be returned

at a same date and are returned at a same date.

- Copy DueReturnDate ActualReturnDate key? No, because, for

example, a same copy may be borrowed several times within a

same day for only some hours (i.e 0 days) and actually being re-

turned the same day at least twice.

Consequently, BORROWS_LISTS does not have any other (semantic) key.

2.3 Third refinement algorithm: E-RD Cycles Analysis By applying the initial step of the algorithm for E-RD cycles analysis, the

following 6 cycles are discovered in the structural E-RD shown in figure

A.1.1, out of which 3 are of the commutative type and other 3 are of the

generalized commutative type (see figures A.1.2 to A.1.7 below):

55

Note that, obviously, if DueReturnDate is implemented as a time stamp (i.e. also stor-

ing the corresponding time, not only the date), then this product is a key, but obviously,

this should not happen as it does not make that much sense to also ask for a time

deadline in this context. 56

Note that, obviously, similar to DueReturnDate above, if ActualReturnDate is imple-

mented as a time stamp (i.e. also storing the corresponding time, not only the date, which

would make sense), then this product is a key.

Page 420: Laborator Baze date

414

2.3.1 First commutative-type cycle

FirstAuthor

PERSONS BOOKS

CO-AUTHORS

Figure A.1.2 First commutative-type cycle from A.1.1

Obviously, the corresponding commutativity question is: Coauthor ?=

FirstAuthor Book (should, for any book, any coauthor be its first au-

thor?); trivially, the answer is no (as there may be several coauthors for a

book, but there is only one first coauthor for each book, and first authors

should appear only once in the coauthors lists, on the corresponding first

position).

Dually, the corresponding anti-commutativity question is: (x CO-AU-

THORS) (Coauthor(x) ? FirstAuthor Book(x)) (should, for any book,

any coauthor be distinct than its first author?); obviously, the answer is

yes (as first authors should appear only once in the coauthors lists, on

the corresponding first position). Consequently, the following con-

straint should be added to the db scheme:

ACC1: (xCO-AUTHORS) (Coauthor(x) FirstAuthor Book(x))

2.3.2 First generalized commutative-type cycle

PERSONS BOOKS

Subscriber CO-AUTHORS

BORROWS VOLUMES_CONTENTS

BORROWS_LISTS Volume VOLUMES

COPIES

Figure A.1.3 First generalized commutative-type cycle from A.1.1

Page 421: Laborator Baze date

415

This cycle has three sources (CO-AUTHORS, VOLUMES_CONTENTS,

and BORROWS_ LISTS) and three destinations (PERSONS, BOOKS, and

VOLUMES).

Let us consider any elements from the three source nodes: co from CO-

AUTHORS, vc from VOLUMES_CONTENTS, and bl from BORROWS_

LISTS; the corresponding three equality questions (associated to the desti-

nation nodes) are the following:

1. Author(co) ?= Subscriber(Borrow(bl)) (are there cases when co-

authors of books should also be borrowers?)

2. Book(co) ?= Book(vc)) (are there cases when co-authored books

should also be published in edition volumes?)

3. Volume(vc) ?= Volume(Copy(bl)) (are there cases when published

in edition volumes should also have borrowed copies?).

Corresponding answers are the following:

1. No: co-authors may be borrowers too, but this is never mandatory.

2. No: on one hand, co-authored (just like any other) books may not

be published; on the other, published volumes need not to be co-

authored.

3. On one hand, no: published volumes need not even to be in the li-

brary’s possession; on the other, YES: all borrowed copies have to

have been previously published.

Consequently, at a first glance, the following constraint has to be added to

the db too:

CBL8:(blBORROWS_LISTS)(vVOLUMES)(Volume(Copy(bl)) = v).

Thinking deeper, this constraint is implied by the following stronger one:

CC4: (cCOPIES)(vVOLUMES)(Volume(c) = v) (in order for a vo-

lume copy to exist, that volume should have been published),

which is obviously equivalent to the second half of RC2: Volume should

be totally defined; as this constraint is already present in the db scheme,

no other implied constraint has to be added to it.

Page 422: Laborator Baze date

416

2.3.3 Second generalized commutative-type cycle

This cycle has two sources (VOLUMES_CONTENTS and BORROWS_

LISTS), as well as two destinations (PERSONS and VOLUMES).

FirstAuthor

PERSONS BOOKS

Subscriber

BORROWS VOLUMES_CONTENTS

BORROWS_LISTS Volume VOLUMES

COPIES

Figure A.1.4 Second generalized commutative-type cycle from A.1.1

Let us consider any elements from the two source nodes: vc from VO-

LUMES CONTENTS and bl from BORROWS_ LISTS; the corresponding

two equality questions (associated to the destination nodes) are the fol-

lowing:

1. FirstAuthor(Book(vc)) ?= Subscriber(Borrow(bl)) (are there cases

when first authors of books should also be borrowers?)

2. Volume(vc) ?= Volume(Copy(bl)) (are there cases when published

in edition volumes should also have borrowed copies?).

Corresponding answers are the following:

1. No: first authors may be borrowers too, but this is never mandato-

ry.

2. On one hand, no: published volumes need not even to be in the li-

brary’s possession; on the other, YES: all borrowed copies have to

have been previously published.

Consequently, as per 2.3.2 above, no additional constraint should be ad-

ded to the db scheme.

Page 423: Laborator Baze date

417

2.3.4 Second commutative-type cycle

BOOKS

VOLUMES_CONTENTS

FirstBook

VOLUMES

Edition

EDITIONS

Figure A.1.5 Second commutative-type cycle from A.1.1

Obviously, there is one source (VOLUMES_CONTENTS), one destination

(BOOKS), and the corresponding commutativity question is: Book ?=

FirstBook Edition Volume (should, for any volume, any included book

be its first one?); trivially, the answer is no (as there may be several books

for a volume, but there is only one such first book per volume).

Dually, the corresponding anti-commutativity question is: ( x VO-

LUMES_CONTENTS) (Book(x) ? FirstBook Edition Volume(x))

(should, for any volume, any included book be distinct from its first

one?); obviously, the answer is no, as the first book is always equal to

itself, so no supplementary constraint should be added to the db scheme in

connection with this cycle (which is an uninteresting one).

2.3.5 Third generalized commutative-type cycle

This cycle has two sources (CO-AUTHORS and BORROWS_ LISTS), as

well as two destinations (PERSONS and BOOKS).

Let us consider any elements from the two source nodes: ca from CO-

AUTHORS and bl from BORROWS_ LISTS; the corresponding two equa-

lity questions (associated to the destination nodes) are the following:

1. Author(ca) ?= Subscriber(Borrow(bl)) (are there cases when co-

authors of books should also be borrowers?)

Page 424: Laborator Baze date

418

PERSONS BOOKS

Subscriber CO-AUTHORS

BORROWS

FirstBook

BORROWS_LISTS Volume VOLUMES

Edition

COPIES EDITIONS

Figure A.1.6 Third generalized commutative-type cycle from A.1.1

2. Book(ca) ?= FirstBook(Edition(Volume(Copy(bl))) (are there ca-

ses when co-authored books should also have borrowed copies of

volumes of their editions?).

Corresponding answers are the following:

1. No: co-authors may be borrowers too, but this is never mandatory

(also see 2.3.2 above).

2. On one hand, no: co-authored books need not even to be in the li-

brary’s possession; on the other, no again: not all borrowed copies

have to have been co-authored (some might only have one author).

Consequently, no supplementary constraint should be added to the db

scheme in connection with this cycle (which is an uninteresting one).

2.3.6 Third commutative-type cycle

Obviously, there is one source (BORROWS_LISTS), one destination

(PERSONS), and the corresponding commutativity question is: Subscri-

ber Borrow ?= FirstAuthor FirstBook Edition Volume Copy

(should subscribers borrowing copies be first authors of first books of the

editions to which that volume copies belongs?); trivially, the answer is no

(as any subscriber may borrow books without being either the first or any

other co-other of the corresponding book).

Page 425: Laborator Baze date

419

FirstAuthor

PERSONS BOOKS

Subscriber

BORROWS

FirstBook

BORROWS_LISTS Volume VOLUMES

Edition

COPIES EDITIONS

Figure A.1.7 Third commutative-type cycle from A.1.1

Dually, the corresponding anti-commutativity question is: (x BOR-

ROWS_LISTS) (Subscriber Borrow(x) ? FirstAuthor FirstBook Edi-

tion Volume Copy(x)) (should subscribers borrowing copies never be

first authors of first books of the editions to which that volume copies be-

longs?); obviously, the answer is no (as any first author of a book may

borrow that book too), so no supplementary constraint should be added to

the db scheme in connection with this cycle (which is an uninteresting

one too).

2.4 Final Mathematical Scheme By merging all above refinements with the initial scheme from section 2.0

above, the following final mathematical scheme results:

PERSONS

x NAT(6), total

FName ASCII(128)

LName ASCII(64), total

e-mail ASCII(255)

CP5: e-mail FName LName key

BOOKS

x NAT(6), total

BTitle ASCII(255), total

Page 426: Laborator Baze date

420

BYear [-2500, Year(SysDate())]

FirstAuthor : BOOKS PERSONS, total

CB4: FirstAuthor BTitle BYear key

CO-AUTHORS = (PERSONS, BOOKS)

x NAT(7), total

PosInList [2, 16], total

CAK2: Book PosInList key

PUBLISHERS

x NAT(4), total

PubName ASCII(128), total

EDITIONS

x NAT(6), total

ETitle ASCII(255), total

EYear [-2500, Year(SysDate())]

Publisher : EDITIONS PUBLISHERS, total

FirstBook : EDITIONS BOOKS, total

CE4: Publisher FirstBook EYear key

VOLUMES

x NAT(7), total

ISBN ASCII(16)

VTitle ASCII(255)

VNo [1, 255], total

VPrice CURRENCY(8), total

Edition : VOLUMES EDITIONS, total, onto

VK1: VTitle Edition key

VK2: VNo Edition key

VOLUMES_CONTENTS = (BOOKS, VOLUMES)

x NAT(7), total

BookPos [1, 16], total

VCK2: Volume BookPos key

COPIES

x NAT(8), total

InvNo ASCII(32), total

Page 427: Laborator Baze date

421

Volume : COPIES VOLUMES, total

BORROWS

x NAT(11), total

BorrowDate [6/1/2011, SysDate()], total

Subscriber : BORROWS PERSONS, total

CBR3: BorrowDate Subscriber key

BORROWS_LISTS = (BORROWS, COPIES)

x NAT(12), total

DueReturnDate [6/1/2011, SysDate() + 300], total

ActualReturnDate [6/1/2011, SysDate()]

CBL4: Borrow Copy key

CP6: (bBORROWS)(FName(Subscriber(b)) NULLS

e-mail(Subscriber(b)) NULLS)

CVC4: (eEDITIONS)(vcVOLUMES_CONTENTS)

(e = Edition(Volume(vc)) FirstBook(e) = Book(vc) BookPos(vc) = 1)

CVC5: (eEDITIONS)(vc,vc’VOLUMES_CONTENTS)

(Edition(Volume(vc)) = Edition(Volume(vc’)) Book(vc) Book(vc’))

CBL5: (blBORROWS_LISTS)

(0 DueReturnDate(bl) – BorrowDate(Borrow(bl)) 300)

CBL6: (bl, bl’BORROWS_LISTS) (Copy(bl) = Copy(bl’))

(ActualReturnDate(bl’) NULLS BorrowDate(Borrow(bl)

ActualReturnDate(bl’) ActualReturnDate(bl) NULLS

BorrowDate(Borrow(bl’) ActualReturnDate(bl))

CBL7: (blBORROWS_LISTS)

(0 ActualReturnDate(bl) – BorrowDate(Borrow(bl)) 36,500)

ACC1: (xCO-AUTHORS) (Coauthor(x) FirstAuthor Book(x))

Note that, as compared to the initial one, 11 more constraints (out of

which there are four keys and seven non-relational ones) have been added

Page 428: Laborator Baze date

422

to this final one, namely: CAK2; Edition : VOLUMES EDITIONS, on-

to; VK1; VK2; VCK2; CVC4; CVC5; CBL5; CBL6; CBL7; and ACC1.

3. Relational Scheme and Associated Non-relational

Constraints List

3.0 Relational db scheme

By applying the algorithm for translating mathematical schemes into rela-

tional ones and non-relational constraint lists, the following output is ob-

tained (with an example instance having at least two tuples per table):

PERSONS (x, e-mail FName LName)

x FName LName e-mail

NAT(6) ASCII(128) ASCII(64) ASCII(255)

NOT

NULL

NOT NULL

1 Homer

2 William Shakespeare

3 Peter Buneman opb @ inf.ed.ac.uk

4 Serge Abiteboul

5 Dan Suciu [email protected]

BOOKS (x, FirstAuthor BTitle BYear)

x FirstAuthor BTitle BYear

NAT(6) Im(PERSONS.x) ASCII(255) [-2500,

Year(SysDate())]

NOT

NULL

NOT NULL NOT NULL

1 1 Odyssey -700

2 2 As You Like It 1600

3 4 Data on the Web: From

Relations to Semi-

structured Data and

XML

1999

Page 429: Laborator Baze date

423

CO-AUTHORS (x, Person Book, Book PosInList)

x Book Person PosInList

NAT(7) Im(BOOKS.x) Im(PERSONS.x) [2, 16]

NOT NULL NOT NULL NOT NULL NOT NULL

1 3 3 2

2 3 5 3

PUBLISHERS (x, PubName)

x PubName

NAT(4) ASCII(128)

NOT NULL NOT NULL

1 Apple Academic Press

2 Springer Verlag

3 Morgan Kaufmann

4 Penguin Books

5 Washington Square Press

EDITIONS (x, Publisher FirstBook EYear)

x Publisher FirstBook ETitle EYear

NAT(6

)

Im(PUBLISHERS.

x)

Im(BOOKS.

x)

ASCII(25

5)

[-2500,

Year(SysDate()

)]

NOT

NULL

NOT NULL NOT NULL NOT

NULL

1 4 1 The

Odyssey

translated

by Robert

Fagles

2012

2 5 2 As You

Like It

2011

3 3 3 Data on

the Web:

From

Relations

1999

Page 430: Laborator Baze date

424

to Semi-

structured

Data and

XML

VOLUMES (x, ISBN, Edition VNo, Edition VTitle)

x Edition VNo VTitle ISBN Price

NAT(7) Im(EDI-

TIONS.x)

[1,

255]

ASCII(255) ASCII(16) CUR-

RENCY(8)

NOT

NULL

NOT

NULL

NOT

NULL

NOT NULL

1 1 1 0-670-

82162-4

$12.95

2 2 1 978-

1613821114

$9.99

3 3 1 978-

1558606227

$74.95

VOLUMES_CONTENTS (x, Volume Book, Volume BookPos)

x Volume Book BookPos

NAT(7) Im(VOLUMES.x) Im(BOOKS.x) [1, 255]

NOT NULL NOT NULL NOT NULL NOT NULL

1 1 1 1

2 2 2 1

3 3 3 1

Page 431: Laborator Baze date

425

BORROWS (x, BorrowDate Subscriber)

x Subscriber BorrowDate

NAT(11) Im(PERSONS.x) [6/1/2011, SysDate()]

NOT NULL NOT NULL NOT NULL

1 5 10/29/2012

COPIES (x, InvNo)

x InvNo Volume

NAT(8) ASCII(32) Im(VOLUMES.x)

NOT NULL NOT NULL NOT NULL

1 H-O-1 1

2 H-O-2 1

3 S-AYLI-1 2

4 ABS-DW-1 3

5 ABS-DW-2 3

BORROWS_LISTS (x, Borrow Copy)

x Borrow Copy DueRe-

turnDate

ActualRe-

turnDate

NAT(12) Im(BORROWS.x) Im(COPIES.x) [6/1/2011,

SysDate()

+ 300]

[6/1/2011,

SysDate()]

NOT

NULL

NOT NULL NOT NULL NOT

NULL

1 1 1 11/29/2012 11/23/2012

2 1 3 12/29/2012

3.1 Non-relational constraints list The following 8 constraints are non-relational:

Edition : VOLUMES EDITIONS, onto;

CP6:

(bBORROWS)(FName(Subscriber(b)) NULLS

e-mail(Subscriber(b)) NULLS)

Page 432: Laborator Baze date

426

CVC4:

(eEDITIONS)(vcVOLUMES_CONTENTS)

(e = Edition(Volume(vc)) FirstBook(e) = Book(vc) BookPos(vc) = 1)

CVC5:

(eEDITIONS)(vc,vc’VOLUMES_CONTENTS)

(Edition(Volume(vc)) = Edition(Volume(vc’)) Book(vc) Book(vc’))

CBL5:

(blBORROWS_LISTS)

(0 DueReturnDate(bl) – BorrowDate(Borrow(bl)) 300)

CBL6:

(bl, bl’BORROWS_LISTS) (Copy(bl) = Copy(bl’))

(ActualReturnDate(bl’) NULLS BorrowDate(Borrow(bl)

ActualReturnDate(bl’) ActualReturnDate(bl) NULLS

BorrowDate(Borrow(bl’) ActualReturnDate(bl))

CBL7:

(blBORROWS_LISTS)

(0 ActualReturnDate(bl) – BorrowDate(Borrow(bl)) 36,500)

ACC1:

(xCO-AUTHORS) (Coauthor(x) FirstAuthor Book(x)).

4. Database Implementation

4.0 Technology choice

I have chosen MS Access because of the following reasons:

- being the only RDBMS installed on the faculty labs PCs, we did

our DB labs in Access;

Page 433: Laborator Baze date

427

- I have a copy of MS Office 2010, including Access 2010, installed

on my PC;

- Access is a fine choice for small and medium (up to 2 GB) dbs;

- any RDBMS is just a tool: you should exploit it at maximum, do

not use its non-sense facilities, and concentrate on the correctness

and optimality of your solution.

I have chosen Oracle Database because of the following reasons:

- being the favorite RDBMS used in western universities DB labs,

the DB Labs Notes by Prof. Christian Mancas and Drd. Alina Di-

cu also include Oracle solutions, in parallel with the Access ones;

- I have a freely downloadable copy of Oracle Xy installed on my

PC;

- Oracle is a fine choice for medium and large dbs;

- any RDBMS is just a tool: you should exploit it at maximum, do

not use its non-sense facilities, and concentrate on the correctness

and optimality of your solution.

4.1 Access db By applying the algorithm for translating rdb schemes into Access 2010

dbs, the following db was obtained (note that a Boolean Author? column

was added to PERSONS, for easing both non-relational constraint en-

forcement and users interaction with the db):

4.1.0 DDL statements for creating and populating the db CREATE TABLE PERSONS (x COUNTER PRIMARY KEY,

FName VARCHAR(128), LName VARCHAR(64) NOT NULL,

[e-mail] VARCHAR(255), [Author?] BIT,

CONSTRAINT PKey UNIQUE ([e-mail], LName, FName));

CREATE TABLE BOOKS (x COUNTER PRIMARY KEY,

FirstAuthor LONG NOT NULL, BTitle VARCHAR(255) NOT NULL,

BYear INT,

CONSTRAINT fkFA FOREIGN KEY (FirstAuthor) REFERENCES

PERSONS,

CONSTRAINT BKey UNIQUE (BTitle, FirstAuthor, BYear));

CREATE TABLE [CO-AUTHORS] (x COUNTER PRIMARY KEY,

Person LONG NOT NULL, Book LONG NOT NULL,

PosInList BYTE NOT NULL,

Page 434: Laborator Baze date

428

CONSTRAINT fkP FOREIGN KEY (Person) REFERENCES

PERSONS,

CONSTRAINT fkB FOREIGN KEY (Book) REFERENCES

BOOKS,

CONSTRAINT CAAKey UNIQUE (Book, Person),

CONSTRAINT CAPKey UNIQUE (Book, PosInList));

CREATE TABLE PUBLISHERS (x COUNTER PRIMARY KEY,

PubName VARCHAR(128) NOT NULL UNIQUE);

CREATE TABLE EDITIONS (x COUNTER PRIMARY KEY,

Publisher LONG NOT NULL, FirstBook LONG NOT NULL,

ETitle VARCHAR(255) NOT NULL, EYear INT,

CONSTRAINT fkPub FOREIGN KEY (Publisher) REFERENCES

PUBLISHERS,

CONSTRAINT fkBk FOREIGN KEY (FirstBook) REFERENCES

BOOKS,

CONSTRAINT EKey UNIQUE (FirstBook, Publisher, EYear));

CREATE TABLE VOLUMES (x COUNTER PRIMARY KEY,

Edition LONG NOT NULL, VNo BYTE NOT NULL,

VTitle VARCHAR(255), ISBN VARCHAR(16) UNIQUE,

Price CURRENCY NOT NULL,

CONSTRAINT fkE FOREIGN KEY (Edition) REFERENCES

EDITIONS,

CONSTRAINT VNKey UNIQUE (Edition, VNo),

CONSTRAINT VTKey UNIQUE (Edition, VTitle));

CREATE TABLE VOLUMES_CONTENTS (x COUNTER PRIMARY KEY,

Volume LONG NOT NULL, Book LONG NOT NULL,

BookPos BYTE NOT NULL,

CONSTRAINT fkV FOREIGN KEY (Volume) REFERENCES

VOLUMES,

CONSTRAINT fkVB FOREIGN KEY (Book) REFERENCES

BOOKS,

CONSTRAINT VCBKey UNIQUE (Volume, Book),

CONSTRAINT VCPKey UNIQUE (Volume, BookPos));

CREATE TABLE BORROWS (x COUNTER PRIMARY KEY,

Subscriber LONG NOT NULL, BorrowDate DATE NOT NULL,

CONSTRAINT fkS FOREIGN KEY (Subscriber) REFERENCES

PERSONS,

CONSTRAINT BRKey UNIQUE (BorrowDate, Subscriber));

CREATE TABLE COPIES (x COUNTER PRIMARY KEY,

Volume LONG NOT NULL, InvNo VARCHAR(32) NOT NULL UNIQUE,

CONSTRAINT fkS FOREIGN KEY (Volume) REFERENCES VOLUMES);

CREATE TABLE BORROWS_LISTS (x COUNTER PRIMARY KEY,

Borrow LONG NOT NULL, Copy LONG NOT NULL,

Page 435: Laborator Baze date

429

DueReturnDate DATE NOT NULL, ActualReturnDate DATE,

CONSTRAINT fkBw FOREIGN KEY (Borrow) REFERENCES

BORROWS,

CONSTRAINT fkCy FOREIGN KEY (Copy) REFERENCES

COPIES,

CONSTRAINT BLKey UNIQUE (Copy, Borrow));

4.1.1 Tables Relationships

Figure A.1.8 Relationships between LibraryDB.accdb tables

4.1.2 Table Lookups SQL statements

4.1.2.1 PERSONS

Foreign keys BOOKS.FirstAuthor and CO_AUTHORS.Co-Author are

using the following query:

SELECT x, IIf(IsNull([FName]),"",[FName] & " ") & [LName] &

IIf(IsNull([e-mail]),""," " & [e-mail])

FROM PERSONS

WHERE [Author?]

ORDER BY IIf(IsNull([FName]),"",[FName] & " ") & [LName] &

IIf(IsNull([e-mail]),""," " & [e-mail]);

Foreign key BORROWS.Subscriber is using the following query:

SELECT x, [e-mail] & " " & [FName] & " " & [LName]

AS [e-mail First and Last Names]

FROM PERSONS

Page 436: Laborator Baze date

430

ORDER BY [e-mail] & " " & [FName] & " " & [LName];

4.1.2.2 BOOKS

Foreign keys CO_AUTHORS.Book, EDITIONS.FirstBook, and VO-

LUMES_CONTENTS.Book are using the following query:

SELECT BOOKS.x, IIf(IsNull([FName]),"",[FName] & " ") &

[LName] & ", " & [BTitle] & ", " & [BYear]

AS [FirstAuthor, Book Title, Year]

FROM PERSONS INNER JOIN BOOKS

ON PERSONS.x = BOOKS.FirstAuthor

ORDER BY IIf(IsNull([FName]),"",[FName] & " ") & [LName] &

", " & [BTitle] & ", " & [BYear];

4.1.2.3 PUBLISHERS

Foreign key EDITIONS.Publisher is using the following query:

SELECT x, PubName FROM PUBLISHERS ORDER BY PubName;

4.1.2.4 EDITIONS

Foreign key VOLUMES.Edition is using the following query:

SELECT EDITIONS.x, IIf(IsNull([FName]),"",[FName] & " ") &

[LName] & ", " & [ETitle] & IIf(IsNull([eyear]),"",", " &

[EYear]) & ", " & IIf(IsNull([Publisher]),"",[PubName]) &

", " & [BTitle]

AS [First Author, Title, Year, Publisher, First Book]

FROM PUBLISHERS RIGHT JOIN (PERSONS INNER JOIN (BOOKS

INNER JOIN EDITIONS ON BOOKS.x = EDITIONS.FirstBook)

ON PERSONS.x = BOOKS.FirstAuthor)

ON PUBLISHERS.x = EDITIONS.Publisher

ORDER BY IIf(IsNull([FName]),"",[FName] & " ") & [LName] &

", " & [ETitle] & IIf(IsNull([eyear]),"",", " & [EYear])

& ", " & IIf(IsNull([Publisher]),"",[PubName]) & ", " &

[BTitle];

4.1.2.5 VOLUMES

Foreign key COPIES.Volume is using the following query:

SELECT VOLUMES.x, IIf(IsNull([FName]),"",[FName] & " ") &

[LName] & ", " & [etitle] & ", " &

IIf(IsNull([eyear]),"",[eyear]) & ", " & [PubName] &

", v." & [VNo]

AS [First Author, EdTitle, EdYear, Publisher, VolNo],

VOLUMES.ISBN

FROM PUBLISHERS RIGHT JOIN (PERSONS RIGHT JOIN ((BOOKS

Page 437: Laborator Baze date

431

RIGHT JOIN EDITIONS ON BOOKS.x = EDITIONS.FirstBook)

RIGHT JOIN VOLUMES ON EDITIONS.x = VOLUMES.Edition)

ON PERSONS.x = BOOKS.FirstAuthor)

ON PUBLISHERS.x = EDITIONS.Publisher

ORDER BY IIf(IsNull([FName]),"",[FName] & " ") & [LName] &

", " & [etitle] & ", " & IIf(IsNull([eyear]),"",[eyear])

& ", " & [PubName] & ", v." & [VNo];

4.1.2.6 COPIES

Foreign key BORROWS_LISTS.Copy is using the following query:

SELECT COPIES.x, "Inv.No. " & [InvNo] & ", " &

IIf(IsNull([FName]),"",[FName] & " ") & [LName]

& ", " & [etitle] & ", " &

IIf(IsNull([eyear]),"",[eyear]) & ", " &

[PubName] & ", v." & [VNo]

AS [InvNo, First Author, EdTitle, EdYear,

Publisher, VolNo]

FROM (PUBLISHERS RIGHT JOIN (PERSONS INNER JOIN

((BOOKS INNER JOIN EDITIONS

ON BOOKS.x = EDITIONS.FirstBook) INNER JOIN

VOLUMES ON EDITIONS.x = VOLUMES.Edition)

ON PERSONS.x = BOOKS.FirstAuthor)

ON PUBLISHERS.x = EDITIONS.Publisher)

INNER JOIN COPIES ON VOLUMES.x = COPIES.Volume

ORDER BY "Inv.No. " & [InvNo] & ", " &

IIf(IsNull([FName]),"",[FName] & " ") & [LName]

& ", " & [etitle] & ", " &

IIf(IsNull([eyear]),"",[eyear]) & ", " &

[PubName] & ", v." & [VNo];

4.1.2.7 BORROWS

Foreign key BORROWS_LISTS.Borrow is using the following query:

SELECT BORROWS.x, [FName] & " " & [LName] & ", "

& [e-mail] & ", " & [BorrowDate]

AS [Subscriber, e-mail, Borrow Date]

FROM PERSONS INNER JOIN BORROWS

ON PERSONS.x = BORROWS.Subscriber

ORDER BY [FName] & " " & [LName] & ", " &

[e-mail] & ", " & [BorrowDate];

Page 438: Laborator Baze date

432

4.1.3 Validation rules, Comments, and Default values

4.1.3.1 Enforcing (co-)domain (range) and tuple (check) constraints

Unfortunately, Access’ SQL does not provide means for enforcing either

(co-)domain (range) or tuple (check) constraints. Fortunately, both of

them can be enforced through its GUI57

by using validation rules (and as-

sociated validation texts).

Figure A.1.9 shows the result of enforcing restriction RB2, the co-domain

of BYear : BOOKS [-2500, current year].

Figure A.1.9 Enforcing restriction RB2

Figure A.1.10 shows the result of enforcing restriction RBR1, the co-

domain of BorrowDate : BORROWS [6/1/2011, SysDate()].

Figure A.1.11 shows the result of enforcing restriction RBL1, the co-

domain of DueReturnDate : BORROWS_LISTS [6/1/2011, SysDate() +

300].

Figure A.1.12 shows the result of enforcing restriction RBL2, the co-do-

main of ActualReturnDate : BORROWS_LISTS [6/1/2011, SysDate() +

900]. 57

They can also be manipulated programmatically, through VBA, DAO, and ADO.

Page 439: Laborator Baze date

433

Figure A.1.10 Enforcing restriction RBR1 and adding default value to

BorrowDate

Figure A.1.11 Enforcing restriction RBL1

Figure A.1.13 shows the result of enforcing restriction RCA1, the co-

domain of PosInList : CO-AUTHORS [1, 16].

Page 440: Laborator Baze date

434

Figure A.1.12 Enforcing restriction RBL2

Figure A.1.13 Enforcing restriction RCA1 and adding default value to

PosInList

Figure A.1.14 shows the result of enforcing restriction RE2, the co-

domain of EYear : EDITIONS [-2500, current year].

Page 441: Laborator Baze date

435

Figure A.1.14 Enforcing restriction RE2 and adding EYear’s default value

Figure A.1.15 shows the result of enforcing restriction RV4, the co-

domain of VNo : VOLUMES [1, 255].

Figure A.1.15 Enforcing restriction RV3 and adding VNo’s default value

Page 442: Laborator Baze date

436

Figure A.1.16 shows the result of enforcing restriction RVC1, the co-

domain of BookPos : VOLUMES_CONTENTS [1, 16].

Figure A.1.16 Enforcing restriction RVC1 and adding BookPos’ default

value

There are no tuple (check) constraints in this db; figure A.1.17 shows the

properties of a table, where, through its Validation rule (and associated

text) such constraints may be enforced.

Figure A.1.17 Enforcing tuple (check) constraints

Page 443: Laborator Baze date

437

4.1.3.2 Adding comments

Comments describing sets (tables) semantics are stored in the tables’ Des-

cription property (see figure A.1.17). Those on functions (columns), in

the homonym one of columns (fields, see figures A.1.9 to A.1.16).

4.1.3.2 Adding default values

Access too provides a Default Value property for functions (columns,

fields), which should always be used when appropriate to spare users re-

peatedely entering same most frequent values.

Figures A.1.10 and A.1.13 to A.1.16 show the default values added to this

db scheme. No other default values are appropriate.

4.2 Oracle db

5. Non-relational constraints enforcement

5.1 Access solutions In order to enforce non-relational constraints in Access, forms have to be

created for all involved tables, in order to associate to them VBA classes

that host corresponding trigger-type event-driven methods. These forms

will then have to make part of a db application that should hide corres-

ponding db tables and only allow data manipulation through forms.

Obviously, for this db, forms are needed to this end for tables: EDI-

TIONS, BORROWS, VOLUMES_CONTENTS, BORROWS_LISTS, and

CO-AUTHORS.

5.1.1 Edition : VOLUMES EDITIONS, onto

(y EDITIONS)( x VOLUMES)(Edition(x) = y) (Any edition should

have at least one volume.)

Ontoness is very easy to enforce: in this case, for example, each time a

new edition is inserted, a corresponding (first) volume should automati-

cally be inserted too and, dually, each time deletion of the last remaining

volume of an edition is successfully committed, the corresponding edition

should be automatically deleted too.

Page 444: Laborator Baze date

438

Consequently, this constraint has to be enforced both in the Form_EDI-

TIONS class, by using the Form_AfterUpdate event (so that the new edi-

tion be already saved in the corresponding table) and in the Form_VO-

LUMES class, by using the Form_AfterDelConfirm event (so that the last

volume be actually deleted from the corresponding table).

Note that automatically adding a first volume for each new edition, as

well as of the first book of this first volume in its content (see constraint

CVC4 below) is also an ergonomic feature of the application.

Also note that volumes cannot be deleted unless their content is previous-

ly deleted too.58

Not only as the the first book of the first volume of any

edition is automatically added, but especially for ergonomical reasons, the

application is also automatically deleting volume contents of any deleta-

ble volume, if users agree with it.

Note too that for deleting an edition left without any volume there are two

possible solutions:

a “tougher” one, consisting in deletion of any edition having no

volumes (for which no edition key is necessary)

a “softer” one, consisting in deleting only the edition just left

without any volume (for which its id should be previously stored

in a variable, as, after successful deletion of its last volume, it can-

not be anymore retrieved from the db)

Although it is a little bit more complicated, we chose the second approach

mainly because, anyhow, in order to establish whether or not a volume is

deletable and then to also automatically delete its content, programming

of the Form_Delete method is required.

Finally, note that, for ergonomical reasons, after successful automatical

deletions and insertions of both volumes and editions, all involved forms

and combo-boxes are requeried, in order for users not having to close and

re-open them for refreshing their data sources.

58

Obviously, volume cannot be deleted either if there are copies of them.

Page 445: Laborator Baze date

439

Here is, first, the code of class Form_VOLUMES:

'Form_VOLUMES class

Option Compare Database

Option Explicit

Private currEdition As Long

'*****************************************

Private Sub Form_Delete(Cancel As Integer)

'*****************************************

'Initializes global variable currEdition

'that is then used by Form_AfterDelConfirm.

'Moreover, prevents deletion when there are copies of the

'volume and deletes corresponding volume content if there

'are no copies of the volume and the user agrees with it,

'in order for deletion to succeed.

On Error GoTo err_point

If vbCancel = MsgBox("Are you sure you want to delete " _

& "the current volume?", _

vbQuestion + vbOKCancel + vbDefaultButton2, _

"Please confirm or cancel your request...") Then

Cancel = True

Else

If Not IsNull(DLookup("x", "COPIES", "Volume=" & Me!x))

Then

Cancel = True

MsgBox "Request denied!", vbCritical, _

"There are copies of this volume..."

Else

If vbCancel = MsgBox("Are you sure you want to also " _

& "delete the content of this volume?", _

vbQuestion + vbOKCancel + vbDefaultButton2, _

"Please confirm or cancel your request...")

Then

Cancel = True

MsgBox "Request denied!", vbCritical, _

"To delete volumes, their content must be " _

& "deleted too..."

Else

currEdition = Me!Edition

DoCmd.RunSQL "DELETE FROM VOLUMES_CONTENTS WHERE " _

& "Volume=" & Me!x

End If

End If

End If

Exit Sub

Page 446: Laborator Baze date

440

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, _

"Error in method Form_VOLUMES.Form_Delete..."

Cancel = True

End Sub

'**********************************************************

Private Sub Form_BeforeDelConfirm(Cancel As Integer,

Response As Integer)

'**********************************************************

'prevents Access from displaying its standard deletion

'confirmation message

Response = acDataErrContinue

End Sub

'**************************************************

Private Sub Form_AfterDelConfirm(Status As Integer)

'**************************************************

'enforces ontoness of Edition : VOLUMES -> EDITIONS

'(immediately after deletion of a last volume of an

'edition, also deletes corresponding edition)

On Error GoTo err_point

If Status = acDeleteOK Then

If IsNull(DLookup("x", "VOLUMES", "Edition=" _

& currEdition)) Then

DoCmd.RunSQL "DELETE FROM EDITIONS WHERE x=" _

& currEdition

MsgBox "Successfully deleted corresponding edition " _

& "too!", vbInformation, _

"Deleted volume was the only one of its edition..."

On Error Resume Next

Forms!EDITIONS.Requery

Forms!VOLUMES_CONTENTS.Requery

Forms!VOLUMES_CONTENTS!Volume.Requery

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_VOLUMES. " _

& "Form_AfterDelConfirm..."

End Sub

Secondly, here is the code of class Form_EDITIONS (obviously, not all

of it enforces this constraint, but, as during its enforcement the values of

the variables v, b, and p are needed to, corresponding code could not be

understood without their definitions and initializations):

Page 447: Laborator Baze date

441

'Form_EDITIONS class

Option Compare Database

Option Explicit

Dim v, b, p As Long

Dim switchPos As Boolean

'*************************

Private Sub Form_Current()

'*************************

On Error GoTo err_point

switchPos = False

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_EDITIONS.Form_Current..."

End Sub

'****************************************************

Private Sub FirstBook_BeforeUpdate(Cancel As Integer)

'****************************************************

'enforces constraints CVC4 (for any edition, its first book

should be

'the first one published in its first volume) and CVC5

'(no edition should include a book more than once)

Dim w, x As Variant

On Error GoTo err_point

If Me!FirstBook <> Me!FirstBook.OldValue Then

'CVC4: first book of any edition should be the first one

' of the edition first volume

If IsNull(Me!FirstBook) Then

Cancel = True

MsgBox "Please choose a not null value for First " _

& "Book!", vbCritical, _

"First book of any edition is compulsory..."

Me!FirstBook.Undo

Else

v = DLookup("VNo", "VOLUMES", "Edition = " & Me!x & _

" AND VNo=1")

If IsNull(v) Then

insertFirstVolume

Else

'CVC5: no edition should include a book more than once

w = DLookup("x", "VOLUMES_CONTENTS", "Book=" & _

Me!FirstBook & " AND Volume IN (SELECT x " _

& "FROM VOLUMES WHERE Edition=" & Me!x & ")")

If IsNull(w) Then

Page 448: Laborator Baze date

442

DoCmd.RunSQL "UPDATE VOLUMES_CONTENTS SET Book=" _

& Me!FirstBook & " WHERE Volume=" & v _

& " AND BookPos=1"

Else

x = DLookup("VNo", "VOLUMES", "x=" & _

DLookup("Volume", "VOLUMES_CONTENTS", _

"x=" & w))

If vbOK = MsgBox("Would you like to switch " & _

"positions between the previous and the " & _

"current books for this edition?", _

vbQuestion + vbOKCancel + vbDefaultButton2, _

"This book already exits in volume " & x & _

" of this edition...") Then

switchPos = True

p = DLookup("BookPos", "VOLUMES_CONTENTS", "x=" _

& w)

b = Me!FirstBook.OldValue

DoCmd.RunSQL "DELETE FROM VOLUMES_CONTENTS " &_

"WHERE x=" & w

DoCmd.RunSQL "UPDATE VOLUMES_CONTENTS SET Book" _

& "=" & Me!FirstBook & " WHERE BookPos = 1 " _

& "AND Volume=" & v

Else

Cancel = True

MsgBox "Please choose another value for " & _

"FirstBook!", vbCritical, "This book is " & _

"already known as belonging to volume number " _

& x & " of this edition..."

Me!FirstBook.Undo

End If

End If

End If

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_EDITIONS. " & _

"FirstBook_BeforeUpdate..."

Cancel = True

End Sub

'*****************************

Private Sub Form_AfterUpdate()

'*****************************

'enforces ontoness of Edition : VOLUMES -> EDITIONS

'(immediately after insertion of a new edition,

'inserts a corresponding first volume of it).

'Moreover, it also enforces constraint CVC4:

'for any edition, its first book should be

Page 449: Laborator Baze date

443

'the first one published in its first volume.

Dim w As Variant

On Error GoTo err_point

If switchPos Then

'enforces constraint CVC4

switchPos = False

DoCmd.RunSQL "INSERT INTO VOLUMES_CONTENTS (Volume, " _

& "Book, BookPos) VALUES (" & v & ", " & b & ", " _

& p & ")"

Else

'enforces ontoness of Edition : VOLUMES -> EDITIONS

w = DLookup("x", "VOLUMES", "Edition=" & Me!x)

If IsNull(w) Then

insertFirstVolume

End If

End If

On Error Resume Next

Forms!VOLUMES.Requery

Forms!VOLUMES!Edition.Requery

Forms!VOLUMES_CONTENTS.Requery

Forms!VOLUMES_CONTENTS!Volume.Requery

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_EDITIONS." _

& "Form_AfterUpdate..."

End Sub

'******************************

Private Sub insertFirstVolume()

'******************************

'called by Form_AfterUpdate

Dim v As Long

On Error GoTo err_point

DoCmd.RunSQL "INSERT INTO VOLUMES (Edition) VALUES (" _

& Me!x & ")"

v = DLookup("x", "VOLUMES", "Edition=" & Me!x & _

" AND VNo=1")

DoCmd.RunSQL "INSERT INTO VOLUMES_CONTENTS (Volume, Book" _

& ", BookPos) VALUES (" & v & ", " & Me!FirstBook & ", 1)"

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_EDITIONS." _

& "insertFirstVolume..."

End Sub

Page 450: Laborator Baze date

444

5.1.2 CP6

(bBORROWS)(FName(Subscriber(b)) NULLS

e-mail(Subscriber(b)) NULLS) (FName and e-mail should be compul-

sory for subscribers.)

Obviously, enforcing this constraint needs not VBA code, as it can be sim-

ply done by adding a corresponding filter to the SELECT statement of the

Subscriber combo-box from BORROWS (also see 4.1.2.1 above):

SELECT x, [e-mail] & " " & [FName] & " " & [LName]

AS [e-mail First and Last Names]

FROM PERSONS

WHERE [e-mail] Is Not Null AND FName Is Not Null

ORDER BY [e-mail] & " " & [FName] & " " & [LName];

5.1.3 CVC4

(eEDITIONS)(vcVOLUMES_CONTENTS)

(e = Edition(Volume(vc)) FirstBook(e) = Book(vc) BookPos(vc) = 1)

(For any edition, its first book should be the first one published in its first

volume.)

As we’ve already seen, this constraint is enforced by methods FirstBook_

BeforeUpdate and Form_AfterUpdate of class Form_EDITIONS (see

5.1.1 above).

5.1.4 CVC5

(eEDITIONS)(vc,vc’VOLUMES_CONTENTS)

(Edition(Volume(vc)) = Edition(Volume(vc’)) Book(vc) Book(vc’))

(No edition may contain same book more than once.)

As we’ve already seen, this constraint is enforced by method FirstBook_

BeforeUpdate of class Form_EDITIONS (see 5.1.1 above).

5.1.5 CBL5

(blBORROWS_LISTS)

(0 DueReturnDate(bl) – BorrowDate(Borrow(bl)) 300) (No

copy may be borrowed less than 0 days or more than 300 days.)

Obviously, this constraint is best enforceable by the DueReturnDate_Be-

foreUpdate method of class Form_ BORROWS_LISTS (Note that the cor-

responding form should never be used alone, but only as a sub-form of

Page 451: Laborator Baze date

445

BORROWS: otherwise, on blank lines Me!Borrow could not be always

defined!):

'********************************************************

Private Sub DueReturnDate_BeforeUpdate(Cancel As Integer)

'********************************************************

'enforces constraint CBL5: no copy may be borrowed less

'than 0 days or more than maxBorrowDays (300) days.

Dim bDate As Date

Dim days As Long

On Error GoTo err_point

If Me!DueReturnDate <> Me!DueReturnDate.OldValue Then

If Not IsNull(Me!DueReturnDate) Then

bDate = DLookup("BorrowDate", "BORROWS", "x = " & _

Me!Borrow)

days = DateDiff("y", bDate, Me!DueReturnDate)

If days < 0 Then

Cancel = True

MsgBox "Please specify a due return date greater " _

& "or equal to " & bDate & "!", vbCritical, _

"DueReturnDate value less than " _

& "the corresponding BorrowDate one..."

Me!DueReturnDate.Undo

ElseIf days > maxBorrowDays Then

Cancel = True

MsgBox "Please specify a due return date less or " _

& "equal to " & bDate + maxBorrowDays & "!", _

vbCritical, "DueReturnDate " & "value greater " _

& "than the corresponding BorrowDate one + " _

& maxBorrowDays & " days..."

Me!DueReturnDate.Undo

End If

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_BORROWS_LISTS." _

& "DueReturnDate_BeforeUpdate..."

Cancel = True

End Sub

5.1.6 CBL6

(bl, bl’ BORROWS_LISTS) (Copy(bl) = Copy(bl’))

(ActualReturnDate(bl’) NULLS BorrowDate(Borrow(bl)

ActualReturnDate(bl’) ActualReturnDate(bl) NULLS

Page 452: Laborator Baze date

446

BorrowDate(Borrow(bl’) ActualReturnDate(bl)) (No copy may be

simultaneously borrowed to more than one subscriber.)

Obviously, this is a fine example of non-relational constraint whose logic

formula is much more complicated than the corresponding enforcement

code: in fact, each time that a copy is selected for lending, all we have to

do is to check whether or not there is another row in BORROWS_LISTS

for the same copy and having ActualReturnDate null (meaning that it has

not been yet returned).

Trivially, the best event for enforcing this constraint is the Copy_Before-

Update one of class Form_BORROWS_LISTS; unfortunately, although

this solution works fine, Access is displaying the following unexpected

and unpleasant (both for users and programmers) error message:

Figure A.1.18 Unexpected unpleasant Access error message

The workaround for it is to postpone enforcement up to the corresponding

Form_BeforeUpdate event:

'***********************************************

Private Sub Form_BeforeUpdate(Cancel As Integer)

'***********************************************

'enforces constraint CBL6: No copy may be simultaneously

'borrowed to more than one subscriber.

Dim v As Variant

On Error GoTo err_point

If Me.NewRecord Or Me!Copy <> Me!Copy.OldValue Then

v = DLookup("DueReturnDate", "BORROWS_LISTS", "Copy=" & _

Me!Copy & " AND ActualReturnDate Is Null AND x <>" _

& Me!x)

If Not IsNull(v) Then

Cancel = True

MsgBox "... so it cannot be lend: it is due to be " & _

Page 453: Laborator Baze date

447

"returned on " & v, vbCritical, _

"This copy is not yet returned..."

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_BORROWS_LISTS." _

& "Form_BeforeUpdate..."

Cancel = True

End Sub

5.1.7 CBL7

(blBORROWS_LISTS)

(0 ActualReturnDate(bl) – BorrowDate(Borrow(bl)) 36,500)

(No copy may be returned before it was borrowed and after 100 years

since corresponding borrow date.)

Obviously, this constraint is best enforceable by the ActualReturnDate_

BeforeUpdate method of class Form_ BORROWS_LISTS:

'**********************************************************

Private Sub ActualReturnDate_BeforeUpdate(Cancel As

Integer)

'**********************************************************

'enforces constraint CBL7: no copy may be returned before

'it was borrowed or after 100 years since corresponding

'borrow date.

Dim bDate As Date

Dim days As Long

On Error GoTo err_point

If Me!ActualReturnDate <> Me!ActualReturnDate.OldValue Then

If Not IsNull(Me!ActualReturnDate) Then

bDate = DLookup("BorrowDate", "BORROWS", "x = " & _

Me!Borrow)

days = DateDiff("y", bDate, Me!ActualReturnDate)

If days < 0 Then

Cancel = True

MsgBox "Please specify a due return date greater " _

& "or equal to " & bDate & "!", vbCritical, _

"ActualReturnDate value less " _

& "than the corresponding BorrowDate one..."

Me!ActualReturnDate.Undo

ElseIf days > maxReturnDays Then

Cancel = True

MsgBox "Please specify a due return date less or " _

& "equal to " & bDate + maxReturnDays & "!", _

Page 454: Laborator Baze date

448

vbCritical, "ActualReturnDate value greater " _

& "than the corresponding " _

& "BorrowDate one + " & maxReturnDays & " days..."

Me!ActualReturnDate.Undo

End If

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_BORROWS_LISTS." _

& "ActualReturnDate_BeforeUpdate..."

Cancel = True

End Sub

5.1.8 ACC1

(xCO-AUTHORS) (Coauthor(x) FirstAuthor Book(x)) (First au-

thors should appear only once in the coauthors lists, on the corresponding

first position.)

Obviously, this constraint is best enforceable by the Co_author_Before-

Update method of class Form_CO_AUTHORS:

'****************************************************

Private Sub Co_author_BeforeUpdate(Cancel As Integer)

'****************************************************

'enforces constraint ACC1: First authors should appear only

'once in the co-authors lists, on the corresponding first

'position.

Dim v As Variant

On Error GoTo err_point

If Me![Co-author] <> Me![Co-author].OldValue Then

If IsNull(Me![Co-author]) Then

Cancel = True

MsgBox "Choose a non-null value for CoAuthor! ", _

vbCritical, "For each book CoAuthors are " _

& "compulsory..."

Me![Co-author].Undo

Else

v = DLookup("x", "Books", "x=" & Me!Book & _

" AND FirstAuthor=" & Me![Co-author])

If Not IsNull(v) Then

Cancel = True

MsgBox "This CoAuthor is already stored in BOOKS " _

& "as the " & "FirstAuthor!", vbCritical, _

"For any book each CoAuthor should appear " _

& " only once in the CoAuthors list..."

Page 455: Laborator Baze date

449

Me![Co-author].Undo

End If

End If

End If

Exit Sub

err_point: MsgBox Err.Source & " -> " & Err.Description, _

vbCritical, "Error in method Form_CO_AUTHORS. " _

& "Co_author_BeforeUpdate..."

Cancel = True

End Sub

5.2 Oracle solutions

6. Database Usage

6.1 Access Queries and Reports

6.1.1 Queries

6.1.1.1 Overdue borrows

Compute the set of all copies that should have been returned at least k

(natural) days ago, in the descending order of the overdue period and then

ascending on borrowers e-mail addresses, last, and first names, and,

finally, copies inventory numbers.

Solution:

Obviously, data on overdue copies is stored in table BORROWS_LISTS:

any copy having a null in the ActualReturnDate is not yet returned and by

subtracting from the current date the DueReturnDate one and comparing

the result to k the requested set is easily computable.

Of course that from the Copy foreign key the corresponding InvNo may

be obtained through a join with table COPIES and that from the Borrow

foreign key the corresponding e-mail, FName, and LName may be ob-

tained through a join with tables BORROWS and then with table PER-

SONS (on foreign key Subscriber).

Consequently, the needed query is the following:

SELECT DateDiff("d",[DueReturnDate],Date()) AS OverdueDays,

Page 456: Laborator Baze date

450

[e-mail], FName, LName, InvNo

FROM PERSONS INNER JOIN (COPIES INNER JOIN (BORROWS

INNER JOIN BORROWS_LISTS

ON BORROWS.x = BORROWS_LISTS.Borrow)

ON COPIES.x = BORROWS_LISTS.Copy)

ON PERSONS.x = BORROWS.Subscriber

WHERE DateDiff("d",[DueReturnDate],Date())>=[k]

AND ActualReturnDate Is Null

ORDER BY DateDiff("d",[DueReturnDate],Date()) DESC,

[e-mail], LName, FName, InvNo;

Figure A.1.19 shows the result of running this query for k = 0:

Figure A.1.19 Result of running query OverdueDays for k = 0

6.1.1.2 Worse borrowers

Compute the set of borrowers that were late with at least k (natural) days

in returning, at least for n (natural) borrows, and at least m copies per bor-

row, in descending order of the sum of number of late returning copies

per borrow, then of the number of borrows, and then ascending on e-mail

addresses, last, and first names.

Solution:

Obviously, all copies that are not yet returned and are overdue already

with at least k days (that is exactly the set computed by the above 6.1.1.1

problem) are satisfying the conditions of this problem. Consequently, this

set may be computed by the following query:

Page 457: Laborator Baze date

451

SELECT DateDiff("d",[DueReturnDate],Date()) AS OverdueDays,

Borrow, Copy

FROM BORROWS_LISTS

WHERE DateDiff("d",[DueReturnDate],Date())>=[k]

AND ActualReturnDate Is Null;

Moreover, copies that were returned (that is their ActualReturnDate is not

null) may have also been returned with at least k days later than due; this

subset is computable by the following query:

SELECT DateDiff("d",[DueReturnDate],Date()) AS OverdueDays,

Borrow, Copy

FROM BORROWS_LISTS

WHERE ActualReturnDate Is Not Null AND

ActualReturnDate >= DueReturnDate AND

DateDiff("d", DueReturnDate, ActualReturnDate)>=[k];

The union of these two subsets (save it as OverdueCopies) is the base set

for computing the final result:

SELECT DateDiff("d",[DueReturnDate],Date()) AS OverdueDays,

Borrow, Copy

FROM BORROWS_LISTS

WHERE DateDiff("d",[DueReturnDate],Date())>=[k]

AND ActualReturnDate Is Null

UNION

SELECT DateDiff("d",[DueReturnDate],Date()) AS OverdueDays,

Borrow, Copy

FROM BORROWS_LISTS

WHERE ActualReturnDate Is Not Null AND

ActualReturnDate >= DueReturnDate AND

DateDiff("d", DueReturnDate, ActualReturnDate)>=[k];

Next step is computable directly from the above computed set, by

grouping on borrows (save it as OverdueBorrowsAndCopyNo): borrows

containing at least m overdue copies; the corresponding query is the

following (where OverdueCopies is the name of the above query):

OverdueBorrowsAndCopyNo:

SELECT Borrow, Count(Copy) AS OverdueCopiesNo

FROM OverdueCopies

GROUP BY Borrow

HAVING Count(Copy)>=[m];

Page 458: Laborator Baze date

452

For computing the number of borrows per subscriber and selecting only

those subscribers that have had at least n borrows, the needed query is:

SELECT Subscriber, Count(x) AS BorrowsNo

FROM BORROWS

GROUP BY Subscriber

HAVING Count(x)>=[n];

For further selecting from this set only those borrows that are computed

by OverdueBorrowsAndCopyNo, a join with it is necessary:

SELECT Subscriber, Count(x) AS BorrowsNo,

Sum(OverdueCopiesNo) AS SumOfOverdueCopiesNo

FROM BORROWS INNER JOIN OverdueBorrowsAndCopyNo

ON BORROWS.x = OverdueBorrowsAndCopyNo.Borrow

GROUP BY Subscriber

HAVING Count(x)>=[n];

The final result is obtainable from this one (save it as WorseBorrowers0)

by replacing subscriber with corresponding e-mail address, first, and last

name (through a join with PERSONS) and by ordering it in the requested

order:

WorseBorrowers:

SELECT SumOfOverdueCopiesNo, BorrowsNo, [e-mail],

FName, LName

FROM WorseBorrowers0 INNER JOIN PERSONS

ON WorseBorrowers0.Subscriber = PERSONS.x

ORDER BY SumOfOverdueCopiesNo DESC, BorrowsNo DESC,

[e-mail], LName, FName;

Figure A.1.20 shows the result of running this query for k = 0, n = m = 1:

Figure A.1.20 Result of running query WorseBorrowers for k = 0, n = m =

1

Page 459: Laborator Baze date

453

6.1.2 Reports

Design and develop a report with the following data: subscribers e-mail

addresses, first, and last names, borrow, due, and actual return dates,

number of overdue days, publisher, editions year and title, volumes num-

ber, ISBN, and title, copies inventory number, volumes first books title,

and their first authors first and last names;

Solution:

The corresponding subjacent query is the following:

SELECT PERSONS.[e-mail], PERSONS.FName, PERSONS.LName,

BorrowDate, DueReturnDate, ActualReturnDate,

IIf(IsNull([ActualReturnDate]),

IIf(Date()>[DueReturnDate],

DateDiff("d",[DueReturnDate],Date()),0),

IIf([ActualReturnDate]>[DueReturnDate],

DateDiff("d",[DueReturnDate],[ActualReturnDate]),

0)) AS OverdueDays, PUBLISHERS.PubName AS

Publisher, EDITIONS.EYear, EDITIONS.ETitle,

VOLUMES.VNo, VOLUMES.ISBN, VOLUMES.VTitle,

COPIES.InvNo, BOOKS.BTitle, AUTHORS.FName AS

AuthFName, AUTHORS.LName AS AuthLName

FROM (((EDITIONS INNER JOIN PUBLISHERS

ON EDITIONS.Publisher = PUBLISHERS.x)

INNER JOIN VOLUMES

ON EDITIONS.x = VOLUMES.Edition) INNER JOIN

(PERSONS INNER JOIN (COPIES INNER JOIN (BORROWS

INNER JOIN BORROWS_LISTS

ON BORROWS.x = BORROWS_LISTS.Borrow)

ON COPIES.x = BORROWS_LISTS.Copy)

ON PERSONS.x = BORROWS.Subscriber)

ON VOLUMES.x = COPIES.Volume) INNER JOIN

((BOOKS INNER JOIN PERSONS AS AUTHORS

ON BOOKS.FirstAuthor = AUTHORS.x) INNER JOIN

VOLUMES_CONTENTS ON BOOKS.x = VOLUMES_CONTENTS.Book)

ON VOLUMES.x = VOLUMES_CONTENTS.Volume

WHERE BookPos = 1;

The needed groupings are the following, in this order:

- On e-mail (with FName and LName too), ascendingly

- On BorrowDate, ascendingly

- On Publisher, ascendingly

- On EYear (with ETitle too), ascendingly

Page 460: Laborator Baze date

454

Sums of overdue days are computed for both editions, publishers, bor-

rows, subscribers, and overall.

Figure A.1.21 shows the corresponding report design view; figures A.1.22

and A.1.23 present the first and last part, respectively, of the results ob-

tained by running this report in preview mode.

Figure A.1.21 Borrows by subscribers report design view

Page 461: Laborator Baze date

455

Figure A.1.22 Borrows by subscribers report preview start screen

Figure A.1.23 Borrows by subscribers report preview end screen

Page 462: Laborator Baze date

456

6.2 Oracle Views and Stored Procedures

7. Conclusion I have chosen the subuniverse of a Library, for which I designed and im-

plemented a db meant to be the foundation of a db software application

for the management of books, subscribers, and borrowing.

First, I have applied the algorithm for assisting the business analysis of

this subuniverse, with which I have obtained a corresponding informal

description of it, a set of entity-relationship diagrams, and a list of asso-

ciated restrictions.

After applying the algorithm for translating entity-relationship diagrams

and restriction lists into mathematic schemes, I have refined the obtained

mathematical scheme by applying the following algorithms:

assistance of sets, functions, and constraints design

assistance of keys discovery

analysis of (structural) entity-relationship diagram cycles.

Next, I’ve applied the algorithm for translating mathematical schemes in-

to relational ones and non-relational constraint lists and, finally, the ones

for translating relational schemes into MS Access 2010 dbs and for en-

forcing non-relational constraints in MS Access 2010,

Finally, I have populated the obtained db with plausible demo data, I have

designed and developed two parameterized queries and a report, which

would very much help librarians to extract the most interesting data and

information from this db, and I fully documented the whole process, from

the business analysis and design stages, up the implementation and usage

ones.

Page 463: Laborator Baze date

457

8. Bibliography 1. Mancas, C. & Dicu, A. I. Databases Lab Notes, 2014, Bucharest

Polytechnic University.

2. Mancas, C. Databases Lecture Notes, 2014, Bucharest Polytech-

nic University.

3. Mancas, C. Conceptual Data Modeling and Database Design:

Analysis, Implementation and Optimization. A Fully Algorithmic

Approach, 2014, Apple Academic Press.

4. Microsoft Corp. Access 2010 Help.

5. IT Services. Microsoft Access 2010 An Essential Guide (Level 1),

2011, The University of Reading (freely downloadable from

http://www.reading.ac.uk/web/files/its/AccessEssen2010.pdf).

6. IT Services. Microsoft Access 2010 An Intermediate Guide (Level

2), 2011, The University of Reading (freely downloadable from

http://www.reading.ac.uk/web/files/its/AccessInter2010.pdf).

7. McDonald, M. Access 2010: The Missing Manual, 2010, O’Reilly

Media (freely downloadable from http://it-ebooks.info/book/104/).

Page 464: Laborator Baze date

458

Appendix 2: VBA and SQL functions by categories

A2.1 String processing functions

A2.1.1 LCase

LCase(string_expr) returns the corresponding string where all uppercase

characters have been converted to lowercase or Null if string_expr eva-

luates to Null. Lowercase letters and nonletter characters remain un-

changed.

A2.1.2 UCase

UCase(string_expr) returns the corresponding string where all lowercase

characters have been converted to uppercase or Null if string_expr eva-

luates to Null. Uppercase letters and nonletter characters remain un-

changed.

A2.1.3 Len

Len(string_expr) returns a Long containing the number of characters in a

string or the number of bytes required to store a variable or Null if string_

expr evaluates to Null. If string_expr is a Variant, Len treats it the same

as a String and returns the number of characters it contains. If string_expr

is a user-defined type, Len returns the size as it will be written to the file;

beware that Len may not be able to determine the actual number of sto-

rage bytes required when used with variable-length strings in user-defined

data types.

Use the LenB function with byte data contained in a string, as in double-

byte character set (DBCS) languages. Instead of returning the number of

characters in a string, LenB returns the number of bytes used to represent

that string. With user-defined types, LenB returns the in-memory size,

including any padding between elements.

A2.1.4 Left and Right

Left(string_expr, length) and Right(string_expr, length) return a Variant

(String) containing length characters from the left/right side of the string

to which string_expr evaluates or Null if string_expr evaluates to Null.

length should be a Variant (Long) numeric expression indicating how ma-

ny characters to return: if it is negative or 0, a zero-length string ("") is re-

turned; if it is greater than or equal to the number of characters in

string_expr, the entire corresponding string is returned.

Page 465: Laborator Baze date

459

Use the LeftB and RightB functions with byte data contained in a string.

Instead of specifying the number of characters to return, length specifies

for them the number of desired bytes.

A2.1.5 LTrim, RTrim, and Trim

LTrim(string_expr), RTrim(string_expr), and Trim(string_expr) return a

Variant (String) containing a copy of a specified string without leading

spaces (LTrim), trailing spaces (RTrim), or both leading and trailing spa-

ces (Trim) or Null if string_expr evaluates to Null.

A2.1.6 StrReverse

StrReverse(string_expr) returns a string in which the character order of

the specified string is reversed; if string_expr is a zero-length string (""),

a zero-length string is returned; if string_expr evaluates to Null, an error

occurs.

A2.1.7 InStr

InStr([start, ]string_expr, substring_expr[, compare]) returns a Variant

(Long) specifying the position of the first occurrence of substring_expr

within string_expr. start is an optional, but required if compare is speci-

fied, numeric expression that sets the starting position for each search; if

omitted, search begins at the first character position; if start contains Null,

an error occurs. compare is optional and specifies the type of string com-

parison; if it is Null, an error occurs; if it is omitted, the Option Compare

setting determines the comparison type; compare has to have one of the

following valid LocaleID (LCID) constants to use locale-specific rules in

the comparison:

Constant Value Description

vbUseCompareOption -1 Performs comparison using the setting of

the Option Compare statement.

vbBinaryCompare 0 Performs binary comparison.

vbTextCompare 1 Performs textual comparison.

vbDatabaseCompare 2 MS Access only: performs comparison

based on information in your db.

Table A2T.1 The LCID constants

Page 466: Laborator Baze date

460

InStr returns the following values:

When: InStr returns:

string_expr is zero-length 0

string_expr is Null Null

substring_expr is zero-length start

substring_expr is Null Null

substring_expr is not found 0

substring_expr is found within string_expr Position where match is

found

start > sub-string_expr 0

A2.1.8 InStrB

InStrB([start, ]string_expr, substring_expr[, compare]) is almost identical

to InStr, except for the returning value which is not the character, but the

corresponding byte position.

A2.1.9 InstrRev

InstrRev(string_expr, substring_expr[, start] [, compare]) is almost iden-

tical to InStr, except for the returning values and search direction (“Rev”

coming from “Reverse”), which from right (end of string_ expr) to left

(begin of string_expr). Its return values are:

When: InStrRev returns:

string_expr is zero-length 0

string_expr is Null Null

sub-string_expr is zero-length start

substring_expr is Null Null

substring_expr is not found 0

substring_expr is found within

string_expr

Position where match is

found

start > Len(substring_expr) 0

Page 467: Laborator Baze date

461

A2.1.10 Replace

Replace(expression, find, replace[, start[, count[, compare]]]) returns a

string obtained from expression in which the specified find substring has

been replaced with the replace substring for count times, beginning at po-

sition start, and concluding at the end of expression.

Argument Description

expression Required. String expression containing substring to replace.

Find Required. Substring being searched for.

Replace Required. Replacement substring.

Start Optional. Position within expression where substring search

is to begin. If omitted, 1 is assumed.

Count Optional. Number of substring substitutions to perform. If o-

mitted, the default value is -1, which means make all possible

substitutions.

compare Optional. Numeric value indicating the kind of comparison

to use when evaluating substrings. See table A2T.1 for its va-

lues.

Replace returns the following values:

When: Replace returns:

expression is zero-length Zero-length string ("")

expression is Null An error.

find is zero-length Copy of expression.

replace is zero-length Copy of expression with all occurences of find re-

moved.

start > Len(expression) Zero-length string.

count is 0 Copy of expression.

Page 468: Laborator Baze date

462

A2.1.11 StrComp

StrComp(string1, string2[, compare]) returns a Variant (Integer) indicat-

ing the result of a string comparison.

Argument Description

string1 Required. Any valid string expression.

string2 Required. Any valid string expression.

compare Optional. Specifies the type of string comparison. If the com-

pare argument is Null, an error occurs. If compare is omitted,

the Option Compare setting determines the type of compari-

son. See table A2T.1 for its values.

StrComp has the following return values:

When: StrComp returns:

string1 < string2 -1

string1 = string2 0

string1 > string2 1

string1 or string2 is Null Null

A2.1.12 Space

Space(number) returns a Variant (String) consisting of number of spaces.

Useful for formatting output and clearing data in fixed-length strings.

A2.1.13 String

String(number, character) returns a Variant (String) containing character

repeated number of times; if char(character) > 255, String converts cha-

racter to a valid ASCII character code using the formula character Mod

256.

Page 469: Laborator Baze date

463

Argument Description

Number Required; Long. Length of the returned string. If number eva-

luates to Null, Null is returned.

character Required; Variant. Character code specifying the character or

string expression whose first character is used to build the re-

turn string. If character evaluates to Null, Null is returned.

A2.1.14 StrConv

StrConv(string_expr, conversion, LCID) returns a Variant (String) con-

verted as specified.

Argument Description

string_expr Required. String expression to be converted.

conversion Required. Integer. The sum of values specifying the type of

conversion to perform.

LCID Optional. The LocaleID, if different than the system’s one.

(The system LocaleID is the default.)

Note that the valid constants for conversion (see following table) may be

combined (for example, vbUpperCase + vbWide), except when they are

mutually exclusive (for example, vbUnicode + vbFromUnicode). Con-

stants vbWide, vbNarrow, vbKatakana, and vbHiragana cause run-time

errors when used in locales where they do not apply.

The following are valid word separators for proper casing: Null (Chr$(0)),

horizontal tab (Chr$(9)), linefeed (Chr$(10)), vertical tab (Chr$(11)),

form feed (Chr$(12)), carriage return (Chr$(13)), space (SBCS)

(Chr$(32)). The actual value for a space varies by country/region for

DBCS.

When converting from a Byte array in ANSI format to a string, use the

StrConv function. When converting from such an array in Unicode for-

mat, use an assignment statement.

Page 470: Laborator Baze date

464

Valid conversion argument values are the following:

Constant Value Description

vbUpperCase 1 Converts the string to uppercase characters.

vbLowerCase 2 Converts the string to lowercase characters.

vbProperCase 3 Converts the first letter of every word in string

to uppercase.

vbWide* 4* Converts narrow (single-byte) characters in

string to wide (double-byte) characters.

vbNarrow* 8* Converts wide (double-byte) characters in

string to narrow (single-byte) characters.

vbKatakana** 16** Converts Hiragana characters in string to Kata-

kana characters.

vbHiragana** 32** Converts Katakana characters in string to Hira-

gana characters.

vbUnicode 64 Converts the string to Unicode using the default

code page of the system. (Not available on the

Macintosh.)

vbFromUnicode 128 Converts the string from Unicode to the default

code page of the system. (Not available on the

Macintosh.)

*Applies to Far East locales. **Applies to Japan only.

A2.1.15 Join

Join(sourcearray[, delimiter]) returns a string created by concatenating all

substrings contained in an array. It is the dual of Split.

Argument Description

sourcearray Required. One-dimensional array containing substrings to

be concatenated.

delimiter Optional. String character used to separate the substrings in

the returned string. If omitted, the space character (" ") is

used. If delimiter is a zero-length string (""), all items in the

list are concatenated with no delimiters.

Page 471: Laborator Baze date

465

A2.1.16 Split

Split(expression[, delimiter[, limit[, compare]]]) returns a zero-based,

one-dimensional array containing a specified number of substrings. It is

the dual of Join.

Argument Description

expression Required. String expression containing substrings and deli-

miters. If expression is a zero-length string(""), Split returns

an empty array, that is, an array with no elements and no da-

ta.

delimiter Optional. String character used to identify substring limits. If

omitted, the space character (" ") is assumed to be the delimi-

ter. If delimiter is a zero-length string, a single-element array

containing the entire expression string is returned.

limit Optional. Number of substrings to be returned; -1 indicates

that all substrings are returned.

compare Optional. Numeric value indicating the kind of comparison

to use when evaluating substrings. See table A2T.1 for its va-

lues.

A2.2 Data types associated functions

A2.2.1 IsNull

IsNull(expression) returns True if expression is Null; otherwise, returns

False; if expression consists of more than one variable, Null in any consti-

tuent variable causes True to be returned for the entire expression. The re-

quired expression argument is a Variant containing a numeric or string

expression.

Note that Null is not the same either as Empty, which indicates that a va-

riable has not yet been initialized, or as a zero-length string (""), which is

sometimes referred to as a null string.

Also note that expressions that you might expect to evaluate to True un-

der some circumstances, such as If Var = Null and If Var <>

Null, are always False, because any expression containing a Null is it-

self Null and, therefore, False.

Page 472: Laborator Baze date

466

A2.2.2 IsEmpty

IsEmpty(expression) returns True if expression is uninitialized, or is ex-

plicitly set to Empty; otherwise, it returns False; False is always returned

if expression contains more than one variable.The required expression ar-

gument is a Variant containing a numeric or string expression that should

evaluate to a single variable name.

A2.2.3 TypeName

TypeName(varname) returns a String that provides information about var-

name. The required varname argument is a Variant that may evaluate to

any variable name, except for variables of user-defined types.

Returned String Variable

object type An object whose type is objecttype

Byte Byte value

Integer Integer

Long Long integer

Single Single-precision floating-point number

Double Double-precision floating-point number

Currency Currency value

Decimal Decimal value

Date Date value

String String

Boolean Boolean value

Error Error value

Empty Uninitialized

Null No valid data

Object An object

Unknown An object whose type is unknown

Nothing Object variable that doesn't refer to an object

DataType() Array of DataType (including Variant) elements

Page 473: Laborator Baze date

467

A2.2.4 VarType

VarType(varname) returns an Integer indicating the subtype of varname.

The required varname argument is a Variant that may evaluate to any va-

riable name, except for variables of user-defined types. Returned values

are the following:

Constant Value Description

vbEmpty 0 Empty (uninitialized)

vbNull 1 Null (no valid data)

vbInteger 2 Integer

vbLong 3 Long integer

vbSingle 4 Single-precision floating-point number

vbDouble 5 Double-precision floating-point number

vbCurrency 6 Currency value

vbDate 7 Date value

vbString 8 String

vbObject 9 Object

vbError 10 Error value

vbBoolean 11 Boolean value

vbVariant 12 Variant (used only with arrays of

variants)

vbDataObject 13 A data access object

vbDecimal 14 Decimal value

vbByte 17 Byte value

vbLongLong 20 LongLong integer (Valid on 64-bit

platforms only)

vbUserDefinedType 36 Variants that contain user-defined types

vbArray 8192 Array

Page 474: Laborator Baze date

468

Note that vbArray is never returned by itself: it is always added to some

other value to indicate an array of a particular type; vbVariant is only re-

turned in conjunction with vbArray to indicate that varname is an array of

type Variant (for example, the value returned for an array of integers is

vbInteger + vbArray = 8194); if an object has a default property, the type

of the object's default property is returned.

A2.2.5 IsDate

IsDate(expression) returns True if expression evaluates to a valid date;

otherwise, it returns False. The required expression argument is a Variant

containing a date expression or string expression recognizable as a date or

time.59

A2.2.6 IsNumeric

IsNumeric(expression) returns True if expression is recognized as a num-

ber; otherwise, it returns False (including when expression is a date one).

The required expression argument is a Variant containing a numeric or

string expression.

A2.2.7 IsArray

IsArray(varname) returns True if varname evaluates to an array; other-

wise, it returns False.

A2.2.8 IsMissing

IsMissing(argname) returns a Boolean value indicating whether the optio-

nal Variant argument argname has been passed to a procedure: True if no

value has been passed for argname or, otherwise, False. The required

argname argument contains the name of an optional Variant procedure

argument.

If IsMissing is used on a ParamArray argument, it always returns False.

To detect an empty ParamArray, test to see if the array's upper bound is

less than its lower bound.

IsMissing does not work on simple data types (such as Integer or Double)

because, unlike Variants, they don't have a provision for a "missing" flag

bit. Because of this, the syntax for typed optional arguments allows you to

specify a default value. If the argument is omitted when the procedure is

called, then the argument will have this default value.

59

Note that in MS Windows, the range of valid dates is January 1, 100 A.D. through De-

cember 31, 9999 A.D.; this range vary among operating systems.

Page 475: Laborator Baze date

469

A2.2.9 IsObject

IsObject(identifier) returns a Boolean value indicating whether identifier

represents an object variable: True if identifier is a variable declared with

Object type or any valid class type, or if it is a Variant of VarType

vbObject, or a user-defined object; returns True even if the variable has

been set to Nothing; otherwise, it returns False. The required identifier ar-

gument is a variable name. Useful only in determining whether a Variant

is of VarType vbObject; this could occur if the Variant actually references

(or once referenced) an object, or if it contains Nothing. Always use error

trapping to be sure that an object reference is valid.

A2.2.10 IsError

IsError(expression) returns True if expression evaluates to an error;

otherwise, it returns False. The required expression argument can be any

valid expression.

Note that error values are created by converting real numbers to error

values using the CVErr function; IsError is used to determine if a nume-

ric expression represents an error.

A2.3 Date functions

A2.3.1 Date and Date$

Date() and Date$() return a Variant (Date) or a string, respectively, con-

taining the current system date. To set the system date, use the Date state-

ment; if you use Date and the calendar is Gregorian, Date$ behavior is

unchanged by the Calendar property setting.60

A2.3.2 Time and Time$

Time() and Time$() return a Variant (Date) or a string, respectively, con-

taining the current system time. (To set the system date, use the Time

statement.)

A2.3.3 Now

Now() returns a Variant (Date) containing the current system date and

time.

60

If the calendar is Hijri, Date$ returns a 10-character string of the form mm-dd-yyyy,

where mm (01-12), dd (01-30) and yyyy (1400-1523) are the Hijri month, day and year.

The equivalent Gregorian range is Jan 1, 1980 through Dec 31, 2099.

Page 476: Laborator Baze date

470

A2.3.4 DatePart

DatePart(interval, date[,firstdayofweek[, firstweekofyear]]) returns a Va-

riant (Integer) containing the specified part of date.

Argument Description

interval Required. String expression that is the interval of time

you want to return.

date Required. Variant (Date) value that you want to evalu-

ate.

firstdayofweek Optional. A constant that specifies the first day of the

week. If not specified, Sunday is assumed.

firstweekofyear Optional. A constant that specifies the first week of the

year. If not specified, the first week is assumed to be the

week in which January 1 occurs.

The interval argument has the following valid values:

Value Description

yyyy Year

q Quarter

m Month

y Day of year

d Day

w Weekday

ww Week

h Hour

n Minute

s Second

Table A2T.2 Date interval codes

Page 477: Laborator Baze date

471

The firstdayofweek argument has the following valid values:

Constant Value Description

vbUseSystem 0 Use the NLS API

setting.

vbSunday 1 Sunday (default)

vbMonday 2 Monday

vbTuesday 3 Tuesday

vbWednesday 4 Wednesday

vbThursday 5 Thursday

vbFriday 6 Friday

vbSaturday 7 Saturday

Table A2T.3 Weekday constants

The firstweekofyear argument has the following valid values:

Constant Value Description

vbUseSystem 0 Use the NLS API setting.

vbFirstJan1 1 Start with week in which January 1 occurs (de-

fault).

vbFirstFourDays 2 Start with the first week that has at least four

days in the new year.

vbFirstFullWeek 3 Start with first full week of the year.

Table A2T.4 First week of year constants

The firstdayofweek argument affects calculations that use the "w" and

"ww" interval symbols.

If date is a date literal, the specified year becomes a permanent part of

that date. However, if date is enclosed in double quotation marks (" "),

Page 478: Laborator Baze date

472

and you omit the year, the current year is inserted in your code each time

the date expression is evaluated. This makes it possible to write code that

can be used in different years.

If the Calendar property setting is Gregorian, date must be Gregorian.61

The returned date part is in the time period units of the current Arabic

calendar.62

A2.3.5 DateSerial

DateSerial(year, month, day) returns a Variant (Date) for the specified

year, month, and day.

Argument Description

year Required; Integer. Natural between 100 and 9999 or a nume-

ric expression that evaluates to such a natural.

month Required; Integer. Any numeric expression.

day Required; Integer. Any numeric expression.

To specify a date, such as December 31, 1991, the range of numbers for

each DateSerial argument should be in the accepted range for the unit;

that is, 1-31 for days and 1-12 for months.63

However, you can also speci-

fy relative dates for each argument using any numeric expression that re-

presents some number of days, months, or years before or after a certain

date.

When any argument exceeds its accepted range, it increments to the next

larger unit, as appropriate. For example, if you specify 35 days, it is eva-

luated as one month and some number of days, depending on where in the

year it is applied. If any argument is outside the range -32,768 to 32,767,

an error occurs. If the date specified by the three arguments falls outside

the acceptable range of dates, an error occurs too. 61

If the calendar is Hijri, the supplied date must be Hijri. 62

For example, if the current calendar is Hijri and the date part to be returned is the year,

the year value is a Hijri year. 63

Under Windows 98 or 2000, two digit years for the year argument are interpreted

based on user-defined machine settings. The default settings are: values between 0 and

29 are interpreted as the years 2000-2029; default values between 30 and 99 are interpre-

ted as the years 1930-1999; for all other year arguments, use a four-digit year (for exam-

ple, 1800). To be sure that the function returns the proper value, always use a four-digit

year.

Page 479: Laborator Baze date

473

For year, month, and day, if the Calendar property setting is Gregorian,

the supplied value is assumed to be Gregorian (also see footnote 60).The

returned date part is in the time period units of the current VBA calendar

(also see footnote 61). For the argument year, values between 0 and 99

are interpreted as the years 1400-1499. For all other year values, use the

complete four-digit year (for example, 1520).

A2.3.6 TimeSerial

TimeSerial(hour, minute, second) returns a Variant (Date) containing the

time for hour, minute, and second.

Argument Description

hour Required; Variant (Integer). Number between 0 (12:00 A.M.)

and 23 (11:00 P.M.), inclusive, or a numeric expression.

minute Required; Variant (Integer). Any numeric expression.

second Required; Variant (Integer). Any numeric expression.

To specify a time, such as 11:59:59, the range of numbers for each

TimeSerial argument should be in the normal range for the unit: that is, 0-

23 for hours and 0-59 for minutes and seconds. However, you can also

specify relative times for each argument using any numeric expression

that represents some number of hours, minutes, or seconds before or after

a certain time.64

When any argument exceeds its normal range, it increments to the next

larger unit, as appropriate. For example, if you specify 75 minutes, it is

evaluated as one hour and 15 minutes. If any argument is outside the

range -32,768 to 32,767, an error occurs. If the time specified by the three

arguments causes the date to fall outside the acceptable range of dates, an

error occurs.

A2.3.7 DateValue

The required date argument of DateValue(date) is normally a string ex-

pression representing a date from January 1, 100 through December 31,

9999. However, date can also be any expression that can represent a date,

a time, or both a date and time, in that range.

64

For example, TimeSerial(12 - 6, -15, 0) returns 15 minutes before (-15)

six hours before noon (12 - 6), which is 5:45:00 A.M.

Page 480: Laborator Baze date

474

If date includes only numbers separated by valid date separators, DateVa-

lue recognizes the order for month, day, and year according to the Short

Date format you specified for your system. DateValue also recognizes un-

ambiguous dates that contain month names, either in long or abbreviated

form. For example, in addition to recognizing 12/30/1991 and 12/30/ 91,

DateValue also recognizes December 30, 1991 and Dec 30, 1991.

If the year part of date is omitted, DateValue uses the current year from

your computer's system date. If the date argument includes time informa-

tion, DateValue doesn't return it. However, if date includes invalid time

information (such as "89:98"), an error occurs. If the Calendar property

setting is Gregorian, date must be Gregorian (also see footnote 60).65

A2.3.8 TimeValue

TimeValue(time) returns a Variant (Date) containing the corresponding

time; if time contains Null, Null is returned; if time contains date informa-

tion, TimeValue doesn't return it; if time includes invalid date information,

an error occurs. The required time argument should be a string expression

representing a time from 0:00:00 (12:00:00 A.M.) to 23:59:59 (11:59:59

P.M.); time can also be any expression that represents a time in that range.

You can enter valid times using a 12-hour or 24-hour clock. For example,

"2:24PM" and "14:24" are both valid time values.

A2.3.9 DateAdd

DateAdd(interval, number, date) returns a Variant (Date) containing a

date to which a specified time interval has been added.

Argument Description

interval Required. String expression that is the interval of time you

want to add. See table A2T.2 for its valid values.

number Required. Numeric expression that is the number of intervals

you want to add. It can be positive (to get dates in the future)

or negative (to get dates in the past).

Date Required. Variant (Date) or literal representing date to which

the interval is added.

65

If the supplied date is Hijri, date is a String representing a date from 1/1/100

(Gregorian Aug 2, 718) through 4/3/9666 (Gregorian Dec 31, 9999).

Page 481: Laborator Baze date

475

To add days to date, you can use Day of Year ("y"), Day ("d"), or Week-

day ("w"). When you use the "w" interval (which includes all the days of

the week, Sunday through Saturday) to add days to a date, the DateAdd

function adds the total number of days that you specified to the date,

instead of adding just the number of workdays (Monday through Friday)

to the date, as you might expect.

The DateAdd function won't return an invalid date. The following exam-

ple adds one month to January 31: DateAdd("m", 1, "31-Jan-

95"). In this case, DateAdd returns 28-Feb-95, not 31-Feb-95. If date is

31-Jan-96, it returns 29-Feb-96, because 1996 is a leap year.

If the calculated date would precede the year 100 (that is, you subtract

more years than are in date), an error occurs. If number isn't a Long value,

it is rounded to the nearest whole number before being evaluated.

The format of the return value for DateAdd is determined by Control Pa-

nel settings, not by the format that is passed in date argument. If the Ca-

lendar property setting is Gregorian, the supplied date must be Gregorian

(also see footnote 60). If month values are names, the name must be con-

sistent with the current Calendar property setting. To minimize the possi-

bility of month names conflicting with the current Calendar property set-

ting, enter numeric month values (Short Date format).

A2.3.10 DateDiff

DateDiff(interval, date1, date2[, firstdayofweek[, firstweekofyear]]) re-

turns a Variant (Long) specifying the number of time intervals between

date1 and date2.

Argument Description

interval Required. String expression that is the interval of time

you use to calculate the difference between date1 and

date2. See table A2T.1 for its valid values.

date1, date2 Required; Variant (Date). Two dates you want to use in

the calculation.

firstdayofweek Optional. A constant that specifies the first day of the

week. If not specified, Sunday is assumed. See table

A2T.3 for its valid values.

Page 482: Laborator Baze date

476

firstweekofyear Optional. A constant that specifies the first week of the

year. If not specified, the first week is assumed to be the

week in which January 1 occurs. See table A2T.4 for its

valid values.

To calculate the number of days between date1 and date2, use either Day

of year ("y") or Day ("d"). When interval is Weekday ("w"), DateDiff re-

turns the number of weeks between the two dates. If date1 falls on a Mon-

day, DateDiff counts the number of Mondays until date2, counting date2

but not date1. If interval is Week ("ww"), however, DateDiff returns the

number of calendar weeks between the two dates, counting the number of

Sundays between date1 and date2; it counts date2 if it falls on a Sunday,

but it doesn't count date1, even if it does fall on a Sunday.

If date1 refers to a later point in time than date2, DateDiff returns the cor-

responding negative number.

The firstdayofweek argument affects calculations that use the "w" and

"ww" interval symbols.

If date1 or date2 is a date literal, the specified year becomes a permanent

part of that date. However, if date1 or date2 is enclosed in double quota-

tion marks (" ") and you omit the year, the current year is inserted in your

code each time the date1 or date2 expressions are evaluated. This makes

it possible to write code that can be used in different years.

When comparing December 31 to January 1 of the immediately succeed-

ing year, DateDiff for Year ("yyyy") returns 1 even though only a day has

elapsed.

If the Calendar property setting is Gregorian, date1 and date2 must be

Gregorian (also see footnote 60).

A2.3.11 Day

Day(date) returns a Variant (Integer) specifying the natural between 1

and 31 that corresponds to the day of the month of date. The required date

argument is any Variant, numeric expression, string expression, or any

combination, that can be evaluated to a date. If date contains Null, Null is

returned. If the Calendar property setting is Gregorian, the returned inte-

ger represents the corresponding Gregorian day (also see footnote 60).

Page 483: Laborator Baze date

477

A2.3.12 Weekday

Weekday(date, [firstdayofweek]) returns a Variant (Integer) containing a

natural corresponding to the day of the week of date (for actual returned

values see constants vbSunday to vbSaturday in table A2T.3).

Argument Description

Date Required. Variant, numeric expression, string expression,

or any combination that can be evaluated to a date. If

date contains Null, Null is returned.

firstdayofweek Optional. A constant that specifies the first day of the

week. If not specified, vbSunday is assumed. See table

A2T.3 for its valid values.

If the Calendar property setting is Gregorian, the returned integer repre-

sents the corresponding Gregorian day (also see footnotes 60 and 64).

A2.3.13 WeekdayName

WeekdayName(weekday, abbreviate, firstdayofweek) returns a string indi-

cating the specified day of the week.

Argument Description

weekday Required. The numeric designation for the day of the

week. Numeric value of each day depends on setting of

the firstdayofweek setting.

abbreviate Optional. Boolean value that indicates if the weekday

name is to be abbreviated. If omitted, the default is False,

which means that the weekday name is not abbreviated.

firstdayofweek Optional. Numeric value indicating the first day of the

week. See table A2T.3 for its valid values.

A2.3.14 Month

Month(date) returns a Variant (Integer) specifying a natural between 1

and 12, representing the month of the year of date. The required date ar-

gument is any Variant, numeric expression, string expression, or any

combination that can be evaluated to a date. If date contains Null, Null is

returned. If the Calendar property setting is Gregorian, the returned inte-

Page 484: Laborator Baze date

478

ger represents the corresponding Gregorian day of the week (also see

footnotes 60 and 64).

A2.3.15 MonthName

MonthName(month[, abbreviate]) returns a string indicating the specified

month.

Argument Description

month Required. The numeric designation of the month. For exam-

ple, January is 1, February is 2, and so on.

abbreviate Optional. Boolean value that indicates if the month name is

to be abbreviated. If omitted, the default is False, which

means that the month name is not abbreviated.

A2.3.16 Year

Year(date) returns a Variant (Integer) containing a natural representing

the year of date. The required date argument is any Variant, numeric ex-

pression, string expression, or any combination that can be evaluated to a

date. If date contains Null, Null is returned. If the Calendar property set-

ting is Gregorian, the returned integer represents the corresponding Gre-

gorian year (also see footnotes 60 and 64).

A2.3.17 Hour

Hour(time) returns a Variant (Integer) specifying a natural between 0 and

23 representing the hour of time. The required time argument is any Vari-

ant, numeric expression, string expression, or any combination that can be

evaluated to a time value. If time contains Null, Null is returned.

A2.3.18 Minute

Minute(time) returns a Variant (Integer) specifying a natural between 0

and 59 representing the minute of time. The required time argument is any

Variant, numeric expression, string expression, or any combination that

can be evaluated to a time value. If time contains Null, Null is returned.

A2.3.19 Second

Second(time) returns a Variant (Integer) specifying a natural between 0

and 59 representing the second of time. The required time argument is any

Variant, numeric expression, string expression, or any combination that

can be evaluated to a time value. If time contains Null, Null is returned.

Page 485: Laborator Baze date

479

A2.4 Numeric functions

A2.4.1 Abs

Abs(number) returns a value of the same type as number specifying the

absolute value66

of number. The required number argument can be any

valid numeric expression. If number contains Null, Null is returned; if it is

an uninitialized variable, zero is returned.

A2.4.2 Int and Fix

Int(number) and Fix(number) return the integer portion of number (re-

move its fractional part). The required number argument is a Double or

any valid numeric expression. If number contains Null, Null is returned.

The difference between Int and Fix is that if number is negative, Int re-

turns the first negative integer less than or equal to number, whereas Fix

returns the first negative integer greater than or equal to number.67

Fix(number) = Sgn(number) * Int(Abs(number)).

A2.4.3 Partition

Partition(number, start, stop, interval) returns a Variant (String) indicat-

ing where number occurs within a calculated series of ranges. If any of

the arguments is Null, Partition returns a Null.

Argument Description

number Required. Integer to be evaluated against the ranges.

start Required. Natural that is the start of the overall range of

numbers.

stop Required. Natural that is the end of the overall range of

numbers. stop > start.

The following table shows how the ranges are determined using three sets

of start, stop, and interval values. The First Range and Last Range co-

lumns show what Partition returns. Ranges are represented by lowerva-

lue:uppervalue, where the low end (lowervalue) of the range is separated

from the high end (uppervalue) of the range with a colon (:).

66

The absolute value of a number is its unsigned magnitude; for example, both ABS(-1)

and ABS(1) return 1. 67

For example, Int converts -8.4 to -9, whereas Fix converts it to -8.

Page 486: Laborator Baze date

480

start stop interval Before

First

First

Range

Last Range After

Last

0 99 5 " :-1" " 0: 4" " 95: 99" " 100: "

20 199 10 " : 19" " 20: 29" " 190: 199" " 200: "

100 1010 20 " : 99" " 100:

119"

" 1000:

1010"

" 1011: "

In the above table, the third line shows the result when start and stop de-

fine a set of numbers that can't be evenly divided by interval. The last

range extends to stop (11 numbers) even though interval is 20.

If necessary, Partition returns a range with enough leading spaces so that

there are the same number of characters to the left and right of the colon

as there are characters in stop, plus one. This ensures that if you use Par-

tition with other numbers, the resulting text will be handled properly dur-

ing any subsequent sort operation.

If interval is 1, the range is number:number, regardless of the start and

stop values. For example, if interval is 1, number is 100 and stop is 1000,

Partition returns " 100: 100".

A2.4.4 Round

Round(expression [,numdecimalplaces]) returns a number rounded to a

specified number of decimal places.

Argument Description

expression Required. Numeric expression being rounded.

numdecimalplaces Optional. Number indicating how many places to the

right of the decimal are included in the rounding. If

omitted, integers are returned.

A2.4.5 Sgn

Sgn(number) returns a Variant (Integer) indicating the sign of number.

The required number argument can be any valid numeric expression.

Page 487: Laborator Baze date

481

When number is Sgn returns

Greater than

zero

1

Equal to zero 0

Less than zero -1

A2.4.6 Rnd

Rnd[(number)] returns a Single containing a random number less than 1

and greater than or equal to zero. The optional number argument is a Sin-

gle or any valid numeric expression. The value of number determines

how random numbers are generated: for any given initial seed, the same

number sequence is generated, because each successive call to Rnd uses

the previous number as a seed for the next number in the sequence.

When number is Rnd generates

Less than zero The same number every time, using number as the

seed.

Greater than

zero

The next random number in the sequence.

Equal to zero The most recently generated number.

Not supplied The next random number in the sequence.

Before calling Rnd, use the Randomize statement without argument value

to initialize the random-number generator with a seed based on the system

timer. To produce random integers in a given range, use the formula

Int((upperbound - lowerbound + 1) * Rnd + lowerbound),

where upperbound is the highest number in the range, and lowerbound is

the lowest one.

To repeat sequences of random numbers, call Rnd with a negative argu-

ment value immediately before using Randomize with a numeric argu-

ment. Using Randomize with the same value for number does not repeat

the previous sequence.

Page 488: Laborator Baze date

482

A2.4.7 Trigonometric and other algebraic functions

Function Description

Sqr Square root

Exp Exponential

Log Logarithm (natural)

Atn Arctangent

Cos Cosine

Sin Sine

Tan Tangent

Note that, for all of them too, when their arguments contain Null, Null is

returned.

A2.4.8 Derived Math Functions

The following is a list of nonintrinsic math functions that can be derived

from the intrinsic ones:

Function Derived equivalents

Secant Sec(X) = 1 / Cos(X)

Cosecant Cosec(X) = 1 / Sin(X)

Cotangent Cotan(X) = 1 / Tan(X)

Inverse

Sine

Arcsin(X) = Atn(X / Sqr(-X * X + 1))

Inverse

Cosine

Arccos(X) = Atn(-X / Sqr(-X * X + 1)) + 2 * Atn(1)

Inverse

Secant

Arcsec(X) = Atn(X / Sqr(X * X - 1)) + Sgn((X) - 1) * (2 *

Atn(1))

Inverse

Cosecant

Arccosec(X) = Atn(X / Sqr(X * X - 1)) + (Sgn(X) - 1) * (2 *

Atn(1))

Inverse

Cotangent

Arccotan(X) = Atn(X) + 2 * Atn(1)

Page 489: Laborator Baze date

483

Hyperbolic

Sine

HSin(X) = (Exp(X) - Exp(-X)) / 2

Hyperbolic

Cosine

HCos(X) = (Exp(X) + Exp(-X)) / 2

Hyperbolic

Tangent

HTan(X) = (Exp(X) - Exp(-X)) / (Exp(X) + Exp(-X))

Hyperbolic

Secant

HSec(X) = 2 / (Exp(X) + Exp(-X))

Hyperbolic

Cosecant

HCosec(X) = 2 / (Exp(X) - Exp(-X))

Hyperbolic

Cotangent

HCotan(X) = (Exp(X) + Exp(-X)) / (Exp(X) - Exp(-X))

Inverse

Hyperbolic

Sine

HArcsin(X) = Log(X + Sqr(X * X + 1))

Inverse

Hyperbolic

Cosine

HArccos(X) = Log(X + Sqr(X * X - 1))

Inverse

Hyperbolic

Tangent

HArctan(X) = Log((1 + X) / (1 - X)) / 2

Inverse

Hyperbolic

Secant

HArcsec(X) = Log((Sqr(-X * X + 1) + 1) / X)

Inverse

Hyperbolic

Cosecant

HArccosec(X) = Log((Sgn(X) * Sqr(X * X + 1) + 1) / X)

Inverse

Hyperbolic

Cotangent

HArccotan(X) = Log((X + 1) / (X - 1)) / 2

Logarithm

to base N

LogN(X) = Log(X) / Log(N)

Page 490: Laborator Baze date

484

A2.5 Conversion functions Each such function coerces an expression to the corresponding data type,

takes a required string or numeric expression argument, and returns the

corresponding converted value, whenever corresponding conversion is

possible. If the expression passed to the function is outside the range of

the data type being converted to, an error occurs.

Note that conversion functions must be used to explicitly assign

LongLong (including LongPtr on 64-bit platforms) to smaller integral

types. Implicit conversions of LongLong to smaller integrals are not

allowed.

In general, you can document your code using the data-type conversion

functions to show that the result of some operation should be expressed as

a particular data type rather than the default data type. For example, use

CCur to force currency arithmetic in cases where single-precision,

double-precision, or integer arithmetic normally would occur.

Function Return

Type

Range for expression argument

CBool Boolean Any valid string or numeric expression.

CByte Byte 0 to 255

CCur Currency -922,337,203,685,477.5808 to

922,337,203,685,477.5807

CDate Date Any valid date expression.

CDbl Double -1.79769313486231E308 to -

4.94065645841247E-324 for negative values;

4.94065645841247E-324 to

1.79769313486232E308 for positive values

CDec Decimal +/-79,228,162,514,264,337,593,543,950,335 for

zero-scaled numbers, that is numbers with no

decimal places. For numbers with 28 decimal

places, the range is +/-

7.9228162514264337593543950335. The

smallest possible non-zero number is

0.0000000000000000000000000001.

Page 491: Laborator Baze date

485

CInt Integer -32,768 to 32,767; fractions are rounded.

CLng Long -2,147,483,648 to 2,147,483,647; fractions are

rounded.

CLngLng LongLong -9,223,372,036,854,775,808 to

9,223,372,036,854,775,807; fractions are

rounded. (Valid on 64-bit platforms only.)

CLngPtr LongPtr -2,147,483,648 to 2,147,483,647 on 32-bit

systems, -9,223,372,036,854,775,808 to

9,223,372,036,854,775,807 on 64-bit systems;

fractions are rounded for 32-bit and 64-bit

systems.

CSng Single -3.402823E38 to -1.401298E-45 for negative

values; 1.401298E-45 to 3.402823E38 for

positive values.

CStr String Returns for CStr depend on the expression

argument.

CVar Variant Same range as Double for numerics. Same range

as String for non-numerics.

You should use the data-type conversion functions instead of Val to

provide internationally aware conversions from one data type to another.

For example, when you use CCur, different decimal separators, different

thousand separators, and various currency options are properly recognized

depending on the locale setting of your computer.

When the fractional part is exactly 0.5, CInt and CLng always round it to

the nearest even number.68

CInt and CLng differ from the Fix and Int

functions, which truncate, rather than round, the fractional part of a

number. Also, Fix and Int always return a value of the same type as is

passed in.

Use the IsDate function to determine if date can be converted to a date or

time. CDate recognizes date literals and time literals as well as some

numbers that fall within the range of acceptable dates. When converting a

number to a date, the whole number portion is converted to a date. Any

68

For example, 0.5 rounds to 0 and 1.5 rounds to 2.

Page 492: Laborator Baze date

486

fractional part of the number is converted to a time of day, starting at

midnight.

CDate recognizes date formats according to the locale setting of your sys-

tem. The correct order of day, month, and year may not be determined if

it is provided in a format other than one of the recognized date settings. In

addition, a long date format is not recognized if it also contains the day-

of-the-week string.69

CDec does not return a discrete data type; instead, it always returns a

Variant whose value has been converted to a Decimal subtype.

A2.5.1 Str

Str(number) returns a Variant (String) representation of number. The

required number argument is a Long containing any valid numeric

expression. Str recognizes only the period (.) as a valid decimal separator.

When different decimal separators may be used (for example, in interna-

tional applications), use CStr to convert a number to a string.

When numbers are converted to strings, a leading space is always re-

served for the sign of number. If number is positive, the returned string

contains a leading space and the plus sign is implied.

Use the Format function to convert numeric values you want formatted as

dates, times, or currency or in other user-defined formats. Unlike Str, the

Format function doesn't include a leading space for the sign of number.

A2.5.2 Val

Val(string) returns the numbers contained in string as a numeric value of

appropriate type. The required string argument is any valid string expres-

sion. Val stops reading the string at the first character it can't recognize as

part of a number.70

Symbols and characters that are often considered parts

of numeric values, such as dollar signs and commas, are not recognized.

However, the function recognizes the radix prefixes &O (for octal) and

69

A CVDate function is also provided for compatibility with previous versions of VB.

The syntax of the CVDate function is identical to that of CDate; however, CVDate

returns a Variant whose subtype is Date instead of an actual Date type. Since there is

now an intrinsic Date type, there is no further need for CVDate. The same effect can be

achieved by converting an expression to a Date, and then assigning it to a Variant. This

technique is consistent with the conversion of all other intrinsic types to their equivalent

Variant subtypes. 70

For example, Val(" 1615 198th Street N.E.") = 1615198

Page 493: Laborator Baze date

487

&H (for hexadecimal)71

. Blanks, tabs, and linefeed characters are stripped

from the argument. Val recognizes only the period (.) as a valid decimal

separator; when different decimal separators are used, as in international

applications, use CDbl instead to convert a string to a number.

A2.5.3 Format

Format(expression[,format [,firstdayofweek [,firstweekofyear]]]) returns a

Variant (String) containing expression formatted according to the instruc-

tions contained in format.

Argument Description

expression Required. Any valid expression.

Format Optional. A valid named or user-defined format

expression.

firstdayofweek Optional. A constant that specifies the first day of the

week. See table A2T.3 for its valid values.

firstweekofyear Optional. A constant that specifies the first week of the

year. See table A2T.4 for its valid values.

To Format Do This

Numbers Use predefined named numeric formats or create

user-defined numeric formats.

Dates and times Use predefined named date/time formats or create

user-defined date/time formats.

Date and time serial

numbers

Use date and time formats or numeric formats.

Strings Create your own user-defined string formats.

If you try to format a number without specifying format, Format provides

functionality similar to the Str function, although it is internationally

aware. However, positive numbers formatted as strings using Format

don't include a leading space reserved for the sign of the value, while

those converted using Str retain the leading space.

71

For example, Val("&HFFFF") = -1

Page 494: Laborator Baze date

488

If you are formatting a non-localized numeric string, you should use a

user-defined numeric format to ensure that you get the look you want.

If the Calendar property setting is Gregorian and format specifies date

formatting, the supplied expression must be Gregorian (also see footnote

60). If the calendar is Gregorian, the meaning of format expression sym-

bols is unchanged.72

A2.5.3.1 Different Formats for Different Numeric Values

A user-defined format expression for numbers can have from one to four

sections separated by semicolons.73

If the format argument contains one

of the named numeric formats, only one section is allowed.

If you use: the result is:

One section

only

The format expression applies to all values.

Two

sections

The first section applies to positive values and zeros, the se-

cond to negative values.

Three

sections

The first section applies to positive values, the second to

negative values, and the third to zeros.

Four

sections

The first section applies to positive values, the second to

negative values, the third to zeros, and the fourth to Null

values.

If you include semicolons with nothing between them, the missing section

is printed using the format of the positive value.74

A2.5.3.2 Different Formats for Different String Values

A format expression for strings can have one section or two sections

separated by a semicolon (;).

72

If the calendar is Hijri, all date format symbols (for example, dddd, mmmm, yyyy) have

the same meaning but apply to the Hijri calendar. Format symbols remain in English;

symbols that result in text display (for example, AM and PM) display the string (English

or Arabic) associated with that symbol. The range of certain symbols changes when the

calendar is Hijri. 73

For example, "$#,##0;($#,##0)" has two sections: the first defines the format

for positive values and zeros; the second one defines the format for negative values. 74

For example, "$#,##0;;\Z\e\r\o" displays positive and negative values using

the format in the first section and displays "Zero" if the value is zero.

Page 495: Laborator Baze date

489

If you use: the result is:

One section

only

The format applies to all string data.

Two

sections

The first section applies to string data, whereas the second

to Null values and zero-length strings ("").

A2.5.3.3 Named Date/Time Formats

The following table identifies the predefined date and time format names:

Format

Name

Description

General

Date

Display a date and/or time. For real numbers, display a date

and time, for example, 4/3/93 05:34 PM. If there is no fractio-

nal part, display only a date, for example, 4/3/93. If there is no

integer part, display time only, for example, 05:34 PM. Date

display is determined by your system settings.

Long

Date

Display a date according to your system's long date format.

Medium

Date

Display a date using the medium date format appropriate for

the language version of the host application.

Short

Date

Display a date using your system's short date format.

Long

Time

Display a time using your system's long time format; includes

hours, minutes, seconds.

Medium

Time

Display time in 12-hour format using hours and minutes and

the AM/PM designator.

Short

Time

Display a time using the 24-hour format, for example, 17:45.

Page 496: Laborator Baze date

490

A2.5.3.4 Named Numeric Formats

The following table identifies the predefined numeric format names:

Format

name

Description

General

Number

Display number with no thousand separators.

Currency Display number with thousand separators, if appropriate;

display two digits to the right of the decimal separator.

Output is based on system locale settings.

Fixed Display at least one digit to the left and two digits to the

right of the decimal separator.

Standard Display number with thousand separators, at least one digit

to the left and two digits to the right of the decimal separa-

tor.

Percent Display number multiplied by 100 with a percent sign (%)

appended to the right; always display two digits to the right

of the decimal separator.

Scientific Use standard scientific notation.

Yes/No Display No if number is 0; otherwise, display Yes.

True/False Display False if number is 0; otherwise, display True.

On/Off Display Off if number is 0; otherwise, display On.

Page 497: Laborator Baze date

491

A2.5.3.5 User-Defined String Formats

You can use any of the following characters to create a format expression

for strings:

Character Description

@ Character placeholder. Display a character or a space. If the

string has a character in the position where the at symbol (@)

appears in the format string, display it; otherwise, display a

space in that position. Placeholders are filled from right to left

unless there is an exclamation point character (!) in the for-

mat string.

& Character placeholder. Display a character or nothing. If the

string has a character in the position where the ampersand

(&) appears, display it; otherwise, display nothing. Placehol-

ders are filled from right to left unless there is an exclamation

point character (!) in the format string.

< Force lowercase. Display all characters in lowercase format.

> Force uppercase. Display all characters in uppercase format.

! Force left to right fill of placeholders. The default is to fill

placeholders from right to left.

Page 498: Laborator Baze date

492

A2.5.3.6 User-Defined Date/Time Formats

The following table identifies characters you can use to create user-de-

fined date/time formats:

Character Description

(:) Time separator. In some locales, other characters may be used

to represent the time separator. The time separator separates

hours, minutes, and seconds when time values are formatted.

The actual character used as the time separator in formatted

output is determined by your system settings.

(/) Date separator. In some locales, other characters may be used

to represent the date separator. The date separator separates

the day, month, and year when date values are formatted. The

actual character used as the date separator in formatted output

is determined by your system settings.

c Display the date as ddddd and display the time as ttttt, in that

order. Display only date information if there is no fractional

part to the date serial number; display only time information

if there is no integer portion.

d Display the day as a number without a leading zero (1 - 31).

dd Display the day as a number with a leading zero (01 - 31).

ddd Display the day as an abbreviation (Sun - Sat).

dddd Display the day as a full name (Sunday - Saturday).

ddddd Display the date as a complete date (including day, month,

and year), formatted according to your system's short date

format setting. The default short date format is m/d/yy.

dddddd Display a date serial number as a complete date (including

day, month, and year) formatted according to the long date

setting recognized by your system. The default long date for-

mat is mmmm dd, yyyy.

aaaa The same as dddd, only it's the localized version of the string.

w Display the day of the week as a number (1 for Sunday

through 7 for Saturday).

Page 499: Laborator Baze date

493

ww Display the week of the year as a number (1 - 54).

m Display the month as a number without a leading zero (1 -

12). If m immediately follows h or hh, the minute rather than

the month is displayed.

mm Display the month as a number with a leading zero (01 - 12).

If m immediately follows h or hh, the minute rather than the

month is displayed.

mmm Display the month as an abbreviation (Jan - Dec).

mmmm Display the month as a full month name (January – Decem-

ber).

oooo The same as mmmm, only it's the localized version of the

string.

q Display the quarter of the year as a number (1 - 4).

y Display the day of the year as a number (1 - 366).

yy Display the year as a 2-digit number (00 - 99).

yyyy Display the year as a 4-digit number (100 - 9999).

h Display the hour as a number without leading zeros (0 - 23).

Hh Display the hour as a number with leading zeros (00 - 23).

N Display the minute as a number without leading zeros (0 -

59).

Nn Display the minute as a number with leading zeros (00 - 59).

S Display the second as a number without leading zeros (0 -

59).

Ss Display the second as a number with leading zeros (00 - 59).

t t t t t Display a time as a complete time (including hour, minute,

and second), formatted using the time separator defined by

the time format recognized by your system. A leading zero is

displayed if the leading zero option is selected and the time is

before 10:00 A.M. or P.M. The default time format is

h:mm:ss.

Page 500: Laborator Baze date

494

AM/PM Use the 12-hour clock and display an uppercase AM with any

hour before noon; display an uppercase PM with any hour be-

tween noon and 11:59 P.M.

am/pm Use the 12-hour clock and display a lowercase AM with any

hour before noon; display a lowercase PM with any hour be-

tween noon and 11:59 P.M.

A/P Use the 12-hour clock and display an uppercase A with any

hour before noon; display an uppercase P with any hour be-

tween noon and 11:59 P.M.

a/p Use the 12-hour clock and display a lowercase A with any

hour before noon; display a lowercase P with any hour betwe-

en noon and 11:59 P.M.

AMPM Use the 12-hour clock and display the AM string literal as de-

fined by your system with any hour before noon; display the

PM string literal as defined by your system with any hour be-

tween noon and 11:59 P.M. AMPM can be either uppercase

or lowercase, but the case of the string displayed matches the

string as defined by your system settings. The default format

is AM/PM.

Page 501: Laborator Baze date

495

A2.5.3.7 User-Defined Numeric Formats

The following table identifies characters you can use to create user-de-

fined number formats:

Character Description

None Display the number with no formatting.

(0) Digit placeholder. Display a digit or a zero. If the expression

has a digit in the position where the 0 appears in the format

string, display it; otherwise, display a zero in that position.

If the number has fewer digits than there are zeros (on either

side of the decimal) in the format expression, display leading

or trailing zeros. If the number has more digits to the right of

the decimal separator than there are zeros to the right of the

decimal separator in the format expression, round the number

to as many decimal places as there are zeros. If the number

has more digits to the left of the decimal separator than there

are zeros to the left of the decimal separator in the format ex-

pression, display the extra digits without modification.

(#) Digit placeholder. Display a digit or nothing. If the expres-

sion has a digit in the position where # appears in the format

string, display it; otherwise, display nothing in that position.

This symbol works like the 0 digit placeholder, except that

leading and trailing zeros aren't displayed if the number has

the same or fewer digits than there are # characters on either

side of the decimal separator in the format expression.

(.) Decimal placeholder. In some locales, a comma is used as

the decimal separator. The decimal placeholder determines

how many digits are displayed to the left and right of the de-

cimal separator. If the format expression contains only num-

ber signs to the left of this symbol, numbers smaller than 1

begin with a decimal separator. To display a leading zero dis-

played with fractional numbers, use 0 as the first digit place-

holder to the left of the decimal separator. The actual charac-

ter used as a decimal placeholder in the formatted output de-

pends on the Number Format recognized by your system.

(%) Percentage placeholder. The expression is multiplied by 100.

The percent character (%) is inserted in the position where it

Page 502: Laborator Baze date

496

appears in the format string.

(,) Thousand separator. In some locales, a period is used as a

thousand separator. The thousand separator separates thou-

sands from hundreds within a number that has four or more

places to the left of the decimal separator. Standard use of

the thousand separator is specified if the format contains a

thousand separator surrounded by digit placeholders (0 or #).

Two adjacent thousand separators or a thousand separator

immediately to the left of the decimal separator (whether or

not a decimal is specified) means "scale the number by divid-

ing it by 1000, rounding as needed." For example, you can

use the format string "##0,," to represent 100 million as 100.

Numbers smaller than 1 million are displayed as 0. Two ad-

jacent thousand separators in any position other than imme-

diately to the left of the decimal separator are treated simply

as specifying the use of a thousand separator. The actual cha-

racter used as the thousand separator in the formatted output

depends on the Number Format recognized by your system.

(:) Time separator. In some locales, other characters may be

used to represent the time separator. The time separator sepa-

rates hours, minutes, and seconds when time values are for-

matted. The actual character used as the time separator in

formatted output is determined by your system settings.

(/) Date separator. In some locales, other characters may be used

to represent the date separator. The date separator separates

the day, month, and year when date values are formatted.

The actual character used as the date separator in formatted

output is determined by your system settings.

(E- E+ e-

e+)

Scientific format. If the format expression contains at least

one digit placeholder (0 or #) to the right of E-, E+, e-, or e+,

the number is displayed in scientific format and E or e is in-

serted between the number and its exponent. The number of

digit placeholders to the right determines the number of di-

gits in the exponent. Use E- or e- to place a minus sign next

to negative exponents. Use E+ or e+ to place a minus sign

next to negative exponents and a plus sign next to positive

exponents.

Page 503: Laborator Baze date

497

- + $ ( ) Display a literal character. To display a character other than

one of those listed, precede it with a backslash (\) or enclose

it in double quotation marks (" ").

(\) Display the next character in the format string. To display a

character that has special meaning as a literal character, pre-

cede it with a backslash (\). The backslash itself isn't dis-

played. Using a backslash is the same as enclosing the next

character in double quotation marks. To display a backslash,

use two backslashes (\\).

Examples of characters that can't be displayed as literal cha-

racters are the date-formatting and time-formatting charac-

ters (a, c, d, h, m, n, p, q, s, t, w, y, / and :), the numeric-for-

matting characters (#, 0, %, E, e, comma, and period), and

the string-formatting characters (@, &, <, >, and !).

("ABC") Display the string inside the double quotation marks (" "). To

include a string in format from within code, you must use

Chr(34) to enclose the text (34 is the character code for a

quotation mark (")).

A2.5.4 FormatCurrency

FormatCurrency(Expression[,NumDigitsAfterDecimal [,IncludeLeading-

Digit [,UseParensForNegativeNumbers [,GroupDigits]]]]) returns expres-

sion formatted as a currency value using the currency symbol defined in

the system control panel.

Argument Description

expression Required. Expression to be formatted.

NumDigitsAfterDecimal Optional. Numeric value indicating

how many places to the right of the de-

cimal point are displayed. Default va-

lue is -1, which indicates that the com-

puter's regional settings are used.

IncludeLeadingDigit Optional. Tristate constant that indi-

cates whether or not a leading zero is

displayed for fractional values. See ta-

ble A2T.6 for its valid values.

Page 504: Laborator Baze date

498

UseParensForNegativeNumbers Optional. Tristate constant that indi-

cates whether or not to place negative

values within parentheses. See table

A2T.6 for its valid values.

GroupDigits Optional. Tristate constant that indi-

cates whether or not numbers are

grouped using the group delimiter spe-

cified in the computer's regional set-

tings. See table A2T.6 for its valid va-

lues.

Table AT2.5 FormatCurrency’s arguments descriptions

The IncludeLeadingDigit, UseParensForNegativeNumbers, and Group-

Digits arguments have the following valid values:

Constant Value Description

vbTrue -1 True

vbFalse 0 False

vbUseDefault -2 Use the setting from the

computer's regional settings.

Table AT2.6 FormatCurrency’s arguments valid values

When one or more optional arguments are omitted, the values for omitted

arguments are provided by the computer's regional settings.

The position of the currency symbol relative to the currency value is de-

termined by the system's regional settings.

All settings information comes from the Regional Settings Currency tab,

except leading zero which comes from the Number tab.

A2.5.5 FormatDateTime

FormatDateTime(Date[,NamedFormat]) returns an expression formatted

as a date or time.

Argument Description

Date Required. Date expression to be formatted.

Page 505: Laborator Baze date

499

NamedFormat Optional. Numeric value that indicates the date/time for-

mat used. If omitted, vbGeneralDate is used.

NamedFormat has the following valid values:

Constant Value Description

vbGeneralDate 0 Display date and/or time. If there is a date part,

display it as a short date. If there is a time part,

display it as a long time. If present, both parts

are displayed.

vbLongDate 1 Display date using the long date format specified

in your computer's regional settings.

vbShortDate 2 Display date using the short date format speci-

fied in your computer's regional settings.

vbLongTime 3 Display time using the time format specified in

your computer's regional settings.

vbShortTime 4 Display time using the 24-hour format (hh:mm).

A2.5.6 FormatNumber

FormatNumber(expression[,NumDigitsAfterDecimal [,IncludeLeadingDi-

git [,UseParensForNegativeNumbers [,GroupDigits]]]]) returns expres-

sion formatted as a number. See table A2T.5 for its arguments’ descrip-

tions. When one or more optional arguments are omitted, the values for

omitted arguments are provided by the computer's regional settings. All

settings information comes from the Regional Settings Number tab.

A2.5.7 FormatPercent

FormatPercent(expression[,NumDigitsAfterDecimal [,IncludeLeadingDi-

git [,UseParensForNegativeNumbers [,]]]]) returns expression formatted

as a percentage (multipled by 100) with a trailing % character. See table

A2T.5 for its arguments’ descriptions. When one or more optional argu-

ments are omitted, the values for omitted arguments are provided by the

computer's regional settings. All settings information comes from the Re-

gional Settings Number tab.

Page 506: Laborator Baze date

500

A2.5.8 Asc, AscB, and AscW

Asc(string), AscB(string), and AscW(string) return the ASCII, binary, and

UNICODE, respectively, first character of string. The required string ar-

gument is any valid string expression. If string contains no characters, a

run-time error occurs. On SBCS systems, range for the returned values is

0 – 255; on DBCS ones, range is -32768 to 65535.

AscB is used with byte data contained in a string: instead of returning the

character code for the first character, AscB returns the first byte. AscW re-

turns the UNICODE character code, except on platforms where UNI-

CODE is not supported, in which case its behavior is identical to that of

Asc.75

A2.5.9 Chr, ChrB, and ChrW

Chr(charcode), ChrB(charcode), and ChrW(charcode) return the string

corresponding to the Long charcode ASCII, binary, and UNICODE, res-

pectively, character code.

Numbers from 0 - 31 are the same as standard, nonprintable ASCII

codes.76

On SBCS systems, range for charcode is 0 – 255; on DBCS

ones, range is -32768 to 65535.

ChrB is used with byte data contained in a String. Instead of returning a

character, which may be one or two bytes, ChrB always returns a single

byte. ChrW returns a String containing the UNICODE character, except

on platforms where UNICODE is not supported, in which case its beha-

vior is identical to that of Chr.77

A2.5.10 Hex

Hex(number) returns a String representing the hexadecimal value of num-

ber. The required number argument is any valid numeric or string expres-

sion. If number is not already an integer, before being evaluated it is

rounded to the nearest integer.

75

VB for Macintosh does not support UNICODE. Therefore, AscW(n) cannot return all

UNICODE characters for n values in the range 128 - 65,535, as it does in Windows envi-

ronments. Instead, AscW(n) attempts a "best guess" for UNICODE values n greater than

127. Therefore, you should not use AscW in the Macintosh environment. 76

For example, Chr(10) returns a linefeed character. 77

VB for Macintosh does not support UNICODE. Therefore, ChrW(n) cannot return all

UNICODE characters for n values in the range 128 - 65,535, as it does in Windows envi-

ronments. Instead, ChrW(n) attempts a "best guess" for UNICODE values n greater than

127. Therefore, you should not use ChrW in the Macintosh environment.

Page 507: Laborator Baze date

501

When number is: Hex returns:

Null Null

Empty 0 (zero)

Any other number Up to eight hexadecimal characters

You can represent hexadecimal numbers directly by preceding numbers in

the proper range with &H.78

A2.5.11 Oct

Oct(number) returns a Variant (String) representing the octal value of

number. The required number argument is any valid numeric or string ex-

pression. If number is not already an integer, before being evaluated it is

rounded to the nearest integer.

When number is: Oct returns:

Null Null

Empty 0 (zero)

Any other number Up to 11 octal characters

You can represent octal numbers directly by preceding numbers in the

proper range with &O.79

A2.5.12 CVErr

CVErr(errornumber) returns a Variant of subtype Error containing error-

number. The required errornumber argument is any valid error number.

Use CVErr to create user-defined errors in your procedures. For example,

if you create a function that accepts several arguments and normally re-

turns a string, you can have your function evaluate the input arguments to

ensure they are within acceptable range. If they are not, it is likely your

function will not return what you expect. In this event, CVErr allows you

to return an error number that tells you what action to take.

78 For example, &H10 represents decimal 16 in hexadecimal notation.

79 For example, &O10 is the octal notation for decimal 8.

Page 508: Laborator Baze date

502

Note that implicit conversion of an Error is not allowed. For example,

you can't directly assign the return value of CVErr to a variable that is not

a Variant. However, you can perform an explicit conversion (using CInt,

CDbl, and so on) of the value returned by CVErr and assign that to a va-

riable of the appropriate data type.

A2.6 Program flow control functions

A2.6.1 IIf

IIf(expr, truepart, falsepart) returns either truepart or falsepart, depend-

ing on the evaluation of expr.

Argument Description

expr Required. Expression you want to evaluate.

truepart Required. Value or expression returned if expr is True.

falsepart Required. Value or expression returned if expr is False.

Note that IIf always evaluates both truepart and falsepart, even though it

returns only one of them: because of this, you should consider possible

undesirable side effects.80

A2.6.2 Switch

Switch(expr-1, value-1[, expr-2, value-2 … [, expr-n,value-n]]) evaluates

a list of expressions and returns a Variant value or an expression associa-

ted with the first expression in the list that is True. Switch argument list

consists of n (natural, n > 0) pairs of expressions and values. The expres-

sions are evaluated from left to right, and the value associated with the

first expression to evaluate to True is returned. If the arguments aren't

properly paired, a run-time error occurs. For example, if expr-1 is True,

Switch returns value-1; if expr-1 is False, but expr-2 is True, Switch re-

turns value-2, and so on.

Switch returns Null if none of the expressions is True or the first True ex-

pression has the Null value. Note that Switch evaluates all of the expres-

sions, even though it returns only one of them: because of this, you should

consider possible undesirable side effects (see similar note 79).

80

For example, if evaluating falsepart results in a division by zero error, an error occurs

even if expr is True.

Page 509: Laborator Baze date

503

Argument Description

expr-i* Required. Variant expression you want to evaluate.

value-i* Required. Value or expression to be returned if the corres-

ponding expression is True.

* 1 i n

A2.6.3 Choose

Choose(index, choice-1[, choice-2, ... [, choice-n]]) selects and returns a

value from its list of arguments, based on the value of index: if index is 1,

Choose returns the first choice in the list; if index is 2, it returns the se-

cond choice, and so on (where n > 0, natural). If index is not already an

integer, before being evaluated it is rounded to the nearest integer. Choose

returns Null if index is less than 1 or greater than n.

Argument Description

index Required. Numeric expression or field that results in a value

between 1 and n.

choice-i* Required. Variant expression containing one of the possible

choices.

* 1 i n

Choose is particularly useful if index represents the value in an option

group. Note that Choose evaluates every choice in the list, even though it

returns only one: because of this, you should consider possible undesira-

ble side effects.81

A2.6.4 CallByName

CallByName(object, procname, calltype,[args()]) executes a method or

gets/sets a property of an object or set.

81

For example, if you use the MsgBox function as part of the expressions of all choices,

a message box will be displayed for each choice as it is evaluated, even though Choose

returns the value of only one of them.

Page 510: Laborator Baze date

504

Argument Description

object Required; Variant (Object). The name of the object/set on

which procname will be executed or whose properties will be

get/set.

procname Required; Variant (String). A string expression containing the

name of a property or method of object.

calltype Required; Constant. A constant of type vbCallType represent-

ing the type of procname (that is one of the following four:

vbGet, vbSet, vbLet, or vbMethod).

args() Optional: Variant (Array). Actual procname‘s argument va-

lues list (if any).

A2.6.5 DoEvents

DoEvents() yields execution so that the operating system can process o-

ther events and returns an Integer representing the number of open forms

in stand-alone versions of VB, such as VB Professional Edition, and zero

in all other applications.

DoEvents passes control to the operating system: control is returned after

the operating system has finished processing the events in its queue and

all keys in the SendKeys queue have been sent. DoEvents is useful for

simple tasks like allowing users to cancel a process after it has started (for

example a search for a file). For long-running processes, yielding the pro-

cessor is better accomplished by using a Timer or delegating the task to an

ActiveX EXE component. In the latter case, the task can continue comple-

tely independent of your application, and the operating system takes care

of multitasking and time slicing.

Any time you temporarily yield the processor within an event procedure,

make sure the procedure is not executed again from a different part of

your code before the first call returns, as this could cause unpredictable

results. In addition, do not use DoEvents if other applications could possi-

bly interact with your procedure in unforeseen ways during the time you

have yielded control.

Page 511: Laborator Baze date

505

A2.7 File functions

A2.7.1 FileAttr

FileAttr(filenumber, returntype) returns a Long representing the file mode

for files opened using the Open statement.

Argument Description

filenumber Required; Integer. Any valid file number.

returntype Required; Integer. Number indicating the type of information

to return. Specify 1 to return a value indicating the file mode.

On 16-bit systems only, specify 2 to retrieve an operating

system file handle. returntype 2 is not supported in 32-bit

systems and causes an error.

When the returntype argument is 1, the following return values indicate

the file access mode:

Mode Value

Input 1

Output 2

Random 4

Append 8

Binary 32

A2.7.2 FileDateTime

FileDateTime(pathname) returns a Variant (Date) that indicates the date

and time when the file specified by pathname was created or last modi-

fied. The pathname string expression may include the directory (folder)

and the drive.

A2.7.3 FileLen

FileLen(pathname) returns a Long specifying the length in bytes of the

file specified by pathname. The pathname string expression may include

the directory (folder) and the drive. If the specified file is open when the

FileLen function is called, the value returned represents the size of the file

immediately before it was opened.

Page 512: Laborator Baze date

506

To obtain the actual length of an open file use the LOF function instead.

A2.7.4 LOF

LOF(filenumber) returns a Long representing the size in bytes, of file file-

number opened using the Open statement. The required filenumber argu-

ment is an Integer containing a valid file number (handler).

To obtain the length of a file that is not open use the FileLen function.

A2.7.5 FreeFile

FreeFile[(rangenumber)] returns an Integer representing the next file

number available for use by the Open statement. The optional rangenum-

ber argument is a Variant that specifies the range from which the next

free file number is to be returned: specify 0 (default) to return a file num-

ber in the range 1 – 255; specify 1 to return a file number in the range 256

– 511. Use FreeFile to supply a file number that is not already in use.

A2.7.6 Input

Input(number, [#]filenumber) returns String containing number characters

from file filenumber opened in Input or Binary mode.

Argument Description

number Required. Any valid numeric expression specifying the num-

ber of characters to return.

filenumber Required. Any valid file number.

Data read with the Input function is usually written to a file with Print #

or Put. Use this function only with files opened in Input or Binary mode.

Unlike the Input # statement, Input returns all of the characters it reads,

including commas, carriage returns, linefeeds, quotation marks, and lead-

ing spaces.

With files opened for Binary access, an attempt to read through the file

using Input until EOF returns True generates an error: when reading

binary files with Input, use LOF and Loc instead of EOF or use Get when

using EOF.

Use the InputB function for byte data contained within text files: with In-

putB, number specifies the number of bytes to return rather than those of

characters.

Page 513: Laborator Baze date

507

A2.7.7 Loc

Loc(filenumber) returns a Long specifying the current read/write position

within open file filenumber. The required filenumber argument is any va-

lid Integer file number (handler). Here are the returned values for each

file access mode:

Mode Return Value

Random Number of the last record read from or written to the file.

Sequential Current byte position in the file divided by 128. However,

information returned by Loc for sequential files is neither

used nor required.

Binary Position of the last read or written byte.

A2.7.8 Seek

Seek(filenumber) returns a Long specifying the current read/write position

within file filenumber opened using the Open statement, which may be in

the range 1 to 2,147,483,647 (equivalent to 2^31 - 1). The required file-

number argument is an Integer containing a valid file number (handler).

Here are the returned values for each file access mode:

Mode Return Value

Random Number of the next read or written record.

Binary, Output,

Append, Input

Byte position at which the next operation takes place:

the 1st byte in a file is at position 1, the 2

nd is at 2, etc.

For files opened in Random mode, Seek returns the number of the next re-

cord; for those opened in other modes, it returns the byte position at

which the next operation takes place.

A2.7.9 EOF

EOF(filenumber) returns an Integer containing the Boolean value True

when the end of file filenumber opened for Random or sequential Input

has been reached. The required filenumber argument is an Integer con-

taining any valid file number (handler). With files opened for Output,

EOF always returns True. Use EOF to avoid the error generated by at-

tempting to get input past the end of a file. EOF returns False until the

end of the file has been reached.

Page 514: Laborator Baze date

508

With files opened for Random or Binary access, EOF returns False until

the last executed Get statement is unable to read an entire record. With

files opened for Binary access, an attempt to read through the file using

the Input function until EOF returns True generates an error: when read-

ing binary files with Input, use LOF and Loc instead of EOF or use Get

when using EOF.

A2.8 Other operating system functions

A2.8.1 Shell

Shell(pathname[,windowstyle]) runs the executable program identified by

pathname and returns a Variant (Double) representing the program's task

ID,82

if successful83

; otherwise, it returns zero. If Shell can't start path-

name an error occurs.

Argument Description

pathname Required; Variant (String). Name84

of the program to exe-

cute and any required arguments or command-line swit-

ches; may include directory (folder) and drive.

windowstyle Optional. Variant (Integer) corresponding to the style of

the window in which the program is to be run. If window-

style is omitted, the program is started minimized with fo-

cus.85

82

a number assigned by the operating systems for uniquely identifying running programs 83

On Macintosh, vbNormalFocus, vbMinimizedFocus, and vbMaximizedFocus place the

application in the foreground; vbHide, vbNoFocus, and vbMinimizeFocus place the ap-

plication in the background. 84

On the Macintosh, you can use the MacID function to specify an application's signa-

ture instead of its name. The following example uses the signature for Microsoft Word:

Shell MacID("MSWD"). 85

On the Macintosh (System 7.0 or later), windowstyle only determines whether or not

the application gets the focus when it is run.

Page 515: Laborator Baze date

509

The windowstyle named argument has these valid values:

Constant Value Description

vbHide 0 Window is hidden and focus is passed to

the hidden window.86

vbNormalFocus 1 Window has focus and is restored to its

original size and position.

vbMinimizedFocus 2 Window is displayed as an icon with fo-

cus.

vbMaximizedFocus 3 Window is maximized with focus.

vbNormalNoFocus 4 Window is restored to its most recent size

and position. The currently active window

remains active.

vbMinimizedNoFocus 6 Window is displayed as an icon. The cur-

rently active window remains active.

Note that, by default, Shell runs other programs asynchronously: this

means that a program started with Shell might not finish executing before

the statements following Shell are executed.

A2.8.2 CurDir

CurDir[(drive)] returns a Variant (String) representing the current path.

The optional drive argument is a string expression that specifies an exist-

ing drive. If no drive is specified or if drive is a zero-length string (""),

CurDir returns the path for the current drive.87

A2.8.3 Dir

Dir[(pathname[, attributes])] returns a String representing the name of the

file or directory (folder) identified by pathname that matches a specified

pattern or file attributes, or the volume label of a drive. You must specify

pathname the first time you call Dir or an error occurs. If you also specify

file attributes, pathname must be included too. Dir returns the first file

name that matches pathname. To get any additional file names that match

pathname, call Dir again with no arguments. When no more file names

86

The vbHide constant is not applicable on Macintosh platforms. 87

On the Macintosh, CurDir ignores any drive specified and simply returns the path for

the current drive.

Page 516: Laborator Baze date

510

match, Dir returns a zero-length string (""). Once a zero-length string is

returned, you must specify pathname in subsequent calls or an error oc-

curs. You can change to a new pathname without retrieving all of the file

names that match the current pathname. However, you can't call Dir re-

cursively. Calling Dir with the vbDirectory attribute does not continually

return subdirectories!

Argument Description

pathname Optional. String expression that specifies a file name (may in-

clude directory (folder) and drive). A zero-length string ("") is

returned if pathname is not found.

attributes Optional. Constant or numeric expression, whose sum speci-

fies file attributes. If omitted, returns files that match path-

name but have no attributes.

The attributes argument valid values are the following:

Constant Value Description

vbNormal 0 (Default) Specifies files with no attributes.

vbReadOnly 1 Specifies read-only files in addition to files with no

attributes.

vbHidden 2 Specifies hidden files in addition to files with no at-

tributes.

vbSystem 4 Specifies system files in addition to files with no at-

tributes.88

vbVolume 8 Specifies volume label; if any other attributed is

specified, vbVolume is ignored. See footnote 87.

vbDirectory 16 Specifies directories or folders in addition to files

with no attributes.

vbAlias 64 Specified file name is an alias. Available only on

the Macintosh.

Table AT2.7 File attribute constants

88

Not available on the Macintosh.

Page 517: Laborator Baze date

511

Note that in MS Windows, Dir supports the use of multiple character (*)

and single character (?) wildcards to specify multiple files.89

To iterate over all files in a folder, specify an empty string: Dir("").90

Because file names are retrieved in no particular order, you may want to

store returned file names in an array and then sort it.

A2.8.4 GetAttr

GetAttr(pathname) returns an Integer representing the attributes of file or

directory (folder) pathname. The required pathname argument is a string

expression that specifies a file name; pathname may include the directory

(folder) and the drive. Values returned by GetAttr are the sum of the attri-

bute ones from table A2T.7 above.

To determine which attributes are set, use the And operator to perform a

bitwise comparison of the value returned by GetAttr and the value of the

individual file attribute you want. If the result is not zero, that attribute is

set for the corresponding file.91

A2.8.5 Environ

Environ({envstring | number}) returns the String associated with an ope-

rating system environment variable.92

If envstring can't be found in the

environment-string table, a zero-length string ("") is returned. Otherwise,

Environ returns the text assigned to the specified envstring: that is, the

text following the equal sign (=) in the environment-string table for that

environment variable. If you specify number, the string occupying that

numeric position in the environment-string table is returned. In this case,

Environ returns all of the text, including envstring. If there is no environ-

ment string in the specified position, Environ returns a zero-length string.

89 On the Macintosh, these characters are treated as valid file name characters and can't

be used as wildcards to specify multiple files. Since the Macintosh doesn't support the

wildcards, use the file type to identify groups of files. You can use the MacID function

to specify file type instead of using the file names. For example, the following statement

returns the name of the first TEXT file in the current folder: Dir("SomePath",

MacID("TEXT")). 90

If you use the MacID function with Dir in MS Windows, an error occurs. Any attri-

bute value greater than 256 is considered a MacID one. 91

For example, the return value of the following And expression is zero if the Archive at-

tribute is not set (whereas a nonzero value is returned if Archive is set): Result =

GetAttr(FName) And vbArchive. 92

Not available on the Macintosh.

Page 518: Laborator Baze date

512

Argument Description

envstring Optional. String expression containing the name of an envi-

ronment variable.

number Optional. Numeric expression corresponding to the numeric

order of the environment string in the environment-string ta-

ble. The number argument can be any numeric expression, but

is rounded to an integer before it is evaluated.

A2.8.6 GetAllSettings

GetAllSettings(appname, section) returns a list of key settings and their

respective values (originally created with SaveSetting) from an applica-

tion's entry in the Windows registry93

or an uninitialized Variant if either

appname or section does not exist.

Argument Description

appname Required. String expression containing the name of the appli-

cation or project whose key settings are requested.94

section Required. String expression containing the name of the sec-

tion whose key settings are requested. GetAllSettings returns a

Variant whose contents is a two-dimensional array of strings

containing all the key settings in the specified section and

their corresponding values.

A2.8.7 GetSetting

GetSetting(appname, section, key[, default]) returns the key setting value

from the appname application's entry in the Windows registry (for Macin-

tosh see footnote 92). If any of its arguments do not exist, GetSetting re-

turns the value of default.

Argument Description

appname Required. String expression containing the name of the appli-

cation or project whose key setting is requested (for Macin-

tosh see footnote 93).

93

or, on the Macintosh, information in the application's initialization file. 94

On the Macintosh, this is the filename of the initialization file in the Preferences fol-

der in the System folder.

Page 519: Laborator Baze date

513

section Required. String expression containing the name of the sec-

tion where the key setting is found.

key Required. String expression containing the name of the key

setting to return.

default Optional. Expression containing the value to return if no value

is set in the key setting. If omitted, default is assumed to be a

zero-length string ("").

A2.8.8 Spc

Spc(n) is used with the Print # statement or the Print method to position

output. The required n argument is the number of spaces to insert before

displaying or printing the next expression in a list. If n is less than the out-

put line width, the next print position immediately follows the number of

spaces printed; if n is greater than the output line width, Spc calculates the

next print position using the formula: currentprintposition + (n Mod

width)95

; if the difference between the current print position and the out-

put line width is less than n (or n Mod width), Spc skips to the beginning

of the next line and generates spaces equal to n - (width – currentprintpo-

sition). Make sure your tabular columns are wide enough to accommodate

wide letters.

When you use the Print method with a proportionally spaced font, the

width of space characters printed using Spc is always an average of the

width of all characters in the point size for the chosen font. However,

there is no correlation between the number of characters printed and the

number of fixed-width columns those characters occupy.96

A2.8.9 Tab

Tab[(n)] is used with the Print # statement or the Print method to position

output. The optional n argument is the column number moved to before

displaying or printing the next expression in a list; if omitted, Tab moves

the insertion point to the beginning of the next print zone: this allows Tab

to be used instead of a comma in locales where the comma is used as a

decimal separator. If the current print position on the current line is grea-

95

For example, if the current print position is 24, the output line width is 80, and you

specify Spc(90), the next print will start at position 34 (current print position + the re-

mainder of 90/80). 96

For example, the uppercase letter W occupies more than one fixed-width column and

the lowercase letter i occupies less than one fixed-width column.

Page 520: Laborator Baze date

514

ter than n, Tab skips to the nth column on the next output line; if n is less

than 1, Tab moves the print position to column 1; if n is greater than the

output line width, Tab calculates the next print position using the formula:

n Mod width;97

if n is less than the current print position, printing begins

on the next line at the calculated print position; if the calculated print po-

sition is greater than the current print position, printing begins at the

calculated print position on the same line.

Note that the leftmost print position on an output line is always 1. When

you use the Print # statement to print to files, the rightmost print position

is the current width of the output file, which you can set using the Width #

statement.

Make sure your tabular columns are wide enough to accommodate wide

letters. When you use Tab with the Print method, the print surface is divi-

ded into uniform, fixed-width columns. The width of each column is an

average of the width of all characters in the point size for the chosen font.

However, there is no correlation between the number of characters printed

and the number of fixed-width columns those characters occupy (see foot-

note 95).

A2.9 Array functions

A2.9.1 Array

Array(arglist) returns a Variant containing an array. The required arglist

argument is a comma-delimited list of values that are assigned to the ele-

ments of the array contained within the Variant. If no arguments are spe-

cified, an array of zero length is created.

The notation used to refer to an element of an array consists of the varia-

ble name followed by parentheses containing an index number indicating

the desired element.98

The lower bound of an array created using Array is determined by the

lower bound specified with the Option Base statement, unless Array is

97

For example, if width is 80 and you specify Tab(90), the next print will start at column

10 (the remainder of 90/80). 98

For example: Dim A As Variant ‘creates a Variant variable named A

A = Array(10,20,30)‘assigns an array to variable A

B = A(2) ‘assigns the value contained in the second array

‘element to another variable

Page 521: Laborator Baze date

515

qualified with the name of the type library (for example VBA.Array); if

qualified with the type-library name, Array is unaffected by Option Base.

Note that a Variant that is not declared as an array can still contain an

array: a Variant variable can contain an array of any type, except fixed-

length strings and user-defined types; although a Variant containing an

array is conceptually different from an array whose elements are of type

Variant, the array elements are accessed in the same way.

A2.9.2 Filter

Filter(sourcesrray, match[, include[, compare]]) returns a zero-based ar-

ray containing the match subset of the string array sourcesrray based on a

specified filter criteria.

Argument Description

sourcearray Required. One-dimensional array of strings to be searched.

match Required. String to search for.

include Optional. Boolean value indicating whether to return sub-

strings that include or exclude match; if include is True,

Filter returns the subset of the array that contains match as

a substring; if include is False, Filter returns the subset of

the array that does not contain match as a substring.

compare Optional. Numeric value indicating the kind of string com-

parison to use. See table A2.T1 for its valid values.

The compare argument can have the following values:

Constant Value Description

vbUseCompareOption -1 Performs a comparison using the setting

of the Option Compare statement.

vbBinaryCompare 0 Performs a binary comparison.

vbTextCompare 1 Performs a textual comparison.

vbDatabaseCompare 2 MS Access only. Performs a comparison

based on information in your database.

Page 522: Laborator Baze date

516

If no matches of match are found within sourcearray, Filter returns an

empty array. An error occurs if sourcearray is Null or is not a one-dimen-

sional array. The array returned by the Filter function contains only e-

nough elements to contain the number of matched items.

A2.9.3 LBound

LBound(arrayname[, dimension]) returns a Long containing the smallest

available subscript for the indicated dimension of the array arrayname.

Argument Description

arrayname Required. Name of the array variable; follows standard va-

riable naming conventions.

dimension Optional; Variant (Long). Natural indicating which dimen-

sion's lower bound is returned: use 1 for the first dimension,

2 for the second, etc.; if dimension is omitted, 1 is assumed.

LBound is used in conjunction with UBound (which returns upper limits

of arrays) to determine the size of arrays.

LBound returns the values in the following table for an array with the fol-

lowing dimensions:

The default lower bound for any dimension is either 0 or 1, depending on

the setting of the Option Base statement. However, the base of an array

created with Array is zero: it is unaffected by Option Base.

Arrays for which dimensions are set using the To clause in a Dim, Pri-

vate, Public, ReDim, or Static statement can have any integer value as a

lower bound.

A2.9.4 UBound

UBound(arrayname[, dimension]) returns a Long containing the largest

available subscript for the indicated dimension of the array arrayname.

Statement Return Value

LBound(A, 1) 1

LBound(A, 2) 0

LBound(A, 3) -3

Page 523: Laborator Baze date

517

Argument Description

arrayname Required. Name of the array variable; follows standard va-

riable naming conventions.

dimension Optional; Variant (Long). Natural indicating which dimen-

sion's upper bound is returned: use 1 for the first dimension,

2 for the second, and so on; if dimension is omitted, 1 is as-

sumed.

UBound is used in conjunction with LBound (which returns lower limits

of arrays) to determine the size of arrays.

UBound returns the values in the following table for an array with the fol-

lowing dimensions:

Statement Return Value

UBound(A, 1) 100

UBound(A, 2) 3

UBound(A, 3) 4

A2.10 Miscellanea functions

A2.10.1 Error

Error[(errornumber)] returns the error message that corresponds to error-

number. The optional errornumber argument can be any valid error num-

ber. If errornumber is a valid error number, but is not defined, Error re-

turns the string "Application-defined or object-defined error." If error-

number is not valid, an error occurs. If errornumber is omitted, the mes-

sage corresponding to the most recent run-time error is returned. If no

run-time error has occurred, or errornumber is 0, Error returns a zero-

length string (""). Examine the property settings of the Err object to iden-

tify the most recent run-time error. The return value of the Error function

corresponds to the Description property of the Err object.

A2.10.2 QBColor

QBColor(color) returns a Long representing the RGB color code corres-

ponding to the color number. The required color argument is a natural in

the range 0-15.

Page 524: Laborator Baze date

518

The color argument has the following valid values:

Number Color Number Color

0 Black 8 Gray

1 Blue 9 Light Blue

2 Green 10 Light Green

3 Cyan 11 Light Cyan

4 Red 12 Light Red

5 Magenta 13 Light Magenta

6 Yellow 14 Light Yellow

7 White 15 Bright White

Note that the color argument represents color values used by earlier ver-

sions of Basic (such as MS VB for MS-DOS and the Basic Compiler).

Starting with the least-significant byte, the returned value specifies the

red, green, and blue values used to set the appropriate color in the RGB

system used by VBA.

A2.10.3 RGB

RGB(red, green, blue) returns a Long natural representing an RGB color

value obtained from mixing different nuances of red, green, and blue.99

Argument Description

red Required; Variant (Integer). Number in the range 0-255 that

represents the red component of the color.

green Required; Variant (Integer). Number in the range 0-255 that

represents the green component of the color.

blue Required; Variant (Integer). Number in the range 0-255 that

represents the blue component of the color.

99

The RGB color values returned by this function are incompatible with those used by

the Macintosh operating system. They may be used within the context of Microsoft ap-

plications for the Macintosh, but should not be used when communicating color changes

directly to the Macintosh operating system.

Page 525: Laborator Baze date

519

Application methods and properties that accept a color specification ex-

pect that specification to be a number representing an RGB color value.

An RGB color value specifies the relative intensity of red, green, and blue

to cause a specific color to be displayed. The value for any argument to

RGB that exceeds 255 is assumed to be 255.

The following table lists some standard colors and the red, green, and

blue values they include:

Color Red Value Green Value Blue Value

Black 0 0 0

Blue 0 0 255

Green 0 255 0

Cyan 0 255 255

Red 255 0 0

Magenta 255 0 255

Yellow 255 255 0

White 255 255 255

A2.10.4 CreateObject

CreateObject(class,[servername]) creates and returns a reference to an

ActiveX object named class. Note that every application that supports Au-

tomation provides at least one type of object. For example, a word proces-

sing application may provide an Application object, a Document object,

and a Toolbar object. To create an ActiveX object, assign the object re-

turned by CreateObject to an object variable.

Argument Description

Class Required; Variant (String). The application name and class

of the object to create.

servername Optional; Variant (String). The name of the network server

where the object will be created. If servername is an empty

string (""), the local machine is used.

Page 526: Laborator Baze date

520

The class argument uses the syntax appname.objecttype and has these

components:

Component Description

appname Required; Variant (String). The name of the application pro-

viding the object.

objecttype Required; Variant (String). The type or class of object to

create.

A2.10.5 GetObject

GetObject([pathname] [, class]) returns a reference to an object provided

by an ActiveX component and identified by pathname or class; if path-

name is a zero-length string (""), GetObject returns a new object instance

of the specified type; if the pathname argument is omitted, GetObject re-

turns a currently active object of the specified type. If no object of the

specified type exists, an error occurs.

Argument Description

pathname Optional; Variant (String). The full path and name of the file

containing the object to retrieve. If pathname is omitted, class

is required.

class Optional; Variant (String). A string representing the object

class name.

class uses the syntax appname.objecttype, where:

Part Description

appname Required; Variant (String). The name of the application pro-

viding the object.

objecttype Required; Variant (String). The type or class of object to re-

trieve.

Use GetObject when there is a current instance of the object or if you

want to create the object with a file already loaded. If there is no current

instance and you don't want the object started with a file loaded, use the

CreateObject function instead.

Page 527: Laborator Baze date

521

GetObject is used to access an ActiveX object from a file and assign the

object to an object variable. Use the Set statement to assign the object re-

turned by GetObject to the object variable.100

Some applications allow you to activate part of a file. Add an exclamation

point (!) to the end of the file name and follow it with a string that identi-

fies the part of the file you want to activate. For information on how to

create this string, see the documentation for the application that created

the object.101

If you don't specify the object's class, Automation determines the applica-

tion to start and the object to activate, based on the file name you provide.

Some files, however, may support more than one class of object. For

example, a drawing might support three different types of objects: an Ap-

plication object, a Drawing object, and a Toolbar object, all of which are

part of the same file. To specify which object in a file you want to

activate, use the optional class argument.102

Once an object is activated, you reference it in code using the object va-

riable you defined. In the preceding example, you access properties and

methods of the new object using the object variable MyObject.103

If an object has registered itself as a single-instance object, only one in-

stance of the object is created, no matter how many times CreateObject is

executed. With a single-instance object, GetObject always returns the

same instance when called with the zero-length string ("") syntax, and it

100

For example, when the following code is executed, the application associated with the

specified pathname is started and the object in the specified file is activated: Dim CADObject As Object

Set CADObject = GetObject("C:\CAD\SCHEMA.CAD") 101

For example, in a drawing application you might have multiple layers to a drawing

stored in a file. You could use the following code to activate a layer within a drawing

called SCHEMA.CAD: Set LayerObject = GetObject("C:\CAD\SCHEMA.CAD!Layer3") 102

For example, if FIGMENT is the name of a drawing application and DRAWING is

one of the object types it supports: Dim MyObject As Object

Set MyObject = GetObject("C:\DRAWINGS\SAMPLE.DRW",

"FIGMENT.DRAWING") 103

For example: MyObject.Line 9, 90

MyObject.InsertText 9, 100, "Hello, world."

MyObject.SaveAs "C:\DRAWINGS\SAMPLE.DRW"

Page 528: Laborator Baze date

522

causes an error if the pathname argument is omitted. Note that you can't

use GetObject to obtain a reference to a class created with VB.

A2.10.6 Financial functions

Here are the financial functions (all returning a corresponding Double):

Function Result

DDB The depreciation of an asset for a specific time period using

the double-declining balance or some other specified method.

FV The future value of an annuity based on periodic, fixed pay-

ments, and a fixed interest rate.

IPmt The interest payment for a given period of an annuity based

on periodic, fixed payments, and a fixed interest rate.

IRR The internal rate of return for a series of periodic cash flows

(payments and receipts).

MIRR The modified internal rate of return for a series of periodic

cash flows (payments and receipts).

NPer The number of periods for an annuity based on periodic,

fixed payments, and a fixed interest rate.

NPV The net present value of an investment based on a series of

periodic cash flows (payments and receipts) and a discount

rate.

Pmt The payment for an annuity based on periodic, fixed pay-

ments, and a fixed interest rate.

PPmt The principal payment for a given period of an annuity based

on periodic, fixed payments, and a fixed interest rate.

PV The present value of an annuity based on periodic, fixed pay-

ments to be paid in the future, and a fixed interest rate.

Rate The interest rate per period for an annuity.

SLN The straight-line depreciation of an asset for a single period.

SYD The sum-of-years' digits depreciation of an asset for a speci-

fied period.

Page 529: Laborator Baze date

523

Subject Index - 497 ! 491, 521 " 497 # 495

See one-to-one function symbol $ 497 % 495, See Oracle wildcard

character & 491, See Access concatenation

operator, See string concatenation operator

( ) 497 (/) 492 (:)492 (co-)domain constraint ................ 19 (conventional) commutative

function diagram example ................................. 287

* 511, See Access wildcard

character , 496 . 495 / 496 : 496 ? 511 @ 491 || See Oracle concatenation

operator + 497 < 491 > 491 0 495 a/p .............................................. 494 A/P ............................................. 494 aaaa ........................................... 492 ABC ........................................... 497 Abs ............................................ 479 Access

Report Generator and Manager ........................................... 322

Report Layout Tools .............. 322 Report Wizard ....................... 322

ActiveX object ............................ 519, 521

ActiveX EXE component .......... 504 acyclic autofunction

examples ....................... 201, 221 acyclic constraint

example ................................. 282 ADF .. See Application Development

Framework ADO ........ See ActiveX Data Objects ADODB

connection ............................. 309 recordset ................................ 310

AfterDelConfirm form event ..... 300 AfterInsert form event ............... 299 AfterUpdate

control event ......................... 301 form event ............................. 299

Algorithm A0 DML statements design

assistance ........................... 120 Query design assistance ........ 120

am/pm ........................................ 494 AM/PM ...................................... 494 AMPM ....................................... 494 And ............................................ 511 anti-commutative constraint

example ................................. 287 anti-symmetric constraint

example ................................. 284 antisymmetric math relation ..... 158,

171 anti-transitive constraint

example ................................. 284 Append .............................. 505, 507 Application ........................ 519, 521 Arccos ....................................... 482 Arccosec .................................... 482 Arccotan .................................... 482

Page 530: Laborator Baze date

524

Arcsec ........................................ 482 Arcsin ........................................ 482 ARGM ................ See Access Report

Generator and Manager ARLT ..... See Access Report Layout

Tools Array .......................................... 514 ARW ....... See Access Report Wizard Asc ............................................. 500 AscB .......................................... 500 ASCII(l) ....................................... 14 AscW ......................................... 500 Atn ............................................. 482 attribute co-domain.... See attribute

domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain

attribute domain example ......... 249, 250, 255, 267

attribute range ............ See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain, See attribute domain

Automation ........................ 519, 521 BA ................. See business analysis BeforeDelConfirm form event .. 300 BeforeInsert form event ............. 298 BeforeUpdate

control event .......................... 301 form event ............................. 299

Binary ................ 505, 506, 507, 508 Black .......................................... 519 Blue ........................................... 519 BOF ...................... See Begin Of File Boolean ...................................... 466 BPR1.0

tables should correspond to

object sets ............................ 74 BPR1.1

ordinary columns should

correspond to object set

properties ............................. 74 BPR1.2

foreign keys should correspond

to functions defined on and

taking values from object sets

............................................. 74 BPR1.3

when available, always use

comboboxes for all foreign

keys ..................................... 74 BPR1.4

at least one column per table not

accepting nulls ..................... 74 BPR1.5

always ban dirty nulls .............. 74 BPR1.6

at least one semantic key per

table ..................................... 74 BPR1.7

use GUI for increasing

productivity ......................... 75 BPR2.0

backup instances before

modifying them ................. 117 BPR2.1

first test UPDATE and DELETE

SELECTs........................... 117 BPR2.2

modify only data which has to be

modified ............................ 117 BPR2.3

use rollback transactions ....... 117 BPR2.4

caution with the ON DELETE

CASCADE ........................ 117 BPR2.5

purge immediately old unneeded

data .................................... 117

Page 531: Laborator Baze date

525

BPR2.6 factorize I/Os ......................... 117

BPR2.7 always test SQL statements ... 118

BPR3.0 ...................................... 156 Byte ............................................ 466 c 492 Calendar .................................... 469 CallByName .............................. 503 Cancel ........................................ 303 cardinality

example ......................... 249, 250 carriage return............................ 463 CBool ........................................ 484 CByte ......................................... 484 CCur .......................................... 484 CDate ......................................... 484 CDbl .......................... 484, 487, 502 CDec .......................................... 484 Choose ....................................... 503 Chr ............................................. 500 ChrB .......................................... 500 ChrW ......................................... 500 CInt .................................... 485, 502 Click

control event ......................... 302 form event ............................. 300

CLng .......................................... 485 CLngLng ................................... 485 CLngPtr ..................................... 485 Close form/report event ............. 301 Combo Box .................................. 28 compulsory data

example . 249, 250, 251, 255, 267 Cos ............................................. 482 Cosec ......................................... 482 Cotan ......................................... 482 CreateObject .............. 519, 520, 521 Crystal Reports .......................... 322 CSng .......................................... 485 CStr .................................... 485, 486 CurDir ........................................ 509

Currency ............................ 466, 490 Current form/report event ......... 298 CVar .......................................... 485 CVDate ...................................... 486 CVErr ................................ 469, 501 Cyan .......................................... 519 d 470, 492 dangling pointer .................... 26, 66 DAO ......... See Data Access Objects Data Definition Language

SQL .......................................... 13 Data Manipulation Language

SQL .......................................... 13 DataErr ...................................... 304 Date ................................... 466, 469 Date$ ......................................... 469 DateAdd .................................... 474 DateDiff .................................... 475 DatePart ..................................... 470 DateSerial .................................. 472 DateValue .................................. 473 DAvg ......................................... 313 Day ............................................ 476 db ................................. See database DBCS .... See double-byte character

set DblClick

control event ......................... 302 form event ............................. 300

DCount ...................................... 313 dd ............................................... 492 DDB .......................................... 522 ddd ............................................. 492 dddd ........................................... 492 ddddd ......................................... 492 dddddd ....................................... 492 DDL . See Data Definition Language Decimal ..................................... 466 Default Value ............................ 437 Delete form event ...................... 299 Description ................................ 437 Dim ............................................ 304

Page 532: Laborator Baze date

526

Dir .............................................. 509 dirty null ...................................... 17 DISTINCT SQL predicate . 165, 181 DLookup .............................. 90, 312 DMax ......................................... 313 DMin ......................................... 313 DML ........... See Data Manipulation

Language DoCmd ...................................... 312 DoCmd.RunSQL ....................... 312 Document .................................. 519 domain constraint ........ (co-)domain

constraint Double ....................................... 466 Drawing ..................................... 521 DROP SQL statement ................. 13 drop-down list.......... See combo box DSum ......................................... 313 DUAL Oracle system table ....... 179 e- 496 E- 496 e.g. See for example (from the Latin

exempli gratia), See for example (from the Latin exempli gratia)

e+ .............................................. 496 E+ .............................................. 496 Empty ......................................... 466 empty recordset ......................... 310 empty set ........................... 201, 221 Enter control event .................... 301 Environ ...................................... 511 EOF ......... 506, 507, See End Of File E-RD

example ......................... 247, 248 Err ...................................... 306, 517 Error .......................... 466, 501, 517 Error form/report event ............. 300 event-driven methods ................ 303 Execute ...................................... 312 Exp ............................................ 482 FE ............. See forward engineering FileAttr ...................................... 505

FileDateTime............................. 505 FileLen .............................. 505, 506 Filter .......................................... 515 Fix ..................................... 479, 485 Fixed .......................................... 490 foreign key .................................. 14 form feed ................................... 463 Form Wizard ............................. 292 Format ............................... 486, 487 FormatCurrency ........................ 497 FormatDateTime ....................... 498 FormatNumber .......................... 499 FormatPercent ........................... 499 Forms ADO collection ............... 311 FreeFile ..................................... 506 function

kernel ..................................... 119 nucleus .......... See function kernel

FV .............................................. 522 General Date ............................. 489 General Number ........................ 490 generalized commutativity

example ................................. 289 Get ..................................... 506, 508 GetAllSettings ........................... 512 GetAttr ...................................... 511 GetObject .................................. 520 GetSetting .................................. 512 Green ......................................... 519 GUI ....... See Graphic User Interface h 470, 493 HArccos .................................... 483 HArccosec ................................. 483 HArccotan ................................. 483 HArcsec ..................................... 483 HArcsin ..................................... 483 HArctan ..................................... 483 HCos .......................................... 483 HCosec ...................................... 483 HCotan ...................................... 483 Hex ............................................ 500 Hh .............................................. 493

Page 533: Laborator Baze date

527

horizontal tab ............................. 463 Hour ........................................... 478 HSec .......................................... 483 HSin ........................................... 483 HTan .......................................... 483 i.e. ....... See that is (from the Latin id

est), See that is (from the Latin id est)

IIf502 Input .................. 505, 506, 507, 508 Input # ....................................... 506 InputB ........................................ 506 InputBox .................................... 309 InStr ........................................... 459 InStrB ........................................ 460 InstrRev ..................................... 460 Int ...................................... 479, 485 Integer ....................................... 466 IPmt ........................................... 522 IRR ............................................ 522 irreflexive autofunction

examples........................ 201, 221 irreflexive constraint

example ......................... 283, 284 irreflexive math relation .... 158, 171 IsArray ....................................... 468 IsDate ................................ 468, 485 IsEmpty ..................................... 466 IsError ........................................ 469 IsMissing ................................... 468 IsNull ......................................... 465 IsNull predicate

Access ............................ 164, 181 IsNumeric .................................. 468 IsObject ..................................... 469 Join ............................................ 464 ker ..................... See function kernel

(f g) .................................... 119 (f) 119

key Access constraint ............... 17, 54

Label Wizard ............................. 322

LBound ...................................... 516 LCase ........................................ 458 LCID ........................... See LocaleID Left ............................................ 458 LeftB ......................................... 459 Left-Root-Right traversal .. 193, 213 Len ............................................ 458 LenB .......................................... 458 linefeed ...................................... 463 Load form/report event ............. 298 Loc ............................. 506, 507, 508 local commutativity

example ................................. 288 LocaleID .................................... 459 Locked ....................................... 297 LOF ................................... 506, 508 Log ............................................ 482 LogN ......................................... 483 Long .......................................... 466 Long Date .................................. 489 Long Time ................................. 489 LTrim ........................................ 459 m 470, 493 MacID ....................................... 511 Magenta ..................................... 519 Me .............................................. 312 Medium Date ............................. 489 Medium Time ............................. 489 metacatalog

Access .................................... 252 Oracle .................................... 255

metacatalogue ............................ 268 metadata

example ................................. 265 Minute ....................................... 478 MIRR ........................................ 522 mm ............................................. 493 mmm .......................................... 493 mmmm ....................................... 493 Month ........................................ 477 MonthName............................... 478 MoveNext .................................. 311

Page 534: Laborator Baze date

528

MS ............................. See Microsoft MS Design View ................ See QBE MsgBox ............................. 307, 503 n 470 N 493 NAT(n) ........................................ 14 NewData .................................... 304 NewRecord ........................ 302, 318 Nn .............................................. 493 No Data ..................................... 331 NoData report event .................. 301 Not In List combo-box event ..... 302 not null

Access constraint ... 17, 18, 54, 55 Nothing .............................. 466, 469 Now ........................................... 469 NPer ........................................... 522 NPV ........................................... 522 Null .................................... 463, 466 null string ...... See zero-length string Object ........................................ 466 Oct ............................................. 501 OldValue .................................... 302 On Error

GoTo ...................................... 306 Resume Next ......................... 307

On/Off ....................................... 490 one-to-one function

example ................................... 14 oooo ........................................... 493 Open form/report event ............. 298 Option Base ............................... 514 Option Compare ................ 459, 515 Oracle

(co-)domain constraint ............ 56 Application Development

Framework ........................ 102 autonumber ....................... 53, 59 db connection .......................... 50 dirty null .................................. 54 domain constraint .... (co-)domain

constraint

NOT NULL constraint ............ 53 PL/SQL

EXECUTE statement ........... 117 Primary Key constraint ........... 53 semantic key ............................ 54 sequence ................................. 59 SQL Developer........................ 49 stored function ...................... 175 trigger ...................................... 60

Output ................................ 505, 507 ParamArray ............................... 468 Parent ........................................ 312 Partition ..................................... 479 Percent ....................................... 490 PL/SQL ......................................... 61

package ................................. 150 body ................................... 151 header ............................... 151

procedure .............................. 150 Pmt ............................................ 522 PPmt .......................................... 522 Primary Key ................................ 16 Print ........................................... 513 Print # ................................ 506, 513 Private ....................................... 305 Public ........................................ 305 Put ............................................. 506 PV .............................................. 522 q 470, 493 QBColor .................................... 517 QBE ............. See Query-by-Example queries hierarchy

example ......................... 204, 222 Query-by-Example ...................... 15 RA ................. See relational algebra Random ............................. 505, 507 Randomize ................................. 481 Rate ........................................... 522 RE .............. See reverse engineering Red ............................................ 519 relational constraint types ......... 292 Replace ...................................... 461

Page 535: Laborator Baze date

529

Report Properties ............... 330, 331 Reporting Services for SQL Server

............................................... 322 Response .................................... 304 RGB ......... 518, See Red-Green-Blue Right .......................................... 458 RightB ........................................ 459 Rnd ............................................ 481 Round ........................................ 480 RTrim ........................................ 459 s 470 S 493 SaveSetting ................................ 512 SBCS . See single-byte character set Scientific .................................... 490 Sec ............................................. 482 Second ....................................... 478 Seek ........................................... 507 SELECT SQL statement

aggregate functions ............... 119 composition ....................... 119

clause FROM ......................... 119, 120

ON sub-clause ................ 119 GROUP BY ................ 119, 120

golden rule ..................... 120 ORDER BY........................... 119 SELECT ............................... 120

AS operator .................... 156 WHERE ............................... 119

self-join .............. 189, 198, 208, 216 SendKeys ................................... 504 Sequential .................................. 507 Set .............................................. 521 Sgn ............................................. 480 Shell ........................................... 508 Short Date ................................. 489 Short Time ................................. 489 Sin .............................................. 482 Single ......................................... 466 SLN ........................................... 522 space .......................................... 463

Space ......................................... 462 Spc ............................................. 513 Split ........................................... 465 SQLSee Structured Query Language

ANSI 92 .................................... 13 ANSI 99 .................................... 13

Sqr ............................................. 482 Ss 493 SSN .......... See (U.S.) Social Security

Number Standard .................................... 490 Status ......................................... 304 Str ...................................... 486, 487 StrComp .................................... 462 StrConv ..................................... 463 String ................................. 462, 466 StrReverse ................................. 459 structural E-RD ......................... 249 structural function ....................... 14 subquery ............................ 130, 145

examples ....................... 204, 222 surrogate key ......................... 15, 53 Switch ........................................ 502 SYD ........................................... 522 t t t t t ......................................... 493 Tab ............................................ 513 Tan ............................................ 482 Time .......................................... 469 Time$ ........................................ 469 Timer ......................................... 504 TimeSerial ................................. 473 TimeValue ................................. 474 Toolbar .............................. 519, 521 transitive closure 193, 211, 225, 226

example ......................... 202, 220 transitive constraint

example ......................... 283, 284 Trim ........................................... 459 True/False .................................. 490 TypeName ................................. 466 UBound ..................................... 516 UNION ALL operator 164, 180

Page 536: Laborator Baze date

530

UNION operator ................. 164 uniqueness

example . 249, 250, 251, 255, 267 Unknown .................................... 466 Val ..................................... 485, 486 Variant ....................................... 305 VarType ............................. 467, 469 VBA ................. See Visual Basic for

Applications, See Visual Basic

for Applications, See Visual Basic for Applications

VBA.Array ................................ 515 vbAbortRetryIgnore .................. 308 vbAlias ...................................... 510 vbArray ...................................... 467 vbBinaryCompare ............. 459, 515 vbBoolean .................................. 467 vbByte ....................................... 467 vbCallType ................................ 504 vbCancel .................................... 308 vbCritical ................................... 307 vbCurrency ................................ 467 vbDatabaseCompare .......... 459, 515 vbDataObject ............................. 467 vbDate ....................................... 467 vbDecimal ................................. 467 vbDefaultButton1 ...................... 308 vbDefaultButton2 ...................... 308 vbDefaultButton3 ...................... 308 vbDefaultButton4 ...................... 308 vbDirectory ................................ 510 vbDouble ................................... 467 vbEmpty .................................... 467 vbError ...................................... 467 vbExclamation ........................... 307 vbFalse ...................................... 498 vbFirstFourDays ........................ 471 vbFirstFullWeek ........................ 471 vbFirstJan1 ................................ 471 vbFriday .................................... 471 vbFromUnicode ......................... 464 vbGeneralDate .......................... 499

vbGet ......................................... 504 vbHidden ................................... 510 vbHide ....................................... 509 vbHiragana ................................ 464 vbInfo ........................................ 307 vbInteger ................................... 467 vbKatakana ................................ 464 vbLet ......................................... 504 vbLong ...................................... 467 vbLongDate ............................... 499 vbLongLong .............................. 467 vbLongTime .............................. 499 vbLowerCase............................. 464 vbMaximizedFocus ................... 509 vbMethod .................................. 504 vbMinimizedFocus .................... 509 vbMinimizedNoFocus ............... 509 vbMonday ................................. 471 vbMsgBoxHelpButton .............. 307 vbNarrow .................................. 464 vbNo .......................................... 308 vbNormal .................................. 510 vbNormalFocus ......................... 509 vbNormalNoFocus .................... 509 vbNull ........................................ 467 vbObject ............................ 467, 469 vbOk .......................................... 308 vbOkCancel ............................... 307 vbOkOnly .................................. 307 vbProperCase ............................ 464 vbQuestion ................................ 307 vbReadOnly............................... 510 vbRetryCancel ........................... 308 vbSaturday ................................ 471 vbSet .......................................... 504 vbShortDate............................... 499 vbShortTime .............................. 499 vbSingle .................................... 467 vbString ..................................... 467 vbSunday ................................... 471 vbSystem ................................... 510 vbTextCompare ................. 459, 515

Page 537: Laborator Baze date

531

vbThursday ................................ 471 vbTrue ....................................... 498 vbTuesday ................................. 471 vbUnicode ................................. 464 vbUpperCase ............................. 464 vbUseCompareOption ....... 459, 515 vbUseDefault ............................. 498 vbUserDefinedType .................. 467 vbUseSystem ............................. 471 vbVariant ................................... 467 vbVolume .................................. 510 vbWednesday ............................ 471 vbWide ...................................... 464 vbYes ......................................... 308 vbYesNo .................................... 308

vbYesNoCancel......................... 308 vertical tab ................................. 463 w 470, 492 Weekday .................................... 477 WeekdayName .......................... 477 White ......................................... 519 Width # ...................................... 514 ww ..................................... 470, 493 y 470, 493 Year ........................................... 478 Yellow ....................................... 519 Yes/No ...................................... 490 yy 493 yyyy .................................... 470, 493