Developing Time-Oriented Database Applications in SQL THE MORGAN KAUFMANN SERIES IN DATA MANAGEMENT SYSTEMS Series Editor, Jim Gray Developing Time-Oriented Database Applications in SQL Richard T. Snodgrass Joe Celko's Data and Databases: Concepts in Practice Joe Celko Web Farming for the Data Warehouse Richard D. Hackathorn Database Modeling & Design, Third Edition Toby J. Teorey Management of Heterogeneous and Autonomous Database Systems Edited by Ahmed Elmagarmid, Marek Rusinkiewicz, and Amit Sheth Object-Relational DBMSs: Tracking the Next Great Wave, Second Edition Michael Stonebraker and Paul Brown with Dorothy Moore A Complete Guide to DB2 Universal Database Don Chamberlin Universal Database Management: A Guide to Object/Relational Technology Cynthia Maro Saracco Readings in Database Systems, Third Edition Edited by Michael Stonebraker and Joseph M. Hellerstein Understanding SQL's Stored Procedures: A Complete Guide to SQL/PSM Jim Melton Principles of Multimedia Database Systems V. S. Subrahmanian Principles of Database Query Processing for Advanced Applications Clement T. Yu and Weiyi Meng The Object Database Standard: ODMG 2.0 Edited by R. G. G. Cattell and Douglas K. Barry Advanced Database Systems Carlo Zaniolo, Stefano Ceri, Christos Faloutsos, Richard T. Snodgrass, V. S. Subrahmanian, and Roberto Zicari Principles of Transaction Processing Philip A. Bernstein and Eric Newcomer Using the New DB2: IBM's Object-Relational Database System Don Chamberlin Distributed Algorithms Nancy A. Lynch Active Database Systems: Triggers and Rules For Advanced Database Processing Edited by Jennifer Widom and Stefano Ceri Joe Celko's SQL for Smarties: Advanced SQL Programming Joe Celko Migrating Legacy Systems: Gateways, Interfaces, & the Incremental Approach Michael L. Brodie and Michael Stonebraker Database: Principles, Programming, and Performance Patrick O'Neil Atomic Transactions Nancy Lynch, Michael Merritt, William Weihl, and Alan Fekete Query Processing for Advanced Database Systems Edited by Johann Christoph Freytag, David Maier, and Gottfried Vossen Transaction Processing: Concepts and Techniques Jim Gray and Andreas Reuter Understanding the New SQL: A Complete Guide Jim Melton and Alan R. Simon Building an Object-Oriented Database System: The Story of O2 Edited by François Bancilhon, Claude Delobel, and Paris Kanellakis Database Transaction Models for Advanced Applications Edited by Ahmed K. Elmagarmid A Guide to Developing Client/Server SQL Applications Setrag Khoshaan, Arvola Chan, Anna Wong, and Harry K. T. Wong The Benchmark Handbook for Database and Transaction Processing Systems, Second Edition Edited by Jim Gray Camelot and Avalon: A Distributed Transaction Facility Edited by Jeffrey L. Eppinger, Lily B. Mummert, and Alfred Z. Spector Readings in Object-Oriented Database Systems Edited by Stanley B. Zdonik and David Maier Developing Time-Oriented Database Applications in SQL RICHARD T. SNODGRASS Morgan Kaufmann Publishers San Francisco, California Senior Editor Director of Production & Manufacturing Production Editor Editorial Coordinator Cover Design Cover Illustration Text Design Technical Illustration Composition Copyeditor Proofreader Indexer Printer Diane D. Cerra Yonie Overton Edward Wade Belinda Breyer Ross Carron Design Michael Bloomenfeld, AEC Mark Ong, Side By Side Studios Cherie Plumlee Ed Sznyter, Babel Press Ken DellaPenta Jennifer McClain Steve Rath Courier Corporation Chapter opener art based on illustrations from the following sources: Chapters 1, 12, and 13 from Brackin, A. J., Clocks: Chronicling Time, Encyclopedia of Discovery and Invention, Lucent Books, 1991; Chapters 2, 3, 4, 5, and 6 from Woodward, P., My Own Right Time: An Exploration of Clockwork Design, Oxford University Press, 1995; Chapters 7, 8, and 9 from Britton, F. J., The Escapements: Their Action, Construction, and Proportion, Geo. K. Hazlitt & Co., reprinted by Arlington Book Co, 1984; and Chapters 10 and 11 from Headrick, M. V., Clock and Watch Escapement Mechanics, self-published, 1997. Designations used by companies to distinguish their products are often claimed as trademarks or registered trademarks. In all instances where Morgan Kaufmann Publishers is aware of a claim, the product names appear in initial capital or all capital letters. Readers, however, should contact the appropriate companies for more complete information regarding trademarks and registration. Morgan Kaufmann Publishers Editorial and Sales Ofce 340 Pine Street, Sixth Floor San Francisco, CA 94104-3205 USA Telephone 415-392-2665 Facsimile 415-982-2665 Email mkp@mkp.com WWW http://www.mkp.com Order toll free 800-745-7323 c 2000 by Morgan Kaufmann Publishers All rights reserved Printed in the United States of America 04 03 02 01 00 5 4 3 2 1 No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher. Library of Congress Cataloging-in-Publication Data. Snodgrass, Richard T. Developing time-oriented database applications in SQL / Richard T. Snodgrass. p. cm. Includes bibliographical references. ISBN 1-55860-436-7 1. SQL (Computer program language) 2. Database design. I. Title. QA76.73.S67S56 2000 005.75'6–dc21 99-14298 CIP Á Merrie Ce jour, et toujours Mach' es wie die Sonnenuhr Zähl' die heiteren Stunden nur Do like the sundial: Count only the bright hours — German proverb Foreword by Jim Gray Microsoft Research Precise clocks were developed so that seafarers could nd their longitude. Precise temporal data techniques were recently developed to help database designers record and reason about temporal information. It is paradoxical that we are only now coming to understand how to think about time and represent it in formal systems. After all, time is the fourth dimension; it is at the core of existence. Yet, it is only recently that we have come to understand the fundamental concepts of instants, intervals, periods, sequenced changes, valid time, transaction time, and a bitemporal view of information. Richard Snodgrass and his colleagues have explored temporal data concepts over the last two decades. They now have a fairly complete solution to the problems. Indeed the concepts are now being added to the SQL language standard. This book summarizes their work and presents it in a very accessible and useful way. Temporal databases, viewed from this modern perspective, are surprisingly simple and powerful. The book gives examples of 85-line SQL programs that collapse to 3-line programs when the new concepts are applied. It introduces the concepts using concrete examples and conventional SQL. I found this mix of theory and practice very instructive and very easy to follow. The book explains that temporal databases can be designed in two steps. First, the static database can be designed. Then, in a second pass, each table and constraint is given its temporal attributes. This makes design much more tractable. This approach is made all the more attractive by the fact that the temporal SQL language extensions are just modiers to standard queries and updates—this very elegant approach makes temporal issues orthogonal to the other language issues. I highly recommend this book to anyone interested in temporal data—either designing and building databases that record information over time, or just understanding the concepts that underlie representing temporal information. This book does an excellent job of organizing and summarizing this important area. Foreword by Jim Melton Oracle Corporation It's about time—time that a book like this was written and time that the SQL community got the benets of the careful analysis and thought put into the subject. Rick Snodgrass is one of the relatively few researchers in the eld of temporal databases and has proved himself to be one of the more important of those few, in part because he insists on applying the theoretical knowledge gained from his research to practical applications and to real products. Snodgrass proposed in 1992 that temporal extensions to SQL be developed by the temporal database community. In response to this proposal, a virtual committee was formed to design extensions to the 1992 edition of the SQL standard (ANSI X3.135.-1992 and ISO/IEC 9075:1992); those extensions, known as TSQL2, were developed during 1993 by this committee meeting only via email. In late 1993, Snodgrass rst presented this work to the group responsible for the American National Standard for Database Language SQL, ANSI Technical Committee X3H2 (now known as NCITS H2). In response to Snodgrass's presentation, X3H2 proposed to the International Organization for Standardization (ISO) that the project to extend the standard for SQL be enhanced by adding a subproject for temporal extensions to the language. This proposal was accepted in 1994, and an initial document for ISO/IEC 9075-7, known as SQL/Temporal, was started. Over the next two years, a series of proposals from Snodgrass and others were considered by the ISO group responsible for SQL (ISO/IEC JTC1/SC21/WG3, later ISO/IEC JTC1/SC32/WG3), but progress was slowed considerably by the need to focus on what has recently been published as SQL:1999. Work will undoubtedly resume on progressing SQL/Temporal in 1999 for publication early in the next millennium, and Snodgrass will no doubt play a signicant role in its standardization. x FOREWORD BY JIM MELTON The book you hold has been a long time in the making, not only because the subject matter can seem overwhelmingly complex if not presented carefully, but also because of the great number of examples that Snodgrass has taken from real application systems and translated into standard SQL and its proposed extensions. (Of course, not all of the examples can be used in all SQL products today; some of them are directed toward specic vendors' systems, while others depend on future extensions to the language.) The result of that care and extensive use of examples is great clarity and focus, yielding ready comprehension to readers willing to give the book the attention it deserves. I recommend this book very highly to all SQL practitioners, especially those with an interest in the temporal semantics of data. Contents Foreword by Jim Gray vii Foreword by Jim Melton ix Preface xvii 1 Introduction 1 1.1 1.2 1.3 1.4 1.5 A Triad of Triples 2 The SQL Standard 4 Conventions 5 Implementation Considerations 7 Readings 8 2 Fundamental Concepts 11 2.1 2.2 2.3 2.4 2.5 Valid-Time State Tables 12 Transaction-Time State Tables 18 Bitemporal Tables 20 Summary 22 Readings 23 3 Instants and Intervals 25 3.1 3.2 Instants 26 Intervals 30 xii CONTENTS 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 Predicates 33 Constructors 36 Implementation Considerations 42 The Year 2000 Problem* 63 Subtleties* 74 Implementation Considerations* 83 Summary 84 Readings 85 4 Periods 89 4.1 4.2 4.3 4.4 4.5 4.6 Literals 90 Predicates 90 Constructors 93 Implementation Considerations 97 Summary 108 Readings 108 5 Dening State Tables 111 6 Querying State Tables 143 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 5.10 6.1 6.2 Initial Schema 112 Adding History 113 Temporal Keys 117 Handling Now 119 Uniqueness Reexamined 121 Referential Integrity 126 Constraint Attributes* 131 Implementation Considerations 132 Summary 139 Readings 140 Extracting the Current State 143 Extracting Prior States 145 CONTENTS 6.3 6.4 6.5 6.6 6.7 6.8 Sequenced Queries 145 Nonsequenced Variants 156 Eliminating Duplicates 158 Implementation Considerations 169 Summary 173 Readings 174 7 Modifying State Tables 177 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 Current Modications 177 Sequenced Modications 188 Nonsequenced Modications 197 Modications That Mention Other Tables* 198 Temporal Partitioning* 206 Implementation Considerations 213 Summary 215 Readings 216 8 Retaining a Tracking Log 219 9 Transaction-Time State Tables 253 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10 8.11 9.1 9.2 Dening the Tracking Log 220 Queries 222 Modications 229 Permitting Insertions 230 Backlogs 233 Using After-Images Consistently 235 Transaction Semantics* 240 Renements* 243 Implementation Considerations 244 Summary 248 Readings 250 Denition 254 Maintenance 255 xiii xiv CONTENTS 9.3 9.4 9.5 9.6 9.7 9.8 Queries 259 Temporal Partitioning* 262 Vacuuming* 268 Implementation Considerations 272 Summary 273 Readings 275 10 Bitemporal Tables 277 11 Temporal Database Design 343 10.1 10.2 10.3 10.4 10.5 10.6 10.7 10.8 10.9 11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 11.10 Denition 278 Modications 282 Queries 307 Integrity Constraints 323 Temporal Partitioning* 329 Vacuuming* 337 Implementation Considerations 339 Summary 339 Readings 340 Properly Sequencing the Design 343 Conceptual Design 345 Logical Design 355 Physical Design 375 Advanced Design Aspects* 377 Benets 382 Application Development 383 Implementation Considerations 396 Summary 397 Readings 397 CONTENTS 12 Language Directions 401 12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9 12.10 12.11 12.12 12.13 12.14 12.15 12.16 SQL-92 401 SQL-92 Limitations 401 SQL3 402 Periods 403 Dening Valid-Time State Tables 406 Querying State Tables 411 Modifying State Tables 416 Retaining a Tracking Log 421 Transaction-Time State Tables 426 Bitemporal Tables 427 Capstone Case 437 Migration 446 Additional Constructs of SQL3* 455 Implementation Considerations 457 Summary 460 Readings 465 13 Prospects 469 Glossary 471 Bibliography 479 Author Index 485 Subject Index 487 About the Author 502 About the CD-ROM 503 xv Preface This is how it goes. We develop a database application, and initially the project proceeds smoothly enough. There are alternatives to weigh during the schema design, problems to contend with while writing the SQL code, and constant reconguration and interaction with other programs and legacy data, but all in all the project is under control. Then we decide that one of the tables needs another DATE column, recording when the row was valid. (After all, we added a birth date column a few weeks ago, with no surprises.) So we rework the part of the application that maintains that table, noticing that the code is getting more complicated. During testing, we discover that the primary key no longer is sufcient. We add the DATE column to the primary key, acknowledging that this is only a stopgap measure, and hope that the input data will be well formed, as there isn't time to write code that checks those constraints properly. In the back of our mind is the lingering doubt that perhaps referential integrity checking isn't working quite right either. We soon realize that we need another DATE column to record when the row was no longer valid. In doing so we encounter a raft of off-by-one bugs, in which some less-than comparisons should have been `<=', and other places where we need to add “+ 1 DAY”. We think we've found all the code locations that need to be changed, but we're not sure. And we now know for a fact that the primary and foreign keys are wrong, but we don't know how to even approach that mess. The code to modify the database is becoming increasingly convoluted. Each modication has to at least consider changing the DATE columns, but it isn't at all clear how to approach such changes in a systematic fashion. And even the most trivial queries, such as “Who was Aaron's manager when he worked on the Capital account?”, which before we could code in our sleep, now become painful to even contemplate writing in SQL. Around this time, users start complaining that reports aren't consistent, that copies of the end-of-the-year summary have different numbers in them. Looking xviii PREFACE into this anomaly, we nally gure out that the reports were run at different times, and the data had been changed in the meantime. We then realize that there is no way to correlate the end-of-the-year report with the cash ow report, unless they are run at the same time. Users are adopting an irreverent view of these reports: if you wait a few days, maybe the numbers will x themselves. To address the inconsistencies in the reports, someone suggests a quick x: add another DATE column. The development group responds with astonishment and chagrin. How can we possibly get the code working with another DATE column, when we all know how much work resulted from adding the previous column? In fact, some in the group despair of ever getting the code as is, with just two DATE columns, working correctly—there are just too many arbitrary decisions, each layered on other equally ill-motivated quick xes. Looking back on the history of the development process, everyone has a vague idea that the problems started when that pesky DATE column was rst added. How could one column ummox the whole system? And why do some columns, such as the birth date column, slide in smoothly, and other DATE columns cause no end of problems? A PARADIGM SHIFT Thomas Kuhn, in his insightful and highly inuential book, The Structure of Scientic Revolutions [64], argued that science does not proceed in a linear, monotonic accumulation of knowledge, but rather exhibits intellectually jarring discontinuities, as radical ideas become the established world view, replacing the now-discredited prior conceptual foundation. Two decades of research into temporal databases have unequivocally shown that a time-varying table, containing certain kinds of DATE columns, is a completely different animal than its cousin, the table without such columns. Effectively designing, querying, and modifying time-varying tables requires a different set of approaches and techniques than the traditional ones taught in database courses and training seminars. Developers are naturally unaware of these research results (and researchers are often clueless as to the realities of real-world applications development). As such, developers often reinvent concepts and techniques with little knowledge of the elegant conceptual framework that has evolved and recently consolidated, and researchers continue to conceal this framework with overly formal prose, never bothering to make the connection with existing tools at hand. This book is an attempt to recast the insights from some 1600 papers in the research literature into terms usable by those brave SQL application coders working in the trenches. These concepts are integrated with the state-of-the-art approaches utilized by forward-thinking developers, as showcased in the case studies that form the bulk of the book. The result is, to use Kuhn's phrase, a paradigm shift in how WHAT TO READ xix we think about time-varying data. This shift impacts how such tables are specied, how they are maintained, and how they are queried. PREREQUISITES I assume you are comfortable with the SQL query language. This book is not a primer on that language, though I do cover the temporal data types and temporal constructs of SQL-92 in depth. There are many excellent books that serve as introductions to SQL. It helps if you have implemented an application involving time-varying data, if only to realize rsthand how difcult and confusing such a project can be, and thus to appreciate the degree to which the approach presented here helps clear out the undergrowth and achieve an elegant and unfettered design. One chapter assumes familiarity with the entity-relationship model; the rest of the book focuses solely on the relational model. The conceptual tools introduced here are in a specic and fundamental way extensions of existing strategies, so everything you've learned until now (well, almost everything) will be useful in this brave new world. The hardest part, for which I'll provide careful guidance, is to jettison the notion that this DATE column “is just another column.” Operating under the old assumptions unhappily doesn't work, as project after project after project has shown. Paradigm shifts are always scary, but the benets are there for those willing to make the jump. WHAT TO READ The best way to understand the principles of time-varying applications and their expression in SQL is to work through a series of tangible examples. By examining the design issues that arise and the kinds of constraints, queries, and modications that we wish to express in implementing these specic applications, you will gain an appreciation of the abstract principles at play. For this reason, the bulk of this book is comprised of case studies. Each case study sets the stage with a discussion of the application domain, which includes oil eld records, cattle location information, and cadastral data. The relevant tables are introduced, followed by a discussion of the design, querying, and modication of these (time-varying) tables. While the applications and the people mentioned in the case studies all exist, the specic SQL examples have been tailored to bring out the issues under discussion. The case studies were easy to locate. It seems that most database applications involve time-varying data. Indeed, applications that are inherently not temporal are about as prevalent as the proverbial hen's teeth. In fact, the only places you xx PREFACE encounter nontemporal examples are in books and seminars, a phenomenon that unintentionally emphasizes the inherent complexity of time-varying applications. To understand the fundamental concepts, you are encouraged to read all the chapters, even if you aren't an oil eld engineer or a veterinarian. Each case study brings out a new category of temporal data, with its unique characteristics and demands. In fact, by studying other elds, you are relieved of the minutiae of your current environment. By studying a foreign language or culture, a deeper understanding of your own language or culture often follows as an additional, or even sometimes primary, benet. After you have read the book, a productive approach to address a new set of requirements is to ask, To which case study is the application under development most closely related? Then the relevant code fragments can be customized to the problem at hand. A few sections are marked with an asterisk to indicate advanced material. Feel free to skip these sections on a rst, or even second, reading. CASE STUDIES Betting the book's categorization as nonction, the people and their situations are as described herein. The specics of their solutions to the problems presented by time-varying data have been adapted to better illustrate general approaches that I wish to emphasize. Most of the SQL code was written by use for the book, but it is reminiscent of that appearing in the actual applications. In the discussion, I have attempted to not oversimplify. Much of the complexity inherent in these applications is cleverly hidden in the details, and any realistic solution must ultimately confront the enterprise in all its glory and intricacy. CD-ROM The included CD-ROM contains the code fragments implemented in a variety of commercial systems, including IBM DB2 Universal Database (UDB), Ingres, Informix–Universal Server, Microsoft Access, Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL. While these code fragments have been tested, the author and the publisher make no claims as to the suitability or correctness of these code fragments. Also included are versions of some of the systems discussed in Chapter 12. ERRORS I would appreciate hearing about any errors that you nd in the book, as well as receiving any other constructive suggestions you may have. (I'd especially like to hear ACKNOWLEDGMENTS xxi of better ways to write individual code fragments.) Please email your comments to the author at snodgrass@mkp.com. ACKNOWLEDGMENTS The specic content of this book, as well as its overall composition, came about through collaboration with my dear friend and colleague Christian S. Jensen, who has assembled and directs the world's strongest temporal database research group at the University of Aalborg in Denmark. He is present on every single page, looking over my shoulder, probing, clarifying, generalizing, exemplifying. While the words in this book are mine (well, except for “exemplifying,” which is denitely one of his words!), the ideas are jointly ours, comingled with the contributions of the many authors discussed in the “Readings” sections. Research is primarily an excuse to play with ideas, and concepts provide opportunities to interact on a deep level with others. Much of the joy I have experienced in this crazy business has directly or indirectly involved Christian, whether in the heady probing of trying to get at core truths, or in appreciating the shimmering simplicity of the resulting insights that, once uncovered, are in retrospect obvious. Many others helped with the case studies, tested the code fragments, read drafts of this book, and offered nontechnical sustenance. Cheryl Bach, Jim Barnett, Nigel Corbin, Brad De Groot, Jens Gadgaard, and Chris Janton were generous with their time in explaining the details of their applications, which provided the impetus for the case studies. I thank Anindya Datta, Igor Viguier, and the Department of Information Systems at the University of Arizona for access to the Sybase DBMS. Cliff Leung from IBM, Paul Brown from Informix, Nick Kline and Goetz Graefe from Microsoft, Ra Ahmed from Oracle, and Jack Reid from UniSQL Customer Support Services provided help with their respective DBMS products. I appreciate comments on the manuscript from Ra Ahmed, John Bair, Paul Brown, Jim Gray, Brad De Groot, Jeff Gross, Robert Brett Gulledge, Christian S. Jensen, and Dennis Shasha. Jim Melton went above and beyond the call of duty in providing two detailed reviews of the entire manuscript. Amad Arsalan, Scott Calvert, Wen-Ke Chen, Brad De Groot, Alvin Gendrano, Bruce Huang, Vijaykumar Immanuel, Jie Li, Wei Li, Giedrius Slivinskas, Helen Thomas, Brad Traweek, and Inés F. Vega-López provided corrections to the code fragments. Alan Brucks provided information on the year 2000 problem. I thank the following people who created the content of the CD-ROM: HTML templates (Christopher Cooper, Jose Alvin Gendrano, Rachana Shah, and Jian Yang), data types: IBM DB2 UDB (Brad Traweek and Giedrius Slivinskas), Informix– Universal Server (Jason Cox and Anand Wagle), Ingres (Wen-Ke Chen), Microsoft Access (Inés F. Vega-López, Lincoln Turner, and Ze-Yuan Zou), Microsoft SQL Server xxii PREFACE (Inés F. Vega-López and Giedrius Slivinskas), Sybase SQLServer (Robert Brett Gulledge and Miltos Vaadis), Oracle8 Server (Christopher Cooper and Jose Alvin Gendrano), and UniSQL (Qing Yan); valid-time state tables: IBM DB2 UDB (Vijaykumar Immanuel and Giedrius Slivinskas), Informix–Universal Server (Jason Cox), Microsoft Access (Ahmad Arsalan and Inés F. Vega-López), Microsoft SQL Server (Inés F. Vega-López and Giedrius Slivinskas), Sybase SQLServer (Wenmin Chen), Oracle8 Server (Jose Alvin Gendrano, Bruce Huang, and Wei Li), and UniSQL (Lincoln Turner and Carlos Ugarte); temporal join and coalescing: Access (Yuji Nishimura, Dhumil Sheth, and Lincoln Turner), IBM DB2 UDB (Jie Li and Kristin Tolle), Oracle8 Server (Jose Alvin Gendrano), and Sybase SQLServer (Sameer Verkhedkar and Xianjin Yang); tracking logs: IBM DB2 UDB (Helen Thomas and Giedrius Slivinskas), Microsoft SQL Server (Inés F. Vega-López and Giedrius Slivinskas), Sybase SQLServer (Yi-Jin Shi), Oracle8 Server (Scott Calvert and Wei Li), and UniSQL (Rachana Shah); transaction-time state tables: Microsoft SQL Server (Inés F. Vega-López and Giedrius Slivinskas) and Oracle8 Server (Scott Calvert and Wei Li); bitemporal tables: Oracle8 Server (Scott Calvert and Wei Li); the capstone case: Oracle8 Server (Wei Li); T IME DB: Andreas Steiner; T IGER: Michael Böhlen; Synchrony: John Bair, Hollis Chin, and Michael Soo; and the white papers: W. L. A. Derks, Heidi Gregersen, Christian S. Jensen, Leo Mark, Janne Skyt, and Jeroen Wijnands. Jian Yang superbly assembled all the les into a coherent and consistent whole. I also appreciate the support over the years from the National Science Foundation, recently via grants IRI-9632569 and ISI-9817798, and from AT&T Corporation, DuPont Corporation, IBM Corporation, and NCR Corporation, which enabled the research that provides the foundation for this book. My editor, Diane Cerra, was wonderful throughout the involved process of writing and producing this book. I especially appreciate her constant quest for quality. I've written for several editors and publishers, and Diane and Morgan Kaufmann are by far the most author- and book-friendly. The design of this book is considerably more complex than that of my other books. Edward Wade worked closely with me on this design. Although I would not have thought it possible, Edward cared as much as I did about getting the design just so, putting his heart into the project. The design feels right, and Edward deserves most of the credit. Edward, it was truly a joy to work with you. Finally, I thank my wife, Merrie, and my two children, Eric and Melanie, for continually emphasizing by their example that life is so much more than book writing. They provided delightful distractions—how could I resist rambling through the park, or reading a poem by Shel Silverstein, or helping out on a pinewood derby car? One of the oft-unexpected benets of taking photographs, whether as a hobby or as a profession, is that you see more vividly. The veins within a fallen leaf become all-absorbing, and shadows on a building are suddenly profound and evocative. My experience in writing this book has been similar, in that the words I have been fortunate to encounter in my reading and listening have particularly ACKNOWLEDGMENTS xxiii resonated with me. During the course of the last two years, I have enjoyed the unwitting companionship of many ne writers, of books and of music, including Beth Nielsen Chapman, Mary Chapin Carpenter, Iris DeMent, Louise Erdrich, Nanci Grifth, Stephen Jay Gould, Lucy Kaplansky, Barbara Kingsolver (a fellow Tucsonan!), William Langewiesche, Alison Moore (another Tucsonan), Ron Querry (Tucson is blessed with accomplished writers), Anna Quindlen, Dava Sobel, Dar Williams, and Lucinda Williams. Their prose and poetry has enriched and sustained me on this at times arduous yet ultimately gratifying journey. My hope is that our paths continue to cross. CHAPTER 1 Introduction I t was “as if you red a 15-inch naval shell at a piece of tissue paper and the shell came right back and hit you.” Thus Ernest Rutherford described his astonishment at the result of his undergraduate student's experiment in 1911. The experiment was a simple one: expose thin foils of gold to particles and watch for appreciable scattering. The then-current model of matter was that it was a “bunch of electrons and some nondescript smeared out jelly of positive charge.” The particle weighs some 8000 times more than an electron, yet was unexpectedly deected by the jelly. This observation led to a radical change in our conception of matter, resulting in the Rutherford atom, a tight nucleus surrounded by orbiting electrons. The scattering of particles and waves such as X rays provides much information on the inner structure of matter. Diffraction patterns are stunningly beautiful in their regularity, reecting in a highly indirect fashion the ordering of atoms of the crystalline solids (such as TaSe2 , shown in Figure 1.1) exposed to the beam. These patterns can be analyzed to understand this geometric structure and other properties. Indeed, much of what is known about the structure of solids is due to analysis of diffraction patterns. Such a study was critical, for example, in understanding the spiral staircase of DNA's double helix. The diffraction patterns are emphatically not magnications of the crystalline structure; rather, the various distances and angles of the blips can be translated back via sophisticated calculations to the unseen lining up of atoms stuck in a three-dimensional gridlock. Only by understanding the phenomenon of diffraction of wave motion, and the impact of a periodic array of barriers on the impinging wave, can physicists accurately orient the atoms and piece together the underlying pattern. An SQL table containing dates and times also exhibits a pleasing regularity, with dates in one column recurring in other rows in another column, and the dates in many rows marching forward almost in lockstep. This regularity is indeed sugges- 2 CHAPTER ONE: INTRODUCTION Figure 1.1 Electron diffraction pattern of TaSe2 . (Image reprinted, by permission, from Structural and Chemical Analysis of Materials, Figure 11.5(b), by J.P. Eberhart. c 1991 John Wiley & Sons, Ltd.) tive of an inner structure, which SQL so effectively masks. Only by understanding the ways in which time-varying behavior can be modeled, and by studying the mapping of this information into tabular form, can an SQL table in a time-varying application be effectively designed, queried, and maintained. 1.1 A TRIAD OF TRIPLES It is human nature to differentiate, to tease apart, to contrast. Identifying dichotomies, partitioning into two mutually exclusive groups, seems to be a fundamental strategy for contending with diversity. We favor black and white, this and that, us and them, over shades of grey, a spectrum of possibilities, a global community. We stereotype ourselves and others and all things by membership in identied groups: plant or animal, minority or majority, right or wrong. Logic and libraries emphasize the distinction between true (nonction) and false (ction). Much of the prevalence of computers in today's society derives from the clarifying simplicity of strings of just two values, 0 and 1, encoding everything from names to the relative strength of a chess conguration. As prevalent as this binary structure is, a collection of three items of similar import seems to resonate even deeper. While a division into two parts is appealing in its reductionism and simplicity, a trichotomy is attractive precisely because it is 1.1 A TRIAD OF TRIPLES 3 not either-or. A triad cannot be reduced to black and white, but is forever resigned to contain ambiguity and complexity. Three-level logics embrace the value of “unknown.” The Greeks viewed the world as comprising the earth, the sea, and the sky (heaven). Christians rejoice in the Trinity; they also speak of earth, heaven, and hell. In Buddhism, there are the three roots of evil: lust, hatred, and delusion. Many religions differentiate the mind, the body, and the soul. Pythagoras celebrated the triangle, the simplest geometric gure. We perceive three spatial dimensions. Rainbows are combinations of three primary colors. Many governments are partitioned into three branches, for a similar reason that a stool has three legs. The harmonic basis of Western music is a chord of three tones consisting of a root with its third and fth. A literary trilogy carries with it a satisfying completeness. In this book we examine how to implement a time-varying application in the SQL structured query language. We focus on three sets of orthogonal concepts:    Temporal data types Kinds of time Temporal statements These concepts are encountered in every time-varying application. If SQL adequately supported these concepts, our task, and yours in actually developing the application, would have been much easier: just use SQL in the appropriate fashion to bring forth the desired behavior. Despite the near universality of time and the time-varying nature of the enterprise being modeled—a static and unmalleable conguration is rare and uninteresting—SQL quite frankly does a lousy job in capturing those aspects that are changing in time, or in providing constructs to effectively model, query, or modify such information. Instead, you, the application developer, are saddled with the task of transforming these concepts into something that SQL can deal with. This book will emphasize the best way to think about timevarying data and will show with many examples how to map these concepts into a temporally unfriendly SQL. Each of these concepts itself consists of three orthogonal elements. There are three fundamental temporal data types:    Instant: something happened at an instant of time (e.g., “now,” which happens to be June 29, 1998, 4:06:39 P. M ., when I am writing this, or sometime, perhaps much later, when you are reading this) Interval: a length of time (e.g., three months) Period: an anchored duration of time (e.g., the fall semester, August 24 through December 18, 1998) SQL-92 includes support for instants and intervals, though in places it confounds the two. Most DBMS products, though, only support instants, with intervals being 4 CHAPTER ONE: INTRODUCTION simulated with integers or oating-point numerics. Periods are always left to the application developer to simulate using supplied data types. There are three fundamental kinds of time. We'll dene more precisely and illustrate these terms shortly, in the next chapter.    User-dened time: an uninterpreted time value Valid time: when a fact was true in the modeled reality Transaction time: when a fact was stored in the database These kinds of time are orthogonal: a table can be associated with none, one, two, or even all three kinds of time. Understanding each kind of time and determining which is present in an application is absolutely critical. We will characterize each in detail. SQL-92 has rudimentary support only for user-dened time; the language provides no help whatsoever with the other two types of time. That is left for you to manage, manually, in your application. We'll see exactly how to do so. There are three basic kinds of time-oriented statements:    Current: now Sequenced: at each instant of time Nonsequenced: ignoring time The trichotomy applies equally well to queries, modication statements, views, and integrity constraints. The most useful is sequenced, for which SQL-92 provides absolutely no help. In fact, getting SQL to express a sequenced statement is often quite painful, yet that is usually what is required by the application. We will show exactly how to write all three kinds of statements. SQL-92 provides some support for nonsequenced statements; current statements are again entirely up to the programmer. So, the several hundred pages of this book attempt to convey three sets of three orthogonal concepts, most of which SQL is woefully ignorant. Those notions foreign to SQL must be transformed from their clean, crisp manifestation into an often baroque expression in SQL. To add to the challenge, no DBMS supports the SQL standard in its entirety; instead, there are infuriating inconsistencies and substitutions each vendor has chosen to impose on its users. We help you navigate these treacherous waters, and avoid the ever-present shoals. 1.2 THE SQL STANDARD SQL is actually a series of standards. SQL-86 included no temporal data types, even though some commercial implementations in the late 1980s did support such data types. SQL-89 added support for referential integrity; no temporal data types were 1.3 CONVENTIONS 5 added. Several temporal data types were introduced in SQL-92: DATE, TIME, TIMESTAMP, and INTERVAL. SQL3 is currently in draft form (and has been so for several years; the path from draft to nal accepted standard is a ponderous one). Portions of SQL3 are expected to be approved as a standard in late 1999. Part 7, SQL/Temporal, introduced a new constructor, PERIOD. In this book, “SQL” refers to SQL-92, and “SQL/Temporal” refers to this draft part of SQL3. We emphasize facilities currently available in database products, but also mention features on the horizon. 1.3 CONVENTIONS In the case studies, for each kind of query (modication, assertion, constraint, view), the general principle behind the query is discussed. For some complex queries, pseudocode may be provided. Following the pseudocode, a particular query is given as a code fragment. Notable features of the query are then examined. Code fragments are often referenced later in the discussion. The references are abbreviated as, for example, CF-1.1. Important points are emphasized as pull quotes (those pieces of information set off from text and extending into the page margins). As an illustration of the stylistic conventions used throughout this book, consider (conventional) queries of the form “. . . at least one . . .”—for example, “Which manager makes less than at least one of their subordinates?” This query must nd a suitable subordinate for each manager listed. Such queries can be written with an EXISTS or IN subquery. “At least one” queries can be easily stated using an additional correlation name in the FROM clause. Code Fragment 1.1 Which managers make less than at least one of their subordinates? SELECT DISTINCT EID FROM Employee AS M WHERE EXISTS ( SELECT * FROM Employee AS E WHERE E.Mgr = M.EID AND E.Salary > M.Salary ) While this query in some ways parallels the English version, the effect can be more easily obtained by augmenting the FROM clause and the WHERE clause. “At least one” queries Mention the table providing the sought-after entity in the FROM clause. Reference that table in the WHERE clause to locate the entity. Here, the sought-after entity is a subordinate (in the Employee table). 6 CHAPTER ONE: INTRODUCTION Code Fragment 1.2 Which managers make less than at least one of their subordinates (without using EXISTS)? SELECT DISTINCT M.EID FROM Employee AS M, Employee AS E WHERE E.Mgr = M.EID AND E.Salary > M.Salary The nested correlation name has been moved up to the main FROM clause, resulting in a more succinct query, a process termed “decorrelation.” A stylized image of an escapement (the critical component of a mechanical clock) is displayed on the opening page of each chapter in this book. Such clocks have an escape wheel connected to a weight (such as in a grandfather clock) or a coiled spring (such as in a wristwatch). The escape wheel, which is connected by gears to the hands of the clock, would spin continuously if not retarded by the escapement, which periodically stops and releases the escape wheel. Over the last 500 years, horologists have devised all manner of ingenious escapements. Examples include Arnold's chronometer escapement, Bond's gravity escapement, Brocot's pin pallet escapement, Congreve's extreme detached escapement, the Debaufre escapement, Froment's electrical escapement, Graham's dead-beat escapement, Grimthorpe's gravity escapement (used in Big Ben), Harrison's grasshopper escapement, and the very early verge and foliot escapement, some of which are illustrated in the chapter openers. Interspersed throughout the case studies will be brief sidebars on a multitude of calendars and on the fascinating alchemy of art, science, and engineering that charCalendars acterizes the development of increasingly accurate clocks through the ages. The clock Calendars are mankind's way of contending with descriptions are accompanied by a stylized years and lunar months composed of a noninte“sun” icon, the calendar descriptions by a gral number of days. As Stephen Jay Gould so elo“moon” icon. quently writes “If God were Pythagoras in Galileo's Finally, each chapter ends with a secuniverse, calendrics would never have become an tion on implementation considerations, intellectual subject at all. The relevant cycles for identifying ways in which commercial sysnatural timekeeping would all be nice, crisp, easy tems deviate from the standard and promultiples of each other.. . . But God, thank goodviding adaptations of the chapter's code ness, includes both Loki and Odin, the comedian fragments that will run on these systems. and the scholar; the jester and the saint. God did A nal section, Readings, provides pointnot fashion a very regular universe after all. And we ers that elaborate on the material in that poor sods of his image are therefore condemned chapter and in the clock and calendar sideto struggle with calendrical questions till the cows bars, indicating the correspondence to the come home.” [35, p. 134] sidebars with the sun and moon icons, respectively. 1.4 IMPLEMENTATION CONSIDERATIONS 7 Gnomonics Man's rst subdiurnal clock was most likely his shadow: when it started getting longer, the day was half over. The next advance was to substitute a gnomon, or staff of known length whose shadow can be measured (gnomon is a Greek word for “pointer”). Obelisks at town centers, which provide a more accurate designation of noon, by virtue of their height, were used in Egypt by around 1450 B . C . E . for the measurement of time and the construction of calendars, thereby signaling the beginning of the science of sundials, or gnomonics. In the third century B . C . E ., a Chaldean priest by Figure 1.2 Berossos's hemispherium. (From Rohr, R. R. J., Sundials: History, Theory, and Practice. Dover Publications, NY, 1996.) 1.4 the name of Berossos hollowed out a half-sphere in a rectangular block of stone, positioned a gnomon in the center, and inscribed lines dividing the arc of the shadow into 12 hours, in accordance with the 12 constellations crossed successively by the sun, the zodiac (Figure 1.2). This hemispherium was the rst sundial to measure hours. Berossos then realized that the bottom half of the sphere was never used, so he removed this useless portion, resulting in the lighter and thus more portable hemicyclium (Figure 1.3). Figure 1.3 Berossos's hemicyclium. (From Rohr, R. R. J., Sundials: History, Theory, and Practice. Dover Publications, NY, 1996.) IMPLEMENTATION CONSIDERATIONS The SQL code for the fragments is almost entirely in standard SQL-92 (any exceptions will be clearly noted). Unfortunately, due to the noncompliance of all existing DBMSs, a few of these fragments run on no existing platform. Hence, each case 8 CHAPTER ONE: INTRODUCTION study concludes with a discussion of how the general approach can be applied to various specic DBMSs, including IBM DB2 Universal Database (UDB), Informix– Universal Server, Microsoft Access and Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL. Each of these products supports a different variant of SQL, introducing limitations that must be worked around and extensions that can be exploited. Each also implements the various constructs in SQL differently, so an approach that is impractical on one product may be the preferred one on another product. The included CD-ROM contains the code fragments implemented on one or more DBMSs. The specic versions on which the fragments were tested were IBM DB2 UDB; Informix–Universal Server 9.12; Microsoft Access 95, Access 97, and Access 2000; Microsoft SQL Server 6.5 and 7.0; Sybase SQLServer 10; Oracle8 Server; and UniSQL. However, because vendors work very hard to ensure their products are upward compatible, these fragments can be expected to continue to apply in future versions of these systems. The descriptions of the specic DBMSs parallel each other, so each can be read independently of the rest. Indeed, it is expected that you will be using only one DBMS; the material on the other products may be safely skipped. 1.5 READINGS The ofcial designation of SQL-86 is American National Standards Institute (ANSI) X3.135-1986 and International Organization for Standardization (ISO) 9075-1987, “Database Language SQL.” This standard, at 110 pages, is relatively brief. SQL-89 is ANSI X3.135-1989 and ISO/IEC 9075:1989; this language added referential integrity. In addition, ANSI published X3.168-1989, “Database languages— Embedded SQL,” which made specications for embedding SQL in conventional programming languages normative (required); ISO chose not to publish an analogous standard. SQL-92, which does have normative embedding, is ANSI X3.1351992 and ISO/IEC 9075:1992, “Database languages SQL” [44]. Melton and Simon provide a comprehensive, readable presentation of SQL-92, including a thorough explanation of the SQL standardization process (Jim Melton is the editor of the SQL standards) [71]. The standard itself is a precise, though soporic 580 pages. In 1995 ISO standardized ISO/IEC 9075-3:1995, “Database languages—SQL– Part 3: Call-Level Interface”; the next year, ISO/IEC 9075-4:1996, “Database languages—SQL–Part 4: Persistent Stored Modules,” appeared. These were originally considered parts of the draft SQL3 specication, but were standardized before the core part of that language. There is also a 150-page “Database language SQL—Technical Corrigendum 3” that provides (mostly minor) corrections and disambiguations to SQL-92, Part 3, and Part 4 [19]. 1.5 READINGS 9 SQL3 is an evolving document, with 10 parts, two of which have achieved standardization, as just mentioned. The core portions of the language, SQL/Framework (Part 1), SQL/Foundation (Part 2), SQL/CLI (Call Level Interface: Part 3), SQL/PSM (Persistent Stored Modules: Part 4), and SQL/Bindings (Host Level Bindings: Part 5) are nearing the FDIS ballot stage, when the SQL committees of the member countries will vote on the question of whether the specication is ready to be an international standard. SQL/Temporal (Part 7) will not go into balloting until the next millennium. SQL/Foundation by itself is 850 pages; together all 10 parts of this specication exceed a back-straining 2000 pages. A page maintained by Keith Hare (www.jcc.com/sql stnd.htm) is a central source of information about the SQL standard. The information available there includes the current status of the standard, information about the standards committees and the standards process, and pointers to other standards pages. Eisenberg and Melton provide a crisply written overview of database standards [29]. Ernest Rutherford, whose model of the atom constituted an essential step toward our current understanding of matter, did not receive the Nobel Prize for that contribution, only because he had already received this ultimate recognition some three years earlier in 1908, at the ripe old age of 37, for his work with radioactive elements and X rays. The context of these experiments is ably described by Abraham Pais (who provides the second quote in the rst paragraph of this chapter) in his superb biography of the Danish physicist Neils Bohr [77, p. 123]. Bohr rened and extended Rutherford's model to arrive at our current understanding (which is often called the “Bohr atom”), attaining the Nobel Prize in 1922, also at the age of 37. Rutherford's undergraduate student, Henry G. J. Moseley, subsequently used Rutherford's model, Bohr's theory, and his own X-ray diffraction studies to understand the periodic table of the elements in terms of atomic numbers. Stephen Jay Gould has written a delightful and highly recommended monograph entitled Questioning the Millennium: A Rationalist's Guide to a Precisely Arbitrary Countdown. “If we regard millennial passion in particular, and calendrical fascination in general, as driven by the pleasure of ordering and the joy of understanding, then this strange little subject. . . becomes a wonderful microcosm for everything that makes human beings so distinctive, so potentially noble, and often so actually funny” [35, pp. 157–158]. René Rohr's Sundials: History, Theory, and Practice provides just that: a fascinating 2500-year chronology, a readable explication of the mathematics behind sundial design, and sage advice on positioning the gnomon and drawing the arcs [80]. Along the way, 51 photographs and over 100 gures illustrate the myriad forms sundials have taken over this period. CHAPTER 2 O V E R V I E W We wend our way through the fundamen- tion. These concepts will be examined in depth, tal concepts of time-varying database applica- along with their expression in SQL, in subsetions via our rst case study, temporarily skirt- quent chapters. ing the complexities of the actual implementa- Fundamental Concepts T hey started getting sick in early June of 1997. Some just had a bad stomachache; others had severe cramping and were passing blood. They suffered from a potentially lethal strain of the bacterium Escherichia coli (O157:H7). By mid-August some dozen-odd cases, all in Colorado, were traced back to a processing plant in Columbus, Nebraska. The plant's operator, Hudson Foods, eventually recalled 25 million pounds of frozen hamburger to attempt to stem the outbreak. That particular plant processes about 400,000 pounds of hamburger daily. Ironically, this plant had received high marks for its cleanliness and adherence to federal food-processing standards. What led to the recall of about one-fth of the plant's annual output was the lack of a database that could track the patties back to the slaughterhouses that supply carcasses to the Columbus plant. It is believed that the meat was contaminated in one of these slaughterhouses, but without such tracking, all were suspect. Put simply, the lack of an adequate time-varying database cost Hudson Foods $25 million. Dr. Brad De Groot is a veterinarian working in Clay Center, Nebraska, about 60 miles southeast of Columbus. He is interested in improving the health maintenance of cows on their way to your freezer. He hopes to establish the temporal relationships between putative risk factor exposure (e.g., a previously healthy cow sharing a pen with a sick animal) and subsequent health events (e.g., the healthy cow later succumbs to a disease). These relationships can lead to an understanding of how disease is transferred to and among cattle, and ultimately to better detection and prevention regimes. As input to this epidemiologic study, Brad is collecting data from commercial feed yard record-keeping systems to extract the movement of some 55,000 head of cattle through the myriad pens of large feedlots in Nebraska. 12 2.1 CHAPTER TWO : FUNDAMENTAL CONCEPTS VALID-TIME STATE TABLES It's present everywhere, but occupies no space. We can measure it, but we can't see it, touch it, get rid of it, or put it in a container. Everyone knows what it is and uses it every day, but no one has been able to dene it. We can spend it, save it, waste it, or kill it, but we can't destroy it or even change it, and there's never any more or less of it. —Jespersen and Fitz-Randolph, From Sundials to Atomic Clocks In a feed yard, cattle are grouped into “lots,” with subsets of lots moved from pen to pen. One of Brad's tables, the LOT LOC table, records how many cattle from each lot reside in each pen of each feed yard. The full schema for this table has nine columns; we'll just consider a few of them. Brad wishes to capture the history of which cattle were coresident, to study how disease moves from cow to cow. He adds two columns, FROM DATE and TO DATE, to this table: LOT LOC(LOT ID NUM, PEN ID, HD CNT, FROM DATE, TO DATE) These two columns will enable many interesting queries to be expressed (some of considerable intricacy), while enormously complicating previously innocuous constructs such as primary and foreign keys. These columns render the table a “validtime state table”: it records information valid at some time in the modeled reality, and it records states, that is, facts that are true over a period of time. The FROM DATE and TO DATE columns delimit the “period of validity” of the information in the row. The “temporal granularity” of this table is a day. The rst three columns are integer columns. The last two columns are of type DATE. SQL supports three kinds of instants, DATE, TIME, and TIMESTAMP, which differ in their range of values (e.g., DATEs range over 9999 years, whereas TIMEs range over only 24 hours) and their temporal granularity (a day for DATE and a second for default TIMEs). Chapter 3 covers these and the INTERVAL data types in all their glory (and grubbiness). The last two columns denote the starting instant (actually, the starting day) of the period of validity of the row and the terminating instant of the period of validity. Unfortunately, SQL-92 does not support periods, so the period of validity must be implemented with two delimiting instants. Chapter 4 lists the various ways periods can be implemented with the data types that SQL does provide, and the operations (predicates and constructors) that may be applied to periods. Table 2.1 records the movement of three lots of cattle in the feed yard. In this table we see that 17 head of cattle were in pen 1 for 11 days, moving inauspiciously 2.1 VALID-TIME STATE TABLES 13 Table 2.1 The LOT LOC table. LOT ID NUM PEN ID HD CNT FROM DATE TO DATE 137 219 219 219 219 374 1 1 1 2 2 1 17 43 20 23 43 14 1998-02-07 1998-02-25 1998-03-01 1998-03-01 1998-03-14 1998-02-20 1998-02-18 1998-03-01 1998-03-14 1998-03-14 9999-12-31 9999-12-31 off the feed yard on February 18 (SQL-92 DATE literals are expressed as year-monthday). Also, 14 head of cattle from lot 374 are still in pen 1 (we use “forever” to denote currently valid rows), and 23 head of cattle from lot 219 were moved from pen 1 to pen 2 on March 1, with the remaining 20 head of cattle in that lot moved to pen 2 on March 14, where they still reside. Without the timestamp columns (FROM DATE and TO DATE), the primary key of LOT LOC is the pair (LOT NUM ID, PEN ID), which can be informally expressed as “the (lot identier, pen identier) pair is unique to a single row.” With the timestamp columns, this can be generalized to “at any point in time, the (lot identier, pen identier) pair is unique to a single row.” It is unfortunate that SQL's PRIMARY KEY construct is inadequate for valid-time state tables; expressing this manifest constraint in SQL-92 requires a complex assertion, as will be shown in Chapter 5, which covers all manner of denitional requirements of valid-time state tables. 2.1.1 Queries Queries over conventional tables ask, “What is?” Queries over time-varying tables can be placed in three broad classes. For each conventional (nontemporal) query over a table without these two DATE columns, there exist “current” (“What is now?”), “sequenced” (“What was, and when?”), and “nonsequenced” (“What was, at any time?”) variants over the corresponding valid-time state table. Consider the nontemporal query “How many head of cattle from lot 219 in feed yard 1 are in each pen?” The current analog over the LOT LOC valid-time state table is “How many head of cattle from lot 219 are (currently) in each pen?” For such a query, we only are concerned with currently valid rows, and we need only to add a predicate requesting such rows. This query returns the following result, stating that all the cattle in the lot are currently in a single pen: PEN ID HD CNT 2 43 14 CHAPTER TWO : FUNDAMENTAL CONCEPTS The sequenced variant is “Give the history of how many head of cattle from lot 219 were in each pen.” The result (Table 2.2) provides the requested history. We see that lot 219 moved around a bit. The nonsequenced variant is “How many head of cattle from lot 219 were, at some time, in each pen?” Here we don't care when the data was valid. Note that the query doesn't ask for totals; it is interested in whenever a portion of the requested lot was in a pen. Table 2.3 shows the result. Nonsequenced queries are often awkward to express in English, but can sometimes be useful. As another example, consider the nontemporal query “Which lots are coresident in a pen?” Such a query could be a rst step in determining exposure to putative risks. Indeed, the entire epidemiologic investigation revolves around such queries, which turn out to be notoriously difcult to express in SQL-92. The current version, “Which lots are currently coresident in a pen?”, will return the empty table when evaluated on Table 2.1, as none of the lots are currently coresident (lots 219 and 374 are currently in the feed yard, but in different pens). The nonsequenced variant is “Which lots were in the same pen, perhaps at different times?” The result is Table 2.4: all three lots had once been in pen 1. Note however that at no time were any cattle from lot 137 coresident with either of the other two lots. To determine coresidency, the sequenced variant is used: “Give the history of lots being coresident in a pen.” This requires the cattle to actually be in the pen together, at the same time. The result of this query on Table 2.1 is the following: L1 L2 PEN ID FROM DATE TO DATE 219 374 1 1998-02-25 1998-03-01 As we will see in Chapter 6, current and nonsequenced queries are relatively easy to express in SQL, but sequenced queries, which are prevalent, are surprisingly arduous. That chapter provides many examples to illustrate how such queries are phrased in SQL. 2.1.2 Modications Modications (that is, insertions, deletions, and updates) comprise the bulk of many applications and are challenging when applied to time-varying data. We'll illustrate modications on the LOT table, which captures the gender of the cattle in each lot. Surprisingly (especially to the cattle!), the gender attribute is time-varying. As an aside on terminology, a “bull” is a male bovine animal (the term also denotes a male moose). A “cow” is a female bovine animal (or a female whale). A “calf” is the young of a cow (or a young elephant). A “heifer” is a cow that has not yet borne a calf (or a young female turtle). “Cattle” are collected bovine animals. 2.1 VALID-TIME STATE TABLES 15 Table 2.2 The history of lot 219. PEN ID HD CNT FROM DATE TO DATE 1 1 2 2 43 20 23 43 1998-02-25 1998-03-01 1998-03-01 1998-03-14 1998-03-01 1998-03-14 1998-03-14 9999-12-31 Table 2.3 Result of a nonsequenced query. PEN ID HD CNT 1 1 2 2 43 20 23 43 Table 2.4 Result of another nonsequenced query. L1 L2 PEN ID 137 137 219 219 374 374 1 1 1 A “steer” is a castrated male of the cattle family. To steer an automobile or a committee is emphatically different from steering a calf. Cows and heifers are not steered, they are “spayed,” or generically, neutered, rendering them a “neutered cow.” There is no single term for neutered cow paralleling the term “steer,” perhaps because spaying is a more invasive surgical procedure than steering, or perhaps because those doing the naming are cowboys. Bulls are steered to reduce injuries to themselves (bulls are quite aggressive animals) as well as to enhance meat quality. Basically, all that ghting reduces glycogen in the muscle bers, which increases the water content of the meat, which results in less meat per pound. Heifers are spayed only if they will feed in open elds, because calving in the feed yard is expensive and dangerous to the cow. Figure 2.1 illustrates the transitions in gender that are possible, all of which are irreversible. (And you thought that this book was going to be about databases!) Capturing the (time-varying) gender of cattle is important in epidemiological studies, for the gender can affect disease transfer to and between cattle. Hence, in Brad's feed yard database schema, LOT is a valid-time state table. 16 CHAPTER TWO : FUNDAMENTAL CONCEPTS Figure 2.1 Gender transitions. A slice of the LOT table is shown in Table 2.5 (in this excerpt, we've omitted several columns not relevant to this discussion). The GNDR CODE is an integer code. For expository purposes, we will use single letters, with c indicating the lot consists of bull calves, h indicating the lot are heifers, and s indicating the lot are steers. The FROM DATE and TO DATE in concert specify the time period over which the values of all the other columns of the row were valid. In this table, on March 23, 1998, a rather momentous event occurred for the cattle in lot 101: they were steered. Lot 234 consists of calves; a TO DATE of forever denotes a row that is currently valid. Lot 234 arrived in the feed yard on February 17; lot 799 arrived on March 12. Brad collects data from the feed yard to populate his database. In doing so he makes a series of modications to his tables, including the LOT table. As with queries, there are three general classes of modications: current, sequenced, and nonsequenced. “Lot 433 arrives today” is a current insertion. “Lot 101 leaves the feed yard today” is a current deletion. The two modications in concert result in Table 2.6. All information on lot 234 after today has been deleted. (As this is being written on January 13, 1999, “today” is shown in SQL as 1999-01-13, exposing the nonlinear fashion in which this book evolved.) “The cattle in lot 799 are being steered today” is a current update, with the result shown in Table 2.7. A current modication applies from “now” to “forever.” A sequenced modication generalizes this to apply over a specied period, termed the “period of applicability.” This period could be in the past, in the future, or overlap “now.” “Lot 426, a collection of heifers, was on the feed yard from March 26 to April 14” is a sequenced insertion. “Lot 234 will be absent from the feed yard for the rst three weeks of October, when the steering will take place” is a sequenced deletion. 2.1 VALID-TIME STATE TABLES 17 Table 2.5 The LOT table. LOT ID NUM GNDR CODE FROM DATE TO DATE 101 101 234 799 c s c c 1998-01-01 1998-03-23 1998-02-17 1998-03-12 1998-03-23 9999-12-31 9999-12-31 9999-12-31 Table 2.6 Result of a current insertion and deletion. LOT ID NUM GNDR CODE FROM DATE TO DATE 101 101 433 234 799 c s c c c 1998-01-01 1998-03-23 1999-01-13 1998-02-17 1998-03-13 1998-03-23 9999-12-31 9999-12-31 1999-01-13 9999-12-31 Table 2.7 Lot 799 was steered today. LOT ID NUM GNDR CODE FROM DATE TO DATE 101 101 433 234 799 799 c s c c c s 1998-01-01 1998-03-23 1999-01-13 1998-02-17 1998-03-12 1999-01-13 1998-03-23 9999-12-31 9999-12-31 1999-01-13 1999-01-13 9999-12-31 A sequenced update is the temporal analog of a nontemporal update, with a specied period of applicability. “Lot 799 was steered only for the month of March” is a sequenced update. (Something magical happened on April 1. The idea here is to show how to implement sequenced updates in general, and not just on cattle.) As with queries, a nonsequenced modication treats the timestamps identically to the other columns and often mentions the period of validity of the rows to be deleted. An example is “Delete the records of lot 234 that have duration greater than three months.” Most modications will be rst expressed as changes to the enterprise being modeled (some fact becomes true, or will be true sometime in the future; some aspect changes, now or in the future; some fact is no longer true). Such modications are either current or sequenced modications. Nonsequenced modications, while generally easier to express in SQL, are rare. 18 CHAPTER TWO : FUNDAMENTAL CONCEPTS Chapter 7 shows that current and nonsequenced modications are not that hard to express in SQL, but sequenced modications, which are often the most useful, are doggedly obstinate, almost to the point of intractability. In that chapter we provide abundant guidance on the care and feeding of modications of time-varying tables. 2.2 TRANSACTION-TIME STATE TABLES The LOT LOC and LOT tables capture the history of reality. The rst row of Table 2.6 says that had we checked the cattle in lot 101 anytime during the rst three months of 1998, we would have seen that they were calves. Brad's database also includes the LOT CONTAINS table, with the following schema (again, we omit mention of some of the columns): LOT CONTAINS (LOT ID NUM, BKP ID, A NAME) The primary key of this table is LOT ID NUM, so at any time, this value uniquely identies one row, which records the backup identier and application name for that lot. Brad copies the les from the feed yard system, then later processes the information. The LOT CONTAINS table stores for each lot the backup le from which the current information on that pen was extracted. Because this data tends to be dirty, containing inconsistencies and omissions, Brad would like to track the information in the LOT CONTAINS table. In particular, he would like to reconstruct its state at any date in the past. He adds two columns, a START DATE indicating when that row was rst inserted into the table, and a STOP DATE indicating when that row was updated or deleted. We should emphasize that rows are logically deleted, because physically deleting old rows would prevent past states from being reconstructed. A table that can The Tropical Year be reconstructed as of a previous date is termed a “transaction-time state table,” as The earth orbits around the sun, requiring a tropical it captures the transactions applied to the year to return to the same point in space, which table. has been measured to take 365.2422 days. The fact As Table 2.8 shows, a row concerning that the tropical year is not an exact multiple of lot 101 was rst inserted on January 1, days, or even a simple fractional multiple of days, 1998. The BKP ID was incorrect, and so such as 365 41 , has caused all manner of difculty in was changed on February 5 from 17 to designing calendars. Calendars are expected to be 18. A row concerning lot 433 was inserted synchronized with both the rising of the sun and on January 13 and is still considered to the seasons, and sometimes with the waxing and be correct (as signaled by a STOP DATE of waning of the moon. “forever”). 2.2 TRANSACTION-TIME STATE TABLES 19 Table 2.8 The LOT CONTAINS table. LOT ID NUM BKP ID A NAME START DATE STOP DATE 101 101 433 17 18 23 ADE ADE SMP 1998-01-01 1998-02-05 1998-01-19 1998-02-05 9999-12-31 9999-12-31 While Tables 2.5 and 2.8 both have two DATE columns, the interpretation of these columns is dramatically divergent. Valid-time tables capture a history of reality, while transaction-time tables capture a history of the changing state of a table. We cannot ask the LOT table what its state was three days ago, but we can ask the LOT CONTAINS table that question. Similarly, we cannot ask the LOT CONTAINS table what was true in reality three days ago, but we can ask the LOT table that question. While any row of the LOT table may change, as we correct mistakes about the captured history, the LOT CONTAINS table grows monotonically, with old rows remaining unchanged in perpetuity. The most relevant query on a transaction-time state table is to reconstruct a past state. “Provide the state of the LOT CONTAINS table on January 12, 1998” yields the following result: LOT ID NUM BKP ID A NAME 101 17 ADE Note that the BKP ID for lot 101 was (erroneously) thought to be 17 on that Monday, and lot 433 hadn't yet arrived. Now we ask, “Provide the state of the LOT CONTAINS table on February 12, 1998,” with the following result: LOT ID NUM BKP ID A NAME 101 433 18 23 ADE SMP The BKP ID for lot 101 is now the correct value of 18. Only current modications are permitted on transaction-time state tables, as past states cannot be changed. Modications must permit subsequent reconstructions. The modication “Correct the backup identier for lot 433 to 37” produces the result shown in Table 2.9. Chapters 8 and 9 discuss transaction-time tables in detail, emphasizing various representations, some requiring only one timestamp column. 20 CHAPTER TWO : FUNDAMENTAL CONCEPTS Table 2.9 The corrected backup identier. LOT ID NUM BKP ID A NAME START DATE STOP DATE 101 101 433 433 17 18 23 37 ADE ADE SMP SMP 1998-01-01 1998-02-05 1998-01-19 1999-01-13 1998-02-05 9999-12-31 1999-01-13 9999-12-31 Table 2.10 The LOT bitemporal table. 2.3 LOT ID NUM GNDR CODE FROM DATE TO DATE START DATE STOP DATE 101 234 799 101 101 c c c c s 1998-01-01 1998-02-17 1998-03-12 1998-01-01 1998-03-23 9999-12-31 9999-12-31 9999-12-31 1998-03-23 9999-12-31 1998-01-03 1998-02-17 1998-03-12 1998-03-19 1998-03-19 1998-03-19 9999-12-31 9999-12-31 9999-12-31 9999-12-31 BITEMPORAL TABLES Valid time, capturing the history of a changing reality, and transaction time, capturing the sequence of states of a changing table, are orthogonal, and can thus be separately utilized or applied in concert. A table supporting both is termed a “bitemporal table.” The LOT table is critical to Brad's epidemiological analysis, so he also tracks the changes made to this table. This table already supports valid time; he adds two columns, START DATE and STOP DATE, to capture transaction time. Table 2.10 has four timestamps, betting its bitemporal nature. There is a wealth of information in such tables, if care is taken in reading them. Let's examine this table row by row.    Row 1: On January 3 (the START DATE), the fact that lot 101, a group of calves, arrived in the feed yard two days previously, on January 1 (the FROM DATE), is recorded. The valid time for this fact is January 1 to forever (the TO DATE), indicating that they are expected to remain calves. We'll return to the STOP DATE when we discuss the fourth row. Row 2: On February 17 (the START DATE), the fact that lot 234, also a group of calves, arrived in the feed yard that day (the FROM DATE) is recorded. A STOP DATE of forever indicates that the fact is still considered to be correct. Row 3: On March 12, the fact that lot 799, a group of calves, arrived in the feed yard that day is recorded. 2.3 BITEMPORAL TABLES 21 Table 2.11 The history as known on March 15. LOT ID NUM GNDR CODE FROM DATE TO DATE 101 234 799 c c c 1998-01-01 1998-02-17 1998-03-12 9999-12-31 9999-12-31 9999-12-31 Table 2.12 The history as known on April 1. LOT ID NUM GNDR CODE FROM DATE TO DATE 234 799 101 c c s 1998-02-17 1998-03-12 1998-03-23 9999-12-31 9999-12-31 9999-12-31   Row 4: On Thursday, March 19, unbeknownst to the cattle in lot 101, these cattle were scheduled to be steered early the next week, on Monday, March 23. So we logically update the rst row by setting its STOP DATE to the current date, insert row 4, indicating that lot 101 consisted of calves from January 1 to March 23, and insert row 5. Row 5: On Thursday, March 19, the fact that lot 101 is a collection of steers from March 23 to forever was recorded, and that fact is still considered correct. Since this table supports transaction time, we can reconstruct its state in the past. “Provide the history of the LOT table as best known on March 15, 1998” (the Ides of March, beware!) would generate the result shown in Table 2.11. As of March 15, we hadn't yet scheduled lot 101's steering. “Provide the history as best known on April 1” yields a different result (Table 2.12). Interactions between valid and transaction time are especially interesting, as in “When were steerings scheduled (as opposed to being recorded after the fact)?” which would identify one such steering: LOT ID NUM When Scheduled When Recorded 101 1998-03-23 1998-03-19 As bitemporal tables include transaction time, all modications are transactiontime current. However, we can still provide the period of applicability for modications, as in “Lot 234 will be absent from the feed yard for the rst three weeks of October.” Chapter 10 explores the glorious expressiveness of bitemporal tables, as well as the intricacies of expressing queries and modications on such tables. 22 2.4 CHAPTER TWO : FUNDAMENTAL CONCEPTS SUMMARY This chapter has introduced what we want to do with time-varying tables and has provided a glimpse of how to do them: add one or more timestamp columns. Chapters 3 through 10 furnish the intellectual tools to code applications in SQL over temporal tables. On the inside front cover, a Concept Map provides guideposts for our journey through the triad of triples. In this map, the sections that explicate each concept are listed in italics, following the concept. The three temporal data types—instants, intervals, and periods—are covered rst. Valid-time state tables are the focus of Chapters 5–7. Chapter 5 considers how such tables may be specied in the schema; integrity constraints are used heavily, as the existing SQL constructs of UNIQUE, PRIMARY KEY, and FOREIGN KEY are inadequate for time-varying tables. The three kinds of queries—current, sequenced, and nonsequenced—are the topic of Chapter 6; the analogous kinds of modications are examined in Chapter 7. Chapters 8 and 9 consider transaction-time tables, emphasizing the critical distinction between valid time and transaction time (SQL unfortunately completely blurs this distinction). Chapter 8 considers instant-stamped tables, and Chapter 9 considers period-stamped tables. Chapter 10 introduces bitemporal tables, supporting both valid and transaction time. Again, we delve into the intricacies of dening, querying, and modifying these tables. We then return to Brad's feed yard apHours plication in Chapter 11, as a thorough review of these strategies. Finally, ChapA day is demarcated by a physical change, the ter 12 indicates where future versions of peaking of the sun in the sky, indicating noon. Not SQL are headed vis-a-vis temporal support so for an hour; it is a purely arbitrary division. The and shows that constructs proposed for ancients studied the stars closely and knew that SQL3 offer a dramatic reduction in both the sun crossed 12 constellations: Aquarius, Pisces, the number of lines of SQL code and the Aries, Taurus, Gemini, Cancer, Leo, Virgo, Libra, mental gymnastics required, thereby endScorpio, Sagittarius, and Capricorn. This sequence ing this exploration on an optimistic note. is called the zodiac, from the Greek word zodios, We now have sufcient background to meaning “gure of an animal.” The Chaldeans thus understand the metaphor of the cover ildivided the day (that is, the time between sunrise lustration. The sphere on the cover is maand sunset) into 12 portions, or hours. However, chined in such a way that it projects shadbecause the daylight is shorter in winter than in ows of three different clock faces. The summer, these were considered horae temporariae, sphere represents a fact in a bitemporal or “temporary hours.” table, say, an employee table. The shadow 2.5 READINGS 23 on the left shows the time 10:25 A . M ., indicating that the fact became true in reality (the valid FROM TIME) in midmorning. The shadow on the right shows the time 12:35 P. M ., indicating that the fact was stored in the database (the transaction START TIME) about a half hour after noon. Part of the fact is the time of birth (a user-dened time) of 6:05 P. M . We see that a particular fact in the database may include a user-dened time and may be associated with both a valid time and a transaction time. 2.5 READINGS Other terms have been applied to the valid-time, transaction-time, and bitemporal tables introduced in this chapter. They have been called temporal tables. The term time-varying has been used, but this is a misnomer, as all tables in practice vary over time, as rows are added, removed, and changed. The term time-oriented tables is also not quite precise; just what does it mean to be “time-oriented”? (For that reason, the title of this book is unfortunate. To be honest, I originally preferred Developing Temporal Database Applications in SQL, but felt that title might confuse people who did not know the technical denition of “temporal,” which no longer characterizes you, gentle reader.) Such tables have also been called historical tables, but this implies that they record information only about the past. Valid-time tables often store information about the future, for example, in planning or scheduling applications. The accepted terminology then is to refer to such tables as temporal tables, or more specically as, say, a valid-time table. The ofcial denition of a temporal database is “a database that supports some aspect of time, not counting user-dened time” [49]. The intuition here is that adding a user-dened time column such as birth date to an employee table does not render it temporal, especially since the birth date of an employee is presumably xed and applies to that employee forever. The presence of a DATE column will not a priori render the database a temporal database; rather, the database must record the time-varying nature of the information managed by the enterprise. It is perhaps surprising that the discipline of temporal databases is a very active area within database research. There have been some 1600 (!) papers written about this topic over a 20-year period. The number of papers has been rising exponentially; several hundred now appear each year. Many are included in the most recent bibliography, which has pointers to six prior bibliographies over the past 17 years [105]. Three brief surveys [56, 76, 103] provide entry into this research eld. The most complete exposition, albeit somewhat dated by now, is Tansel et al. [102]; a more recent text provides an updated summary [107]. The cover illustration was inspired in part by the cover of Hofstadter's Gödel, Escher, Bach [40], which showed two pieces of wood carved to project shadows of the letters G, E, and B on the three planes. CHAPTER 3 O V E R V I E W At the core of a temporal application are tem- stant variants and two interval variants) and poral values, indicating when something hap- the operations permitted on these types. The pened. There are three basic temporal types. highly idiosyncratic temporal facilities of prevaInstants and intervals are covered in this chap- lent DBMSs are compared in detail with the ter; periods, which enjoy much less support in SQL-92 standard. The language facilities supmost versions of SQL, are the topic of the next porting temporal values are similar in one way chapter. to assembly language facilities: you can (gener- We examine in depth the variants of in- ally) do what you want, but it is often far from stants and intervals (SQL-92 supports ve in- easy. Instants and Intervals J im Barnett is the quintessential Texan: barrel-chested, sporting a thick mustache, a graduate of the University of Texas, an oil man. His speech has an easy cadence, peppered with humor. He is an engineer for GeoQuest, a data management company owned by Schlumberger, a Paris-based instrumentation company. (This name is of Germanic origin, but is pronounced as a French word.) The oil and gas business is a dynamic, worldwide industry, with its practitioners transferred far and wide, and often. September of 1995 found Jim working in Dubai, U.A.E., 8000 miles from his home base in Houston, Texas, working with the Arabian Oil Company (AOC) to systematize its records on wells and oil and gas production and distribution. Several of his clients are in Al Khafji, a company town immediately south of the Saudi border with Kuwait. Al Khafji saw action in the Gulf War, with the AOC workers leaving scant hours before the town was invaded. Jim helped design the database underlying GeoQuest's F INDER product. F INDER implements the industrial standard Public Petroleum Data Model (PPDM) via some 300 tables on the Oracle DBMS. The enterprise (here, wells, production, land, lithography, and seismic data) must be modeled using the available data types, such as numerics, character strings, and dates. Character strings record the names of things, numerics record the values that have been measured or noted, and dates record the when of things. As this book considers the time-varying nature of data, we focus here on the date columns. F INDER utilizes all manner of dates. Many tables have Start Date and End Date columns, denoting a period of time; we will examine this usage in detail in the next chapter. Other tables have Start Date and Next Event Date columns, recording a succession of events. F INDER also uses other approaches to capture time-varying data. The Fac Daily Prod table tracks daily production of a facility. Each row of this table records a month's worth of production. The PRODUCTION YEAR column (of type NUMBER(4,0)) and MONTH column (of type VARCHAR(3)) denote the particular month, and 31 columns, DAY1 through DAY31, of type NUMBER(12,4), provide the daily production. 26 CHAPTER THREE : INSTANTS AND INTERVALS Duration data is also present in the F INDER schema. In the Well Core Hdr table, the Dry Time column (of type NUMBER(7,2)) and the Dry Time Unit (of type VARCHAR(12)) in concert capture the drying time of the chemical analysis of a well core (a sample extracted from a known depth from the well). Jim found that addressing the AOC requirements involved adding even more date columns. To most tables he added the following columns: Created By, Create Date, Updated By, and Last Update, to track more carefully who effected a change and when the change was made. Other temporal columns were needed by particular tables, such as the Sample Date, Dispatch Date, and Return Date columns of the Well Core Sample table. SQL denes several temporal types for use in columns. Any respectable DBMS provides similar data types, though few compliant with the standard. SQL also provides useful predicates, constructors, and functions for manipulating time values. Again, DBMSs include somewhat similar, though usually incompatible, operators. This chapter summarizes the temporal support that SQL and prevalent DBMSs provide, and shows how to use these facilities to perform common tasks. Jim's task was made easier (or perhaps more difcult) by the fact that Oracle supports but one temporal data type, DATE, of a xed granularity, to a second. This often shifted the decision from which temporal type was best to which other available type, for example, NUMBER, should be used. As in all data modeling, the rst question that must be asked is, What is the semantics, that is, the meaning, of the enterprise to be captured? In this sense, the Dry Time column of the Well Core Hdr table is of a fundamentally different nature than the Core Date column of that table, even if both are to a precision of seconds. And both are fundamentally different than the Start Date and End Date columns. How these columns are typed and correctly manipulated in SQL depends critically on determining their underlying semantics. In this and the next chapter, we examine the different temporal semantics that are available, and explore how Jim made these distinctions when specifying the AOC extensions to the F INDER data model. 3.1 INSTANTS An instant is an anchored location on the time line. An SQL-92 datetime denotes an instant. An instant is an anchored location on the time line. I am writing this on the instant of 2:38 P. M ., January 14, 1997, two days after HAL's birth. (From 2001: A Space Odyssey: “I am a HAL 9000 computer, production number 3. I became operational at the HAL plant in Urbana, Illinois, on January 12, 1997.”) An instant occurs but once, and then is forever in the past. 3.1 INSTANTS 27 This data type is most fundamental. Other types can be implemented by, or simulated to some degree with, instants; indeed, most DBMSs provide no other temporal data types. SQL terms instants datetimes and provides three specic forms and two variations. 3.1.1 The DATE Type An SQL-92 DATE stores the year, month, and day values of an instant. The year value must be in the range 0001 C . E . (Common Era, formerly called A . D .) through 9999 C . E . Note that a DATE value cannot denote B . C . E . (Before the Common Era, formerly called B . C .) dates. While the SQL designers point to some technical issues in justifying this design decision (such as there being no year 0 C . E ., or year 0 B . C . E .), its true rationale may lie in initial use of relational products primarily in administrative data processing rather than in scientic applications. Both uses could have been accommodated much better by centering this 10,000-year range at, say, 1 C . E ., rather than favoring the years 5000 C . E . through 9999 C . E . over B . C . E . dates. The month value is limited to the values 1 through 12, denoting the 12 Gregorian months. The day value is limited to the values 1 through 31, although the month and year value can apply additional restrictions limiting the maximum to 28, 29, or 30. For example, February 29, 1996, is legal, as is February 29, 2000, but February 29, 1900, is not. None of these elds can be negative. This notation is derived from the ISO 8601 standard. Date literals consist of the year as four A D versus B C digits, followed by a hyphen, followed by the month as two digits, followed by a There is no 0 A . D .; 1 A . D . follows 1 B . C . The reahyphen, followed by the day as two digson for this seeming anomaly is that when the its, in descending granularity (thereby prebifurcation into B . C . and A . D . was proposed, by sumably allowing less-than comparisons to a sixth-century monk named Dionysius Exiguus, be implemented via lexicographic comparunder instruction by Pope St. John I, the conisons). HAL's birth date is then DATE 1997cept of zero had not been invented. That epic 01-12. Note that this literal requires 10 event would have to wait several centuries, rst characters. The length of a DATE is specfor Arabic mathematicians to devise the notion ied as 10 positions, which is dened as of zero as a placeholder and as a value unto it“the number of characters from the charself, then for farsighted Pope Sylvester II, reignacter set SQL TEXT that it would take to reping over the last millennial transition from 999 resent any value” in the DATE type. SQL to 1003, to advocate this concept in Western does not prescribe what internal format an usage. implementation employs for such values. . . . . 28 3.1.2 CHAPTER THREE : INSTANTS AND INTERVALS The TIMESTAMP Type Should the user desire a ner precision than day, the TIMESTAMP data type is available in SQL. This variation stores the year, month, and day, as in DATE, along with the hour, minute, and second, and a number of fractional digits of the second. The default is six fractional digits, corresponding to microseconds. None of the elds may be negative. The timestamp's precision, or number of fractional digits, can be specied in parentheses when this data type is used; the precision defaults to 6. A precision of 3 (i.e., TIMESTAMP(3)), indicates a granularity of milliseconds; a precision of 0, seconds; a precision of 15, femtoseconds. The maximum precision is dened by the implementation; a negative precision is not allowed. Twenty-four hour clock time is used, so the hour value ranges from 0 to 23. The minute value ranges from 0 to 59, and the second value from 0 to 61 (more on this shortly). SQL uses Coordinated Universal Time (UTC), based on atomic clocks. The time portion of a timestamp literal is denoted in descending granularity: hour, minute, second, each two digits and separated with colons, followed by a period and fractional digits, if the precision is greater than zero. Hence the present time, as near as I can tell from my watch, is TIMESTAMP 1997-01-15 11:35:29.123456. The length of a TIMESTAMP value is 26 positions (the length includes the period character); the length of TIMESTAMP(0) is 19 positions. 3.1.3 The TIME Type Will there really be a morning? Is there such a thing as day? . . . . . . . . . . . . . Oh, some scholar! Oh, some sailor! Oh, some wise man from the skies! Please to tell a little pilgrim Where the place called morning lies! —Emily Dickinson, “Will there really be a morning?” The SQL TIME data type stores the hour, minute, and second, and a number of optional fractional digits of the second. The default is no fractional digits, corresponding to integral seconds; a nonzero precision is denoted, as with TIMESTAMP, in parentheses. TIME literals are as one would expect: in descending granularity, separated with colons (e.g., TIME 11:35:29). The length of a TIME value is eight positions; if the precision is nonzero, then it is nine positions (for the decimal point) plus the precision. Unlike DATE The SQL-92 datetime types DATE, TIME, and TIMESTAMP differ in the elds (year, month, day, hour, minute, and second) they contain. 3.1 INSTANTS 29 and TIMESTAMP values, TIME values include a zero element: '00:00:00'. As we will see in Section 3.7, and as hinted in Emily Dickinson's poem, TIME is not really an instant data type at all; it is a funny kind of interval (to be discussed below), representing a number (between 0 and 86,400) of seconds (along with optional fractional seconds). 3.1.4 Time Zone Variants Greenwich Mean Time ensures that the sun, on those days it is visible, is directly overhead Greenwich, England, each noon. Locales distant from England, shift UTC by a certain number of hours and minutes so that the sun is approximately overhead locally at noon. Mountain Standard Time subtracts 7 hours from UTC. We would expect 24 time zones, each corresponding to 60 minutes of longitude, but as with all things political, there are many exceptions. Nepal's time zone is 15 minutes off from India's as an expression of independence. Many locales also change the offset, advancing their clocks by one hour in the summer and turning them back in the winter, at specied days. Arizona, unlike the other states in the Mountain Time Zone, does not adopt this adjustment, called daylight saving time, presumably as an expression of independence from the federal government. The Navajo Indian reservation, located within Arizona, does use daylight saving time, perhaps to be different than Arizona. And the Hopi Indian reservation, which is completely surrounded by the Navajo Indian reservation, does not adopt daylight saving time, perhaps to differentiate themselves from the Navajos. So you can drive a few hours in Arizona and go in and out of daylight saving time four times. Each SQL session has an associated default offset from UTC that is used in that session. This offset can range from -12:59 The time zone can be stored to +13:00 (the reason for the additional hour on each side is with SQL-92 TIME and daylight saving time). The offset is assumed for TIME and TIMETIMESTAMP values. STAMP values manipulated within the SQL session. Hence, time literals denote the local time, whereas times are stored as UTC time (with no time zone, i.e., Greenwich Mean Time). The TIME WITH TIME ZONE data type includes with the stored value an explicit offset from UTC. This is written as a sign (the hyphen character for a minus sign, or the plus character) followed by the offset hour as two digits, a colon, and the offset minute as two digits (e.g., TIME 11:08:27-07:00). This added information requires an additional six positions: four digits, a hyphen, and a colon. Fractional seconds appear before the time zone (e.g., TIME 11:08:27.123456-07:00). The TIMESTAMP WITH TIME ZONE data type is also available. Without fractional digits, the length of this type is 25 positions, more with fractional digits. An example is TIMESTAMP 1997-01-15 11:35:29.123456-07:00, requiring 32 positions. 30 3.2 CHAPTER THREE : INSTANTS AND INTERVALS INTERVALS . . . and an ocean tumbled by with a private boat for Max and he sailed off through night and day and in and out of weeks and almost over a year to where the wild things are. —Maurice Sendak, Where the Wild Things Are And which of you by being anxious can add one cubit to his span of life? —Matthew 6:27 An interval is an unanchored contiguous portion of the time line. An interval is relative; an instant is absolute. An interval can be added to an instant, yielding another instant. Intervals cannot be added to spatial points, nor spatial intervals (such as cubits) to temporal intervals, except as (often highly effective) literary devices, as the above quotes illustrate. The distance between two instants is an interval. Unlike instants, intervals have direction. An interval can be positive orThe negative, denoting a shift future or SQL-92 interval typeto the is complex. to the past. Whereas the other SQL types require but a Intervals are less prominent in the few F INDER thanintervals instants. Someover are lines schema to describe, require signaled with “duration” or “interval” in their name, examples being the Period three pages just to specify the syntax. Even Durtn column in Well Test Period and the Sampling Interval column of the(asSeis then, some details are left unstated will Survey Hdr table, or by mentioning the time during which something be discussed in Section 3.7.3). was happening, as in the Time String In Hole columnSQL of differentiates the Well Log Service table. Other year-month intervals interval columns are more obscure, suchand as the Incrmnt Time column of the Stage day-time intervals. The rst can be Flowback table (other columns having considered a name with thatequivalent sufx denote to be to aninstants, integral INDER schema, As e.g., Start Time). It appears that in the Fnumber of yearsallorintervals months;are thepositive. latter conwe'll see, while SQL has an interval type,sidered Oracle8equivalent Server does not support this type, to an integral number of relying on the designer to differentiate instants fromminutes, intervals seconds, in other ways. days, hours, or fractions of a second. This distinction is due to varying month lengths in the Gregorian calen3.2.1 The INTERVAL Type dar. The individual units (months, hours, Solid stone is microseconds) just sand and water, ... are termed granules, so an Sand and water, and interval a millionvalue yearsisgone by integer number a (signed) of granules. —Beth Nielsen Chapman, “Sand and Water” Intervals have a qualier that Intervals are combinations of the elds year, month, day, hour, minute, and second, though not all combinations are species the leading eld, an An interval is an unanchored, directional duration of the time line. optional trailing eld, and an optional precision for the leading and trailing elds. 3.2 INTERVALS 31 Sundials A sundial, or more ostentatiously, a heliochronometer , in contrast to most other clocks, does not measure an interval of time; rather, it indicates a given instant of time. A sundial can be moved to another longitude and remain accurate; a mechanical watch must be reset when moved—hence the presence of multiple time zones on many modern watches. Sundials, when adjusted for the correct latitude, are exceedingly accurate, measuring true solar time (see page 95), at least when the sky is not cloudy. There is no drift with a sundial, unlike mechanical clocks. allowed, as we will see. Intervals have a qualier associated with them that species the leading eld, an optional trailing eld, and an optional precision for the leading and trailing elds. If no trailing eld is present, the interval contains only the leading eld. 3.2.2 Year-Month Intervals For year-month intervals, the only elds available are year and month. Such an interval can contain only years (INTERVAL YEAR), only months (INTERVAL MONTH), or both (INTERVAL YEAR TO MONTH). For the leading or only eld, a precision, specifying the maximum number of digits, is permitted (INTERVAL YEAR(p), INTERVAL MONTH(p), INTERVAL YEAR(p) to MONTH); the precision defaults to two digits and must be positive. Nonleading elds can have up to two digits. Year-month literals are denoted with the year (e.g., INTERVAL 3 YEAR), the month (e.g., INTERVAL 7 MONTH), or the year Year-month intervals contain a followed by a hyphen followed by the month (e.g., INTERVAL year, a month, or both elds. 3-7 YEAR TO MONTH, for three years and seven months). Note that the elds must be specied in literals, but the precision need not be. If years and months are present, then the number of months must be between 1 and 12. The length, in positions, of a year-month interval is the precision of the year eld if alone, the precision of the month eld if alone, or the precision of the year eld plus three, for the hyphen and two digits of the month, if both are present. 32 CHAPTER THREE : INSTANTS AND INTERVALS The hyphen in intervals is not a minus sign; it serves instead to separate eld values. An interval literal can have a sign preceding the quoted portion. A positive interval literal is indicated by the absence of a sign or by a plus sign (e.g., INTERVAL 3-4 YEAR TO MONTH = INTERVAL +3-4 YEAR TO MONTH). A negative interval literal is indicated with a minus sign (a hyphen) preceding the string portion of the literal (e.g., INTERVAL -3-7 YEAR TO MONTH, for three years and seven months going back into the past). The one exception is the zero element, for which positive and negative literals denote the same value: INTERVAL +0-0 YEAR TO MONTH = INTERVAL 0-0 YEAR TO MONTH = INTERVAL -0-0 YEAR TO MONTH. We note in passing that the Technical Corrigendum 3, currently in draft form, permits a sign to also appear within the quoted portion. In fact, two signs can be present, with the normal mathematical interpretation—for example, double negation results in a positive literal. Hence, INTERVAL +3-4 YEAR TO MONTH = INTERVAL +3-4 YEAR TO MONTH = INTERVAL ++3-4 YEAR TO MONTH = INTERVAL --3-4 YEAR TO MONTH = INTERVAL 3-4 YEAR TO MONTH. 3.2.3 Day-Time Intervals The gods confound the man who rst found out How to distinguish hours. Confound him, to, Who in this place set up a sundial, To cut and hack my days so wretchedly Into small pieces! —Plautus (quoted by David S. Landes), Boeotia Day-time intervals may contain up to four elds: day, hour, minute, and second, with optional fractional seconds. All elds between the leading and trailing elds are included. Hence, INTERVAL DAY TO SECOND contains four elds, while INTERVAL DAY TO HOUR contains two elds, and Day-time intervals contain day, hour, minute, and second elds, INTERVAL DAY (or, equivalently, INTERVAL DAY TO DAY) contains only one eld. As with year-month intervals, we can specify a in any contiguous sequence. precision for the leading eld, which defaults to two digits. Examples include INTERVAL DAY(4) TO HOUR, which can represent up to 9999 days, and up to 24 hours; INTERVAL HOUR(3) TO SECOND, which can represent up to approximately 40 days; and INTERVAL MINUTE(4) TO SECOND, which can represent almost a week (within a few minutes), to the granularity of seconds. Day-time interval types and literals are even more complex when seconds are involved because the standard wished to accommodate fractional seconds (no other eld can have a fractional value). If the leading (i.e., only) eld is SECOND, then it can have a precision, which defaults to two digits (e.g., INTERVAL SECOND(8), which can represent three years). (A bit of trivia: there are   107 seconds in a year, to 3.3 PREDICATES 33 an accuracy of greater than 1 in 100.) If the trailing (or only) eld is SECOND, it can also have a fractional precision, which defaults to six (e.g., INTERVAL DAY(3) TO SECOND(3), which represents a count of milliseconds). A single SECOND eld can thus have two precisions, separated with a comma (e.g., INTERVAL SECOND(5,3), which can represent milliseconds up to a little more than a day). Such intervals require nine positions, including the period. Day-time literals are just what you might expect, making the correspondence with timestamp literals (e.g., INTERVAL 1 23:45:12 DAY TO SECOND). In all cases, the length in positions of an interval type is identical to the number of characters required by any literal of that type. 3.3 PREDICATES For such a diverse set of types (DATE, TIME, TIMESTAMP, TIME WITH TIME ZONE, TIMESTAMP WITH TIME ZONE, and two variants of INTERVAL: year-month and day-time), SQL-92 supports only four classes of temporal predicates: equality, lessthan, is null, and overlaps. There are several variants of the equality predicate; these variants apply to all the data types. When applied to two expressions, `=' determines whether the values of these expressions are identical. When applied to a value and a set of values (of the same type), =ANY determines if the left-hand value is identical to at least one of the values in the right-hand set. =SOME and IN are nonorthogonal equivalents. MATCH also relies on equality testing. The queries in CF-3.1 are identical in meaning. Code Fragment 3.1 Seven ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE BirthDate = DATE 1970-01-01 SELECT * FROM Employee WHERE BirthDate =ANY (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE BirthDate =ALL (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE BirthDate =SOME (VALUES ((DATE 1970-01-01))) continued on page 34 34 CHAPTER THREE : INSTANTS AND INTERVALS continued from page 33 SELECT * FROM Employee WHERE BirthDate IN (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE NOT BirthDate NOT IN (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE BirthDate MATCH (VALUES ((DATE 1970-01-01))) Here, VALUES constructs a table with one row consisting of one column. More variations are possible using the UNIQUE and PARTIAL reserved words available with MATCH. (We mention MATCH for completeness. This construct, particularly with its options, is intended for determining whether or not candidate rows would satisfy referential integrity constraints.) In all of the above examples, the two values being compared are of a specic type (DATE). Two datetimes can be compared if they are comparable, which is dened as having the same elds. Intervals are compared by rst converting to a common base granularity, then converting to integers, then doing the integer comparison. So INTERVAL 3-7 YEAR TO MONTH can be compared to INTERVAL 43 MONTH (and in fact these two intervals are equal), while neither of these intervals can be compared with INTERVAL 23 DAY, as the two intervals are incomparable. Since every SQL-92 data type, including the temporal types, is ordered, less-than is dened on them all. The operators `<', `<=', `>', `>=', and `<>' comprise the available combinations. Each combination is a disjunction, OR-ing the two possibilities, so `<=' means “less than or equal to.” The last, `<>', means “less than or greater than,” or equivalently, “not equal to.” Code Fragment 3.2 Four more ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE NOT BirthDate <> DATE 1970-01-01 SELECT * FROM Employee WHERE NOT BirthDate <>ANY (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE NOT BirthDate <>ALL (VALUES ((DATE 1970-01-01))) SELECT * FROM Employee WHERE NOT BirthDate <>SOME (VALUES ((DATE 1970-01-01))) There are yet other ways to test for equality of temporal values in SQL; the following discussion will provide more than a dozen. 3.3 PREDICATES 35 The BETWEEN construct is a useful form of inequality. The predicate value 1 BETWEEN value 2 AND value 3 is equivalent to value 2 <= value 1 AND value 1 <= value 3 Note that the BETWEEN predicate is ordered, in that value 2  value 3 is required. Code Fragment 3.3 Two more ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE BirthDate BETWEEN DATE 1970-01-01 AND DATE 1970-01-01 SELECT * FROM Employee WHERE NOT BirthDate NOT BETWEEN DATE 1970-01-01 AND DATE 1970-01-01 These exploit the fact that equality is allowed on both sides of the BETWEEN. As with other data types, the value of any temporal column can be NULL. And as with other data types, predicates on null temporal values have the value unknown, except for value IS NULL, which returns true when the value is null and false otherwise, and value IS NOT NULL, which naturally returns true if the value is not null. The nal temporal predicate, OVERLAPS, differs from the rest, in that it only applies to temporal values, and then only to values of particular temporal types. As we'll see in Chapter 4, OVERLAPS is a way to get periods in the back door. The format of this predicate is period information 1 OVERLAPS period information 2 Either period information is constructed either via ( start time, duration) or ( start time, end time) where start time and end time are instants, that is, SQL datetimes, and duration is an interval that can be added to start time (we'll cover adding intervals to datetimes in more detail in the next section). These two forms can be mixed and matched at will. The predicate returns true if period information 1 overlaps period information 2 , that is, if they share at least one instant, or, equivalently, if the start of period information 1 is less than the end of period information 2 and the start of period information 2 is less than the end of period information 1 (try it!). By 36 CHAPTER THREE : INSTANTS AND INTERVALS using a zero duration, or identical start and end instants, we can construct periods of one granule, as the following illustrate. Code Fragment 3.4 Yet four more ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE (BirthDate, INTERVAL 0 DAY) OVERLAPS (DATE 1970-01-01, INTERVAL 0 DAY) SELECT * FROM Employee WHERE (BirthDate, BirthDate) OVERLAPS (DATE 1970-01-01, INTERVAL 0 DAY) SELECT * FROM Employee WHERE (BirthDate, INTERVAL 0 DAY) OVERLAPS (DATE 1970-01-01, DATE 1970-01-01) SELECT * FROM Employee WHERE (BirthDate, BirthDate) OVERLAPS (DATE 1970-01-01, DATE 1970-01-01) NULL can be used in either position within a period information; often the predicate will return true (or false) anyway. Code Fragment 3.5 Three more ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE (BirthDate, NULL) OVERLAPS (DATE 1970-01-01, INTERVAL 0 DAY) SELECT * FROM Employee WHERE (BirthDate, NULL) OVERLAPS (DATE 1970-01-01, NULL) SELECT * FROM Employee WHERE (BirthDate, NULL) OVERLAPS (NULL, DATE 1970-01-01) 3.4 CONSTRUCTORS A temporal constructor is an expression that returns a temporal value. (Some might consider a predicate to be a boolean constructor, but we nd it helpful to differentiate predicates and other constructors.) 3.4 CONSTRUCTORS 37 The Gregorian Calendar The Gregorian calendar was necessitated by the fact that a year is not an integral number of days. The tropical year is roughly 365.242191 days, or equivalently, 365 days, 5 hours, 48 minutes, and 45.96768 seconds. (“Nature, apparently, can make a gorgeous hexagon, but she cannot (or did not deign to) make a year with a nice even number of days or lunations” [35, p. 137].) The Julian calendar starts off with 12 months of various lengths that add up to 365 days. It then makes a correction of imposing a leap day every fourth year, as a sequence of 365, 365, 365, 366 days, averaging out at 365.25 days per year. This is pretty close: it makes the year about 11 minutes and 154 seconds longer than it actually is. But 11 minutes a year can add up, and the civil calendar got more and more out of step from the solar calendar. By 1581, the vernal equinox was on April 2, rather than the accepted March 21. So Pope Gregory 3.4.1 XIII appointed a committee, with the Jesuit mathematician Christopher Clavius as chair. His committee came up with two solutions, both imposed by Pope Gregory in a papal bull issued on February 24, 1582. First, to get the civil and solar calendars back in sync, 10 days, October 5 through 14, 1582, were simply dropped—they never existed! Second, the denition of leap years (a year divisible by 4) was amended to not include a century year (multiple of 100), but to still include years divisible by 400. So, every 25th leap year was removed, but every 100th was restored. 1900 is not a leap year, but 2000 is, a fact still misunderstood by some software packages. This yields the Gregorian year to be 365.2425 days long, departing from the solar calendar by some 25.96 seconds: pretty darned close! At this rate, a discrepancy of one day accumulates every 2800 years or so. Datetime Constructors SQL provides seven constructors returning datetimes (DATE, TIME, TIMESTAMP, TIME WITH TIME ZONE, and TIMESTAMP WITH TIME ZONE). We discuss each in turn, after providing an example.     DATE 1996-02-24 + INTERVAL 7 DAY This expression evaluates to DATE 1996-03-02, as 1996 was a leap year. The instant is shifted forward (or back, for negative intervals) by the length of the interval. For expressions involving an interval and a datetime, the interval must contain only elds that are also contained in the datetime. DATE 1996-02-24 + INTERVAL 12:30 HOUR TO MINUTE is thus disallowed, as is DATE 1996-02-24 + INTERVAL 2 12 DAY TO HOUR. INTERVAL 7 DAY + DATE 1996-02-24 This expression also evaluates to DATE 1996-03-02, as addition of intervals and datetimes is commutative. DATE 1996-03-02 - INTERVAL 7 DAY This expression evaluates to DATE 1996-02-24 and is not commutative. TIMESTAMP 1996-02-24 12:34:56 AT LOCAL This expression assumes that the value is expressed in terms of GMT and applies the local time zone offset 38 CHAPTER THREE : INSTANTS AND INTERVALS    to get the local time. As Tucson, Arizona is always at Mountain Standard Time (MST), seven hours behind Greenwich, this evaluates to TIMESTAMP 1996-0224 19:34:56. As another example, TIMESTAMP 1996-02-24 12:34:56+02:00 AT LOCAL takes the Danish TIMESTAMP WITH TIME ZONE, specically, at Mean European Time with daylight saving (MET DST), normalizes it to UTC (i.e., 10:34:56), then applies the Tucson, Arizona time zone offset, yielding TIMESTAMP 1996-02-24 03:34:56. This construct may not be applied to DATE values. If we use a value without specifying an AT clause, AT LOCAL is assumed. TIMESTAMP 1996-02-24 12:34:56 AT TIME ZONE INTERVAL -7:00 HOUR TO MINUTE The expression allows the user to specify a particular time zone offset, which must be an hour to minute interval. It returns TIMESTAMP 1996-02-24 19:34:56. As with the previous example, this construct may not be applied to DATE values. CURRENT DATE returns the current date (the date of the current instant). CURRENT TIME and CURRENT TIMESTAMP function analogously. All such so-called datetime value functions within a statement are effectively performed simultaneously. Such functions appearing in two separate statements are allowed to return different results. CAST(1996-02-24 AS DATE) The CAST function converts a value in a source data type (here, CHARACTER) to the specied target data type. When the target data type (here, DATE) is a temporal type, then the cast may be regarded as a temporal constructor. In this case, the function returns DATE 1996-02-24. While only character strings may be cast to (and from) datetimes in SQL-92, products often extend this to integers and other types. The following types can be converted to a datetime value.   CHARACTER A character string can be converted to a DATE, TIME, or TIMESTAMP value. The string must be identical to a literal of the datetime type. The example above converts a character string to a DATE. CAST(12:34:56 TO TIME) is another example. TIME A time value may be converted to a TIME or TIMESTAMP value, the latter lling in the year, month, and day with the value of CURRENT DATE. If the target type has a time zone, then these elds are set to the current time zone of the session. This is being written on Wednesday, July 23, 1997. CAST(TIME 12:34:56 AS TIMESTAMP WITH TIME ZONE) results in TIMESTAMP 1997-07-23 12:34:56-07:00. If the target has a smaller precision than the source, the additional digits are discarded. If the target has a greater precision than the source, the needed digits are set to 0. Hence, CAST(TIME 12:34:56.123 AS TIME(6)) results in TIME 12:34:56.123000; casting this value to TIME(1) results in TIME 12:34:56.1. 3.4   CONSTRUCTORS 39 TIMESTAMP A timestamp value may be converted to a DATE, TIME, or TIMESTAMP value, by extracting the requested elds and adjusting, if necessary, the precision. Hence, CAST(TIMESTAMP 1997-07-23 12:34:56.123 AS TIME(6)) results in TIME 12:34:56.123000; casting this value to DATE results in DATE 1997-07-23. DATE A date value may be converted into a DATE by simply copying the value or into a TIMESTAMP by setting the hour, minute, and second to 0. CAST(DATE 1997-01-01 AS TIMESTAMP(4)) yields 1997-01-01 00:00:00.0000. Note that when a TIME value is cast to a TIMESTAMP, the current date provides the missing elds, but when a DATE value is cast to a TIMESTAMP, the missing elds are set to zero. 3.4.2 Interval Constructors SQL provides a variety of constructors that return year-month or day-time intervals. We summarize all but the cast function, which warrants closer scrutiny.     INTERVAL 3 DAY + INTERVAL 4 DAY evaluates to INTERVAL 7 DAY. The result is at a precision so that information is not lost and contains the elds of both arguments. Hence, INTERVAL 3 DAY + INTERVAL 4 HOUR yields INTERVAL 3 4 DAY TO HOUR, and INTERVAL 3 DAY + INTERVAL 8 4 DAY TO HOUR yields INTERVAL 11 4 DAY TO HOUR. The SQL-92 semantics treats INTERVAL 3 DAY as exactly 3 days (72 hours). INTERVAL 3 DAY - INTERVAL 4 DAY yields INTERVAL -1 DAY. As with addition, subtraction results in the union of the elds, to the necessary precision. INTERVAL 3 DAY - INTERVAL -8 4 DAY TO HOUR results in INTERVAL 11 4 DAY TO HOUR. (DATE 1997-01-01 - DATE 1996-01-01) DAY yields INTERVAL 366 DAY, as 1996 was a leap year. Note that both the parentheses and a qualier must be specied; this provides the granularity of the result. The subtraction is done at the least signicant eld of the qualier, then the interval is converted to an interval of that eld as the end eld, with a start eld chosen to not lose any information. So (DATE 1997-01-01 - DATE 1996-01-01) YEAR TO MONTH will convert both to months (23,952 and 23,940, respectively, though it turns out the origin doesn't matter), then the difference is taken, resulting in INTERVAL 12 MONTH, then the result is converted to the requested qualier, or INTERVAL 1-0 YEAR TO MONTH. INTERVAL 4 DAY * 3 yields INTERVAL 12 DAY. Multiplication is symmetric; this result is also obtained from 3 * INTERVAL 4 DAY. Multiple elds can be accommodated; the interval is rst converted to a scalar at the smallest eld, then converted back after the multiplication. INTERVAL 12:30 HOUR TO 40 CHAPTER THREE : INSTANTS AND INTERVALS   MINUTE * 3 yields 750 minutes times 3, or 2250 minutes, or INTERVAL 37:30 HOUR TO MINUTE. INTERVAL 4 DAY / 2 yields INTERVAL 2 DAY. This is similar to multiplication, though it is not symmetric. Hence, 2 / INTERVAL 4 DAY is not permitted. - INTERVAL 4 DAY yields, naturally, INTERVAL -4 DAY. Unary plus is also provided: + INTERVAL 4 DAY yields itself. The nal constructor is CAST. Datetimes cannot be cast to intervals, nor intervals to datetimes. In fact, year-month intervals cannot be cast to day-time intervals, nor vice versa. The only casts that result in year-month intervals are from three sources:    CHARACTER As with datetimes, a character string may also be cast to a yearmonth interval, assuming the character string would have been acceptable as a literal. CAST(2 AS INTERVAL MONTH) works, but CAST(3-7 AS INTERVAL MONTH) does not. year-month interval The source interval is rst converted to a scalar in units of the least signicant eld of the target type. For CAST(INTERVAL 8-7 YEAR TO MONTH AS INTERVAL MONTH(2)), the source value would be converted to 103 months. This value is then normalized (a term not dened in the standard) to conform to the target type. If the precision is not sufcient, as here, an exception is raised. As another example, CAST(INTERVAL 3 YEAR AS INTERVAL YEAR TO MONTH), the source value would be converted to 36 months, then normalized to 3 years and 0 months, resulting in INTERVAL 3-0 YEAR TO MONTH. exact numeric Here, the target interval must contain a single eld, YEAR or MONTH. The source value is interpreted as a number of such units. CAST(103 AS INTERVAL MONTH) would evaluate to INTERVAL 103 MONTH; CAST(103 AS INTERVAL MONTH(2)) would raise an overow exception. Similarly, the only casts that result in day-time intervals are as follows:    CHARACTER CAST(2 12:34 AS INTERVAL DAY TO MINUTE) works, but CAST(12:34 AS INTERVAL DAY TO MINUTE) does not. day-time interval As before, the source interval is rst converted to a scalar in units of the least signicant eld of the target type. For CAST(85 23:59:60 AS INTERVAL HOUR TO SECOND), the source value is converted to 7,434,060 seconds. This value is then normalized to conform to the target type, resulting in INTERVAL 2065:00:00 HOUR TO SECOND. Had a target type of INTERVAL HOUR(3) TO SECOND been specied, an overow exception would have been raised. exact numeric Here, the target interval must contain a single eld, DAY, HOUR, MINUTE, or SECOND. The source value is interpreted as a number of such units. To convert an exact numeric to a multield interval, two casts are required. CAST(CAST(7434060 AS INTERVAL SECOND) AS INTERVAL DAY TO SECOND) would evaluate to our original value INTERVAL 86 00:00:00 DAY TO SECOND. 3.4 3.4.3 CONSTRUCTORS 41 Other Constructors Temporal values can also participate in casts to other types. We list these here for completeness:   CAST(DATE 1997-01-01 AS CHARACTER) returns the character string 1997-0101. All temporal types can be cast to xed- or variable-length character strings. CAST(INTERVAL 743060 SECOND AS INTEGER) returns the value 743,060. The source interval must have a single eld. Intervals with multiple elds can be converted to exact numerics via two casts; for example, CAST(CAST(INTERVAL 2064:60:60 HOUR TO SECOND AS INTERVAL SECOND) AS INTEGER) yields the same value. Finally, individual elds can be extracted from datetimes and intervals:     EXTRACT(YEAR FROM DATE 1970-01-01) returns the integer value 1970. EXTRACT(MINUTE FROM INTERVAL 12:34:56 HOUR TO SECOND) returns 34. EXTRACT(TIMEZONE HOUR FROM TIME 12:34:56-07:00) returns -7. EXTRACT(TIMEZONE MINUTE FROM TIME 12:34:56-07:00) returns 0. The last two exemplify new reserved words that were required to obtain these additional elds from datetimes with time zones. Code Fragment 3.6 Yet another four ways to ask for information on those born on January 1, 1970. SELECT * FROM Employee WHERE CAST(BirthDate AS CHAR) = 1970-01-01 SELECT * FROM Employee WHERE CAST(BirthDate AS CHAR) LIKE 1970-01-01 SELECT * FROM Employee WHERE CAST((DATE 1971-01-01 - BirthDate) DAY AS INT) = 365 AND CAST((DATE 1971-01-01 - BirthDate) YEAR AS INT) = 1 SELECT * FROM Employee WHERE EXTRACT(YEAR FROM BirthDate) = 1970 AND EXTRACT(MONTH FROM BirthDate) = 1 AND EXTRACT(DAY FROM BirthDate) = 1 The resulting data type (elds and precision) varies among the operators. Table 3.1 summarizes the cases. Here, d denotes a datetime value, i an interval value, and n a numeric (exact or approximate) value. Union ([) is shorthand for combining the elds of both operands. This table lists all the constructors involving temporal values. 42 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.1 Result type of SQL-92 expressions involving temporal values. Expression d +i i +d d -i d AT LOCAL d AT TIME ZONE i CAST(type 1 AS type 2 ) EXTRACT(field FROM d) CURRENT DATE CURRENT TIME CURRENT TIMESTAMP i1 + i2 i1 - i2 (d - d ) qual i *n n*i i1 / i2 i /n +i -i EXTRACT(field FROM i) 3.5 Result type type of d type of d type of d type of d type of d type 2 n (exact numeric) DATE TIME TIMESTAMP type of i 1 [ type of i 2 type of i 1 [ type of i 2 qual type of i type of i n (integer) type of i type of i type of i n (exact numeric) IMPLEMENTATION CONSIDERATIONS Although temporal types have been in the SQL standard since 1992 and were dened in the mid-1980s, it is surprising, and unfortunate, that unlike other portions of SQL, the types and their predicates and constructors are not supported by most DBMSs. Instead, each vendor has dened an incompatible and idiosyncratic set of temporal types and operators, replete with inconsistencies and seemingly arbitrary design decisions. Temporal types are among No vendor supports SQL-92 at the most variable features of commercial DBMSs. Coupled with the Full SQL level of this is the often poor documentation available from the venconformance. All products dors of temporal features of their products. Determining the opinclude idiosyncrasies in their erations supported on temporal type(s) can be a frustrating extemporal support that render ercise, with the information, if present at all, spread across the porting to other DBMSs difcult. documentation. The following is an attempt to gather in one place the information about temporal support in a few prominent DBMSs. We make no claim for comprehensiveness, but then, neither do most 3.5 IMPLEMENTATION CONSIDERATIONS 43 vendors. Interestingly, only Informix–Universal Server supports a type that provides partial support for intervals; all of the other DBMSs require intervals to be simulated with integers, xed-point, or oating-point numbers. 3.5.1 IBM DB2 Universal Database We start with IBM DB2 Universal Database (UDB), as it is closest to the SQL-92 standard in its support of temporal data types. IBM DB2 UDB supports the DATE, TIME, and TIMESTAMP instant types, with a few deviations from SQL-92. The TIME type has a xed precision of 0, indicating a granularity of seconds. The TIMESTAMP type has a xed precision of 6, indicating a granularity of microseconds. Time zone information is not included in DB2 instant values; however, the current time zone is available in the CURRENT TIMEZONE register. Instant literals are specied as a conversion function of the name of the data type operating on a character string, for example, DATE(1997-01-15) or CAST(1997-01-15 AS DATE), which is preferred, because DATE( ) could be a userdened function. Timestamp literals replace the space between the day and hour with a dash, for example, TIMESTAMP(1997-01-15-11.35.29.123456). There is no INTERVAL data type in DB2 UDB. Instead, DB2 UDB supports specialized versions of the DECIMAL data type, termed durations.    A date duration, in the format YYYYMMDD, is a DECIMAL(8,0) number representing an interval of days, with a range of 10,000 years. A time duration, in the format HHMMSS., is a DECIMAL(6,0) number representing an interval of seconds, with a range of one day. Note that the decimal point is required in a time duration. A timestamp duration, in the format YYYYMMDD.HHMMSSZZZZZZ, is a DECIMAL(20,6) number representing an interval of microseconds, with a range of 10,000 years. These values can be stored in DECIMAL columns and represented by DECIMAL constants. Hence, “DATE(1997-11-08) + 00010101.” adds one year, one month, and one day to the indicated instant, resulting in the date 1998-12-09. DB2 UDB also supports a kind of highly restricted interval literal, termed a labeled duration, which is a numeric expression followed by a time unit (singular or plural). Labeled durations can only be used in an addition or subtraction with an instant type. An example is DATE(1997-11-08) + 1 MONTH. The available units are YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MICROSECOND, and plural versions of these keywords. The function TIMESTAMPDIFF takes two parameters, a code specifying the granularity (e.g., 256 denotes years, 16 denotes days), and a character string that is the result of subtracting two timestamps and converting the result to character form. Note that there are many datetime functions provided. 44 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.2 shows how the facilities in SQL-92 can be simulated, to some degree, in IBM DB2 UDB. In the SQL-92 column, d denotes a datetime value, i an interval value, and n a numeric (exact or approximate) value. In the IBM DB2 UDB column, d denotes a datetime value, i denotes a DB2 timestamp duration, and itype is an integer denoting an interval type. 3.5.2 Informix–Universal Server Informix–Universal Server supports two instant types, DATE and DATETIME, and an interval type, INTERVAL. Time zones are not supported. An Informix DATE is stored internally as an integer denoting the number of dates since December 31, 1899; for example, day 1 is January 1, 1900. DATEs occupy four bytes, so the maximum date is sometime after 5 million C . E . Informix DATE literals are inconsistent with SQL-92; in Informix, the month is rst, followed by the day, followed by the year, all separated with dashes, with the entire string delimited with double quotes. However, an Informix DATE literal only supports two digits, for example, DATE("10/01/98"), with the year 00 being 1900. To denote the years after 1999, you have to add an INTERVAL explicitly. Hence, to designate January 1, 2000, you have to use something like DATE("12/01/99") + INTERVAL(0-1) YEAR TO MONTH or DATE("01/01/99") + INTERVAL(1-0) YEAR TO MONTH. The Informix DATETIME type is equivalent to TIMESTAMP in SQL-92 and can have a user-specied precision, such as YEAR TO MONTH or YEAR TO SECOND. SQL-92's TIME type is identical to Informix's DATETIME HOUR TO SECOND. Fractional seconds are denoted with FRACTION(n). SQL-92's TIMESTAMP type is then equivalent to Informix's DATETIME YEAR TO FRACTION(6). Interestingly, Informix DATETIME literals are consistent with SQL-92 (except that Informix DATETIME literals don't use quotes) but are inconsistent with Informix DATEs. Specically, in an Informix DATETIME literal, the year comes rst, as a four-digit number, followed by the month and day, then hour, minute, and second, without quotes (!). At this second, my watch reads DATETIME(1998-04-08 12:13:52), about time for lunch; my calendar reads DATE("04/08/98"). Informix–Universal Server supplies utilities such as DATE, MDY (month/day/ year), YEAR, and WEEKDAY for formatting and converting dates. The current DATE is given by TODAY; the current DATETIME is given by CURRENT. The EXTEND function can be used to alter the precision of instants. This function extracts the year and month from the corresponding values of CURRENT; the minutes and the seconds are set to zero if not provided. Hence, EXTEND(DATETIME(16 19) DAY TO HOUR, YEAR TO SECOND) returns DATETIME(1997-01-01 19:00:00). It can also be used to convert strings into instant types. The standard predicates are also available on instants. As in SQL-92, an Informix INTERVAL must be either a year-month interval or a day-time interval. Note that intervals can be added to instants (yielding an instant), 3.5 IMPLEMENTATION CONSIDERATIONS Table 3.2 SQL-92 operations in IBM DB2 UDB. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND IBM DB2 UDB Equivalent DATE TIME (precision xed at 0) TIMESTAMP (precision xed at 6) no equivalent no equivalent A date duration(DECIMAL(8, 0)) with a 0 DAY eld A timestamp duration with 0 YEAR, MONTH, and MICROSECOND elds, negative values not available DATE(1997-01-01) TIME(12:34:56) TIMESTAMP(1997-01-0112.34.56.000000) 40 MONTHS, 00030400 (only in an expression) 00000001234512.000000, 171912 SECONDS (only in an expression) Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL d 1 < d 3 AND d 2 < (d 1 + i ) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL CURRENT DATE CURRENT TIME CURRENT TIMESTAMP d +i i +d d -i d +i d + CURRENT TIMEZONE CURRENT DATE CURRENT TIME CURRENT TIMESTAMP 45 46 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.2 (continued) SQL-92 Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i *n n*i i1 / i2 i /n +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) i is YEAR TO DAY i is DAY TO HOUR i is DAY TO MINUTE i is DAY TO SECOND EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i ) Operators not in SQL-92: convert d to Julian day IBM DB2 UDB Equivalent not possible not possible TIMESTAMPDIFF(itype, CHAR(d1 - d 2 )) TIMESTAMPDIFF(64, CHAR(d1 - d 2 )) not possible not possible not possible not possible i not possible CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) not possible not possible CHAR(d) not possible JULIAN DAY(DATE(001-01-01) + i) - JULIAN DAY(DATE(001-01-01-00)) 24 * DAY(i) + HOUR(i) 1440 * DAY(i) + 60 * HOUR(i) + MINUTE(i) 86400 * DAY(i ) + 3600 * HOUR(i) + 60 * MINUTE(i ) + SECOND(i) DAY(d ) DAY(i ) HOUR(i) JULIAN DAY(d) but instants can't be added to intervals, the reason being that the resulting type must be an interval. Table 3.3 shows how the facilities in SQL-92 can be simulated, to some degree, in Informix–Universal Server. 3.5 IMPLEMENTATION CONSIDERATIONS Table 3.3 SQL-92 operations in Informix–Universal Server. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND Informix–Universal Server Equivalent DATE DATETIME HOUR TO SECOND DATETIME YEAR TO FRACTION(6) no equivalent no equivalent INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND DATE("01/01/97") DATETIME(12:34:56) HOUR TO SECOND DATETIME(1997-01-01-12:34:56) YEAR TO SECOND INTERVAL(3-4) YEAR TO MONTH INTERVAL(1 23:45:12) DAY TO SECOND Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL d 1 < d 3 AND d 2 < (d 1 + i) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL CURRENT DATE CURRENT TIME CURRENT TIMESTAMP d +i d +i d -i not supported not supported TODAY CURRENT HOUR TO SECOND CURRENT 47 48 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.3 (continued) SQL-92 Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i *n n*i i1 / i2 i /n +i -i i1 + i2 i1 - i2 d 1 - d 2 (if both have the same precision) not supported i *n i *n not possible not possible +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) DATE(d) EXTEND(DATE(d), HOUR TO SECOND) EXTEND(d, YEAR TO SECOND) INTERVAL(i ) YEAR TO MONTH INTERVAL(i ) DAY TO SECOND not possible not possible not supported DAY(d) (returns an integer) not possible not possible Operators not in SQL-92: extract weekday from d (where d is DATE) 3.5.3 Informix–Universal Server Equivalent WEEKDAY(d) Microsoft Access While SQL-92 supplies six temporal types (DATE, TIME, TIMESTAMP, TIME WITH TIME ZONE, TIMESTAMP WITH TIME ZONE, and INTERVAL), Microsoft Access supplies just one, Date/Time, which is similar to SQL-92's TIMESTAMP type. Access Date/Time values are stored as an IEEE 8-byte oating-point number, with the integral portion denoting days since December 30, 1899, and the fractional portion denoting fractions of a day, to a precision of eight decimal places, or equivalently, a granularity of slightly less than one millisecond. The range is restricted to 1 C . E . to 9999 C . E .; dates before 1899 are represented with negative values. Literals are delimited with `#', for example, #5/10/96#, which uses the “U.S. format” (month, day, year), even on international versions of Microsoft Windows. To have the format depend on the locale, use DateValue. For example, 3.5 IMPLEMENTATION CONSIDERATIONS 49 The Hijri Calendar The Hijri is an Islamic calendar based on lunar cycles, with one year consisting of 12 (purely lunar) months. It was rst introduced in 638 C . E . by Umar ibn Al-Khattab. The rst day of this calendar, Muharram 1 (New Year), 1 A . H . (“Anno Hegirae”) corresponds to June 16, 622 C . E . Since the Islamic calendar is purely lunar, as opposed to solar or lunar-solar, the Hijri year is shorter than the Gregorian year by about 11 days. Also contrary to most calendars, months in the Hijri year are not related to seasons, which are themselves tied to the solar cycle. Important Muslim festivals, which always fall in the same Hijri month, may oc- cur in different seasons. For example, the Hajj and Ramadan can take place in the summer as well as the winter. It is only over a roughly 33-year cycle that lunar months resynchronize with the solar year. Interestingly, the start of a Hijri month is dened not by an astronomical new moon, but rather by an actual sighting of the crescent moon at a particular locale. This implies that a month will start at different Gregorian times in different locales, and indeed the start is affected by weather conditions and various optical factors of the atmosphere. DateValue(5/10/96) when evaluated in the U.S. will return the same date as DateValue(10/5/96) when evaluated in the U.K. In an effort to address the year 2000 problem, Access 2000 has a special interpretation of two-digit years. #1/1/00# through #12/31/29# are interpreted as the dates January 1, 2000, through December 31, 2029. #1/1/30# through #12/31/99# are interpreted as the dates January 1, 1930, through December 31, 1999. Of course, this just moves the year 2000 problem ahead 30 years, as well as invalidating previous data from the rst third of this century. More detail may be found in Section 3.6.5. The format of a literal is specied in a format property setting. Custom formats may be specied using some thirty-odd multicharacter symbols, such as “ww,” which species a number between 1 and 53 denoting the week of the year. The format routine allows a format to be used once, for example, format("1/10/99", "dd/mm/yy"). Predened formats, set in the properties, may also be used within this function, for example, format("1/10/99", "short date"). The Windows 95 system settings (in “Regional Settings”) dictate the initial values for these format properties. The CDate( ) function takes a string and attempts to convert it into a date, using context to determine which elds are where in the string. The equality and inequality predicates are available for Access Date/Times. OVERLAP is not available. Extraction of elds is accomplished through a variety of functions, such as Day( ) and Second( ). There is also an extraction function, DatePart( ), for example, DatePart("yyyy", [OrderDate]) would return a four-digit year. 50 CHAPTER THREE : INSTANTS AND INTERVALS Intervals are simulated with two functions, DateAdd and DateDiff. DateAdd takes a string expression specifying the interval granularity ("yyyy" denotes year, "q" denotes quarter, "m" denotes month, "y" denotes day of year, "d" denotes day, "w" denotes weekday, "ww" denotes week, "h" denotes hour, "m" denotes minute, and "s" denotes second), a numeric expression (positive or negative) denoting the number of granules, and a date to be shifted. As an example, DateAdd("d", 7, #2/24/96#) yields the date March 2, 1996. Analogously, DateDiff takes the parameters of a string expression denoting the granularity, as well as two days, and returns a long integer specifying the number of time intervals between these dates. For example, DateDiff("d", #3/2/96#, #2/26/96#) evaluates to the value 7. The weekday granularity depends on which day is considered the rst day of the week. Several of the functions, including DateDiff, take an optional parameter specifying a particular day (1 = Sunday through 7 = Saturday, with Sunday being the default). The week granularity depends on which week is considered the rst week of the year. Several of the functions take an optional parameter specifying this detail (1 = start with the week in which January 1 occurs, 2 = start with the rst week that has at least four days in the year, 3 = start with the rst full week of the year, with 1 being the default). Table 3.4 shows how the facilities in SQL-92 can be simulated, to some degree, in Access. In the Access column, d denotes an Access Date/Time value and j denotes an Access FLOAT, indicating a (fractional) count of Julian days. 3.5.4 Microsoft SQL Server Microsoft SQL Server supplies two temporal data types, DATETIME and SMALLDATETIME, with precisions of 1/300 second and 1 minute, respectively. The range of these two types is January 1, 1753 to December 31, 9999 for the DATETIME type, and from January 1, 1900 to June 6, 2079 for the SMALLDATETIME type. A DATETIME requires eight bytes, four bytes for the number of days since the base date and four bytes for the time of day. A SMALLDATETIME requires only four bytes, two bytes for the number of days since the base date and two bytes for the number of minutes since midnight. Intervals can be represented as SQL Server integers, of an integral number of granules in the required granularity. Table 3.5 shows how the facilities in SQL-92 can be simulated, to some degree, in Microsoft SQL Server. In the SQL-92 column, d denotes a datetime value, `i ' an interval value, and n a numeric (exact or approximate) value. In the Microsoft column, d denotes an SQL Server DATETIME value, and i denotes an SQL Server integer representing an integral number of seconds. Microsoft SQL Server automatically handles certain data type conversions; in such cases, the convert function is optional. For example, when a character expression is compared with a DATETIME expression, the character expression is implicitly converted to a DATETIME. 3.5 IMPLEMENTATION CONSIDERATIONS 51 Table 3.4 SQL-92 operations in Microsoft Access 2000. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL CURRENT DATE CURRENT TIME CURRENT TIMESTAMP Microsoft Access 2000 Equivalent Date/Time, ignoring the hour, minute, and second elds Date/Time, ignoring the century, year, month, and day elds Date/Time no equivalent no equivalent INTEGER (months) INTEGER (seconds) or FLOAT (days) DateValue(1997-01-01) or #1997-01-01# TimeValue(12:34:56, HH:MI:SS) or #12:34:56# Format("1997-01-01 12:34:56", "YYYY-MM-DD HH:NN:SS") or #1997-01-01 12:34:56# 40 (months) 171912 (seconds) or 1.9897222 (Julian days) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 j1 = j2 j1 < j2 j 1 <> j 2 j 1 BETWEEN j 2 AND j 3 d IS NULL j IS NULL d 1 < d 3 AND d 2 < DateAdd("m", j, d 1 ) DateAdd("d",d, j) DateAdd("d",d, j) DateAdd("d",d, -j) time zones not supported time zones not supported Date() The time part is set to 0 Time() The date part is set to 0 (i.e., December 31, 1899) Now() 52 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.4 (continued) SQL-92 Interval Constructors: i1 + i2 i1 - i2 (d - d ) qual d - d MONTH i *n n*i i1 / i2 i /n +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) d is a DATE d is a TIME CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) i is DAY i is HOUR i is MINUTE i is SECOND EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) Microsoft Access 2000 Equivalent j1 + j2 j1 - j2 d 1 - d 2 (result is a fractional number of days) DateDiff("m", d 2 , d 1 ) (result is an integral number of months) j *n n*j Trunc(j 1 / j 2 ) Trunc(j / n) j -j DateValue(d) or Format(d, "YYYY-MM-DD") TimeValue(d) or Format(d, "HH:MI:SS") d not possible not possible not possible Cstr(d) Cstr(j) CLng(j) CLng(j * 24) CLng(j * 1440) CLng(j * 86400) Day(d) Day(j) Hour(j) 3.5 IMPLEMENTATION CONSIDERATIONS 53 Table 3.5 SQL-92 operations in Microsoft SQL Server. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND Microsoft SQL Server Equivalent DATETIME or SMALLDATETIME, ignoring the hour, minute, and second elds DATETIME or SMALLDATETIME, ignoring the century, year, month, and day elds DATETIME (to second granularity) no equivalent no equivalent int (integral number of months) int (integral number of seconds) convert(datetime, "1997-01-01", 102) "12:34:56" or convert(datetime, "12:34:56") "1997-01-01 12:34:56" or convert(datetime, "1997-01-01 12:34:56") or convert(datetime, "1997-01-01 12:34:56", 102) 40 (months) 171812 (seconds) Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL d 1 < d 3 AND d 2 < dateadd(second,i,d 1) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL dateadd(second, i , d) dateadd(second, i , d) dateadd(second, -i , d) not supported not supported 54 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.5 (continued) SQL-92 Datetime Constructors, cont.: CURRENT DATE CURRENT TIME CURRENT TIMESTAMP Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i *n n*i i1 / i2 i /n +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) Microsoft SQL Server Equivalent convert (datetime, (convert(char(3), datename(month,getdate())) + " " + convert(char(2), datename(day,getdate())) + "," + convert(char(4), datename(year,getdate())))) convert (datetime, convert(char(2), datename(hour,getdate())) + ":" + convert(char(2), datename(minute,getdate())) + ":" + convert(char(2), datename(second,getdate()))) getdate() i1 + i2 i1 - i2 datediff(qual, d 1 , d 2 ) (result is an integral number at the indicated granularity) datediff(month, d 1 , d 2 ) i *n n*i convert(int, i 1 / i 2 ) convert(int, i / n) i -i convert (datetime, (convert(char(3), datename(month,d )) + " " + convert(char(2), datename(day,d)) + "," + convert(char(4), datename(year,d)))) convert (datetime, convert(char(2), datename(hour,d)) + ":" + convert(char(2), datename(minute,d)) + ":" + convert(char(2), datename(second,d))) 3.5 IMPLEMENTATION CONSIDERATIONS 55 Table 3.5 (continued) SQL-92 Other Operators, cont.: CAST(d AS TIMESTAMP) d is a DATE d is a TIME CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) 3.5.5 Microsoft SQL Server Equivalent d convert (datetime, (convert(char(3), datename(month,getdate())) + " " + convert(char(2), datename(day,getdate())) + "," + convert(char(4), datename(year,getdate())) + " " + convert(char(2), datename(hour,d)) + ":" + convert(char(2), datename(minute,d)) + ":" + convert(char(2), datename(second,d)))) not possible not possible convert(char, d) convert(char, i) i already an integer datename(day,d ) (returns a string) convert(int, i/86400) convert(int, i/3600) Sybase SQLServer Support for time in Sybase SQLServer is essentially identical to that of Microsoft SQL Server because they started from the same code base. For details, see the discussion on that system, in Section 3.5.4. Table 3.6 shows how the facilities in SQL-92 can be simulated, to some degree, in Sybase SQLServer. In the SQL-92 column, d denotes a datetime value, i an interval value, and n a numeric (exact or approximate) value. In the Sybase SQLServer column, d denotes an SQLServer DATETIME value, and i denotes an SQLServer integer representing an integral number of seconds. 3.5.6 Oracle8 Server As with Access, Oracle8 Server provides but one temporal type, here called DATE. An Oracle DATE comprises seven elds, century, year, month, day, hour, minute, and second, each as one byte. Oracle8 Server can store dates from January 1, 4712 B . C . E . (Julian Day 1) to December 31, 4712 C . E ., while disallowing the nonexistent 56 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.6 SQL-92 operations in Sybase SQLServer. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL CURRENT DATE Sybase SQLServer Equivalent DATETIME or SMALLDATETIME, ignoring the hour, minute, and second elds DATETIME or SMALLDATETIME, ignoring the century, year, month, and day elds DATETIME (to second granularity) no equivalent no equivalent int (integral number of months) int (integral number of seconds) convert(datetime, "1997-01-01", 105) convert(datetime, "12:34:56") convert(datetime, "1997-01-01 12:34:56",105) 40 (months) 171812 (seconds) d1 = d2 d1 < d2 d 1 <> d 2 d 2 <= d 1 AND d 1 <= d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 2 <= i 1 AND i 1 <= i 3 d IS NULL i IS NULL d 1 < d 3 AND d 2 < dateadd(second,i,d 1) dateadd(second,i,d ) dateadd(second,i,d ) dateadd(second,-i,d) not supported not supported convert (datetime, (convert(char(3), datename(month,getdate())) + " " + convert(char(2), datename(day,getdate())) + "," + convert(char(4), datename(year,getdate())))) 3.5 IMPLEMENTATION CONSIDERATIONS 57 Table 3.6 (continued) SQL-92 Datetime Constructors, cont.: CURRENT TIME CURRENT TIMESTAMP Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i *n n*i i1 / i2 i /n +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) d is a DATE Sybase SQLServer Equivalent convert (datetime, convert(char(2), datename(hour,getdate())) + ":" + convert(char(2), datename(minute,getdate())) + ":" + convert(char(2), datename(second,getdate()))) getdate() i1 + i2 i1 - i2 datediff(qual, d 1 , d 2 ) (result is an integral number at the indicated granularity) datediff(month, d 1 , d 2 ) i *n n*i convert(int, i 1 / i 2 ) convert(int, i / n) i -i convert (datetime, (convert(char(3), datename(month,d )) + " " + convert(char(2), datename(day,d)) + "," + convert(char(4), datename(year,d)))) convert (datetime, convert(char(2), datename(hour,d))+":" + convert(char(2), datename(minute,d)) + ":" + convert(char(2), datename(second,d))) d 58 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.6 (continued) SQL-92 Other Operators, cont.: CAST(d AS TIMESTAMP) d is a TIME CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) Sybase SQLServer Equivalent convert (datetime, (convert(char(3), datename(month,getdate())) + " " + convert(char(2), datename(day,getdate())) + "," + convert(char(4), datename(year,getdate())) + " " + convert(char(2), datename(hour,d)) + ":" + convert(char(2), datename(minute,d)) + ":" + convert(char(2), datename(second,d)))) not possible not possible convert(char, d) convert(char, i) i already an integer datename(day,d) (returns a string) convert(int, i /86400) convert(int, i /3600) year 0000. It is thus superior to SQL's TIMESTAMP type in permitting B . C . E . dates, but is inferior in not permitting fractions of a second and in stopping about halfway to the year 9999. SQL-92's INTERVAL DAY can be simulated using Oracle NUMBER, which provides a day count. Smaller granularities can be partially simulated with fractional days. NUMBER(12,5) is sufcient for seconds; NUMBER(18,11) will support microseconds. Both support the full range of 4700 years. It is not possible to simulate SQL92 year-month intervals, though subtraction to the months granularity is possible via MONTHS BETWEEN. NEXT DAY gives the date of the next day of the week (specied as a character string such as Monday) after a specied date value. The predicates that Oracle8 Server supports on DATEs are `=', `<', `<=', `>', `>=', `<>', and BETWEEN. These are based on the seven-byte internal representation of dates. For not equals, Oracle8 Server also allows `!=', `ˆ =', and `:=' (on some systems). Oracle dates can be converted to character strings via the TO CHAR function, which takes as a second argument the format desired. SQL-92's CAST(value AS CHARACTER) may thus be simulated with TO CHAR(value, YYYY-MM-DD HH24:MI:SS) (HH24 requests military time, that is, a 24-hour clock). This format string is quite 3.5 IMPLEMENTATION CONSIDERATIONS 59 exible, with over 30 options available. As an example, TO CHAR(value, DY Month DD, YYYY) will produce a string looking like THU July 24, 1997. A third parameter to this function species other aspects of the output, such as the language, for example, TO CHAR(BirthDate, Month DD, YYYY, HH12:MI A.M., NLS DATE LANGUAGE = American). The TO CHAR function can also extract individual elds; for example, TO CHAR(BirthDate, MM) returns the month. Finally, the Julian day number can be computed via TO CHAR(BirthDate, J), returning an integer (2,440,588, for January 1, 1970). The TO DATE function produces a date value from a character string, via a format string, for example, TO DATE(January 15, 1989, 11:00 A.M., Month DD, YYYY, HH12:MI A.M.). This function can also convert an integer (containing the Julian number) to a date, for example, TO DATE(2440588, J). The Julian number identies a particular day, so the hour, minute, and second elds are set to 0. There seems to be no way to extract fractional days from an Oracle DATE, nor convert fractional days to a DATE value. However, an Oracle (fractional) NUMBER, representing a day-time interval, can be added (or subtracted) from a DATE, yielding a DATE. Oracle8 Server provides a variety of other date functions. ADD MONTHS adds an integer number of months to a DATE value. By using a negative integer, months can be subtracted. GREATEST picks the latest date from a list of dates; LEAST is analogous. LAST DAY returns the date of the last day of the month that the provided date is in. The NEW TIME function allows you to shift a DATE from one specied time zone to another. The source and target time zones are three-character strings; only a few time zones are supported. There seems to be no way within Oracle8 Server to nd out your own time zone. The TRUNC function removes the hour, minute, and second elds from a DATE value, resulting in a day starting at midnight. TRUNC also accepts an optional string parameter, specifying a eld below which truncation should occur; for example, TRUNC(BirthDate, HH24) would zero out the minute and second elds. An analogous ROUND function is also available for DATEs. Finally, the current date and time is returned by SYSDATE. Table 3.7 shows how the facilities in SQL-92 can be simulated, to some degree, in Oracle8 Server. In the SQL-92 column, d denotes a datetime value, i an interval value, and n a numeric (exact or approximate) value. In the Oracle8 Server column, d denotes an Oracle DATE value and j denotes an Oracle NUMBER representing Julian days. So, how did Jim Barnett represent instants and intervals in the F INDER schema? Well, for the most part he used Oracle DATEs. In fact, in the resulting schema one of every ve columns is a DATE column. The fundamental distinction between instants and intervals is hidden in the Oracle schema; column names and comments 60 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.7 SQL-92 operations in Oracle8 Server. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND Oracle8 Server Equivalent DATE, ignoring the hour, minute, and second elds DATE, ignoring the century, year, month, and day elds DATE (to second granularity) no equivalent no equivalent no equivalent NUMBER(12, 5) TO DATE(1997-01-01, YYYY-MM-DD) TO DATE(12:34:56, HH24:MI:SS) TO DATE(1997-01-01 12:34:56, YYYY-MM-DD HH24:MI:SS) not possible TO NUMBER(SUBSTR(1 23:45:12, 1,LENGTH(1 23:45:12)-9)) + TO NUMBER(SUBSTR(1 23:45:12, LENGTH(1 23:45:12)-7,2))/24 + TO NUMBER(SUBSTR(1 23:45:12, LENGTH(1 23:45:12)-4,2))/1440 + TO NUMBER(SUBSTR(1 23:45:12, LENGTH(1 23:45:12)-1,2))/86400 (result is a fractional Julian day) Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 3 , d 4 ) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 j1 = j2 j1 < j2 j 1 <> j 2 j 1 BETWEEN j 2 AND j 3 d IS NULL j IS NULL d 1 < d 4 AND d 3 < (d 1 + j ) Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL d + j, ADD MONTHS(d, j) j + d , ADD MONTHS(d, j) d - j , ADD MONTHS(d, -j) not supported not supported 3.5 IMPLEMENTATION CONSIDERATIONS Table 3.7 (continued) SQL-92 Datetime Constructors, cont.: CURRENT DATE CURRENT TIME CURRENT TIMESTAMP Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i *n n*i i1 / i2 i /n +i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) d is a DATE d is a TIME CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) i is DAY i is HOUR i is MINUTE i is SECOND EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) Oracle8 Server Equivalent TRUNC(SYSDATE) TO DATE( TO CHAR(SYSDATE, HH24:MI:SS), HH24:MI:SS) SYSDATE j1 + j2 j1 - j2 d 1 - d 2 (result is a (fractional) Julian number) MONTHS BETWEEN(d 1, d 2 ) (result is a (fractional) number of months) j *n n*j j1 / j2 j /n +j -j TRUNC(d ) TO DATE(TO CHAR(d, HH24:MI:SS), HH24:MI:SS) TRUNC(d) TRUNC(SYSDATE)+(d -TRUNC(d)) not possible j TO CHAR(d, YYYY-MM-DD  HH24:MI:SS) TRUNC(j, 0) TO CHAR(j + TO DATE(1, J),  HH24:MI:SS) k k TRUNC(j, 0) TRUNC(j * 24, 0) TRUNC(j * 1440, 0) TRUNC(j * 86400, 0) TRUNC(d, DD) - TRUNC(d,MM) + 1 TRUNC(j,0) TRUNC(j*24, 0) - (TRUNC(j,0)*24) 61 62 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.7 (continued) SQL-92 Operators not in SQL-92: convert d to Julian day convert Julian day n to DATE pick the earliest date pick the latest date pick the last day of the month get the next day of the week Oracle8 Server Equivalent TO CHAR(d, J) n + TO DATE(1, J) LEAST(d 1 , . . ., d ) GREATEST(d 1, . . ., d ) LAST DAY(d) NEXT DAY(d, Monday) n n are necessary to highlight these differences. So a Start Time is an instant, but an Incrmnt Time is an interval (the comment states that the “Increment Time is taken in reference to the start of the period”). Intervals were represented with numerics. The Time String In Hole column of the Well Log Service table is of type NUMBER(8,2); the granularity must be inferred from other information. For example, the comment for the Sample Interval column of the Seis Trace Hdr table species “sampling interval in milliseconds.” When he needed more control over the granularity, Jim found that Oracle was of little help. Most of these values were expressed as a pair of columns. Although the Start Time is a DATE, thereby utilizing a possible granularity of seconds, the Incrmnt Time is a NUMBER(7,2) column, coupled with an Incrmnt Time Unit column, of type VARCHAR(12). The Well Test Hdr table species the Start Time, with the Well Test Incrmnt providing a specic observation (ordered by the Incrmnt Obs No column). Consider though how you would calculate in SQL the starting time of a particular observation. The Incrmnt Time is a fractional number of units, which must be multiplied by the size of the unit, determined from the name of that unit, then added to the Start Time. This calculation must be done in terms of fractional days, so it is important that the size of the units are stored in that manner (Oracle8 Server will blithely permit this calculation without this requirement being satised, with incorrect results). 3.5.7 UniSQL UniSQL supports the DATE, TIME, and TIMESTAMP data types. TIMESTAMPs are constrained to a granularity of a second; their range is only January 1, 1970 through 03:14:07 January 19, 2038. TIMEs also are to a granularity of one second. Subtracting two dates yields an integral number of days; subtracting two TIME or TIMESTAMP values will yield an integral number of seconds. Table 3.8 shows how the facilities in SQL-92 can be simulated, to some degree, in UniSQL. In the SQL-92 column, d denotes a datetime value, i an interval value, 3.6 THE YEAR 2000 PROBLEM* 63 The Start of the Millennium Given that there is no 0 A . D . (see page 27), the issue is then raised of when the millennium starts, 2000 A . D . or 2001 A . D . Those of a more mathematical constitution generally insist on the latter, an example being the Royal Greenwich Observatory in Cambridge, England, as reported in the New York Times on December 8, 1996. Pop culture clearly sides with the former; we can effectively argue that the millennium has already arrived months before the end of 2000 A . D . But in that case, the rst millennium was but 999 years long, thereby belying its etymological basis (“one thousand years,” in Latin, see page 86), and raising the questions of how long is a century, or even a decade? Stephen Jay Gould is unapologetic on this—it is clear his sentiments lie with the solution that a (nay, every) millennium is 10 centuries long, a century consists of 10 decades, and all decades are 10 years, save the rst, which was but 9 years in length, thus, by incontrovertible logic, the rst century contained 99 years and the rst millennium (but thankfully, not the present one) comprised 999 years. and n a numeric (exact or approximate) value. In the UniSQL column, d denotes a UniSQL TIMESTAMP value (to the granularity of seconds), and i denotes a UniSQL INTEGER representing an integral number of granules (seconds). 3.6 THE YEAR 2000 PROBLEM* (We remind you that the asterisk in this section heading—and in some later section headings—indicates advanced material that may be skipped on a rst reading.) The year 2000 problem has often been abbreviated to the “Y2K problem” by those who love acronyms, and termed the “Millennium Bug” by those who want a more catchy name. The problem involves software that stores dates using only two digits for the year. That raises the issue of determining what the year 00 denotes. If it denotes 2000, then everything will generally be ne when that year arrives. On the other hand, if it denotes 1900, then all manner of difculties will arise. A phone call that starts the night of December 31, 1999, and extends a little past midnight, could be charged for 100 years of air time, resulting in a horrendous bill. A bill due in December 1999 but not paid until the next month could result in an interest fee of gigantic proportions. Or the software might just fail, freezing bank accounts and leaving ight controllers with no information on their tracking screens. Indeed, consumers are already being affected. The expiration date on Mastercard and Visa credit and debit cards is listed as MM/YY. Recently, cards were issued with an expiration date of 01/00, and these cards are being denied, as having expired some 98 years ago. While the larger authorization centers have updated their software, some smaller authorization centers still cannot accept those cards (as of June 1998). 64 CHAPTER THREE : INSTANTS AND INTERVALS Table 3.8 SQL-92 operations in UniSQL. SQL-92 Types: DATE TIME TIMESTAMP TIME WITH TIME ZONE TIMESTAMP WITH TIME ZONE INTERVAL YEAR TO MONTH INTERVAL DAY TO SECOND UniSQL Equivalent DATE TIME TIMESTAMP (to second granularity) no equivalent no equivalent no equivalent INTEGER (integer number of seconds or days) Literals: DATE 1997-01-01 TIME 12:34:56 TIMESTAMP 1997-01-01 12:34:56 INTERVAL 3-4 YEAR TO MONTH INTERVAL 1 23:45:12 DAY TO SECOND DATE 01/01/1997 TIME 12:34:56 TIMESTAMP 01/01/1997 12:34:56 not possible 171812 (seconds) Predicates: d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL (d 1 , i) OVERLAPS (d 2 , d 3 ) d1 = d2 d1 < d2 d 1 <> d 2 d 1 BETWEEN d 2 AND d 3 i1 = i2 i1 < i2 i 1 <> i 2 i 1 BETWEEN i 2 AND i 3 d IS NULL i IS NULL d 1 < d 3 AND d 2 < d 1 + i Datetime Constructors: d +i i +d d -i d AT i d AT LOCAL CURRENT DATE CURRENT TIME CURRENT TIMESTAMP d +i i +d d -i not supported not supported not supported not supported not supported Interval Constructors: i1 + i2 i1 - i2 (d 1 - d 2 ) qual (d 1 - d 2 ) MONTH i1 + i2 i1 - i2 d 1 - d 2 (result is an integer number at the indicated granularity) not possible 3.6 THE YEAR 2000 PROBLEM* 65 Table 3.8 (continued) SQL-92 UniSQL Equivalent Interval Constructors (cont.): i *n n*i i1 / i2 i /n +i -i i *n n*i j1 / j2 j /n i -i Other Operators: CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) CAST(i AS INTERVAL YEAR TO MONTH) CAST(i AS INTERVAL DAY TO SECOND) CAST(d AS CHAR) CAST(i AS CHAR) CAST(i AS INTEGER) EXTRACT(DAY FROM d) EXTRACT(DAY FROM i) EXTRACT(HOUR FROM i) CAST(d AS DATE) CAST(d AS TIME) CAST(d AS TIMESTAMP) not possible i CAST(d AS CHAR) CAST(i AS CHAR) i already an integer EXTRACT(DAY FROM d ) not possible not possible The year 2000 problem is a specic instance of a more general problem of an (often unstated) assumption that will be invalidated purely by the course of time. The year 2000 problem is but one instance of a more general problem, that of making assumptions that are invalidated purely by the course of time. Here, the assumption was that two digits sufce for the year, which is a valid assumption if all the information is contained in a single century. Indeed, one digit sufces if the information is contained in a particular decade. What has captured the imagination of the public and the press about the year 2000 problem is due to four factors: 1. The underlying assumption was made, sometimes implicitly, in so many software systems. 2. The problem was ignored until (almost) too late, despite being recognized for decades: the 1965 Multics system used a 71-bit microsecond representation. 3. The assumption is invalidated at exactly the same time (well, within a single 24-hour period) for these systems. 4. The systems involved are generally legacy systems, with underlying source code a much-modied mess, or worse, simply unavailable. 66 CHAPTER THREE : INSTANTS AND INTERVALS These factors conspire to make xing the problem exceedingly expensive, yet the third factor imposes an unavoidable deadline for coming up with an acceptable solution, with often disastrous consequences if this deadline is not met. The classic movie High Noon comes to mind, with Gary Cooper in almost every scene glancing at that pendulum clock inexorably ticking away the minutes. I, as author of this book, which contains material on the Y2K problem, am similarly constrained by this approaching deadline. The year 2000 problem may be found in hardware, specically physical clocks, and all manner of software, from programming languages to operating systems, from DBMSs to applications. As the present book considers time-varying applications and SQL, we will limit our discussion to those topics. In particular, we will eschew discussion of the extremely important and challenging task of identifying, repairing, and testing legacy code. At the same time, we will examine the phenomenon more generally, by highlighting time-dependent assumptions that involve both the year 2000 and other dates. As we will emphasize, it is effectively impossible to completely avoid these problems, but we can minimize them, and be aware of those that are present. 3.6.1 Year 2000 Compliance and Certication Each organization must develop its own denition of compliance, termed “year 2000 compliance,” or in the general case, “century compliance.” The following language is recommended by the Chief Information Ofcers Council Sub-Committee on the Year 2000 for voluntary use by federal agencies in their solicitations and contracts for year 2000 compliant products. The contractor warrants that each hardware, software, and rmware product delivered under this contract and listed below shall be able to accurately process date/time data (including, but not limited to, calculating, comparing, and sequencing) from, into, and between the twentieth and twenty-rst centuries, and the years 1999 and 2000 and leap year calculations to the extent that other information technology, used in combination with the information technology being acquired, properly exchanges date/time data with it. Year 2000 certication is dened by Mitre as “a measure of assurance by a designated Y2K authority (or their representative), that an item is operationally ready. Any company working toward Year 2000 compliance must ultimately be concerned with Year 2000 certication.” For database products, vendors generally certify, viewing themselves as a Y2K authority, that their products are (or are not) year 2000 compliant, generally based on their specic denition of year 2000 compliance. To address the problem of two-digit dates, vendors generally dene a “window” of 100 years within which a two-digit date is interpreted. This interpretation is often called the “implied century rule.” The window is sometimes dependent on when the date is interpreted. In many cases, the window is xx00–xx99, meaning 3.6 THE YEAR 2000 PROBLEM* 67 that a two-digit date is interpreted as being in the current century. So, 34 would then be interpreted in 1998 as 1934, and in 2001 as 2034; the window jumped in the year 2000. The year 2000 problem can be rephrased as the “window ending at 99 and jumping at 00 problem,” in that the window goes from 1900 to 1999, and jumps to the next century (2000–2099) in the year 2000. Products vary on where this window is located and when it jumps (in the best scenario, the jump and the window boundary should be far apart). It would have been to the consumer's benet for vendors to come up with a common approach to the year 2000 problem: specify a common window, specify a common jump point, and specify a common mechanism to ensure backward compatibility. Vendors in their wisdom have taken exactly the opposite tack: every approach is unique. Would it be cynical to think that this is intentional? Two-digit dates, and indeed, any nite representation, imply that eventually the range will be exhausted, and some kind of discontinuity will result. All that the windowing approaches do is delay the discontinuity at the jumps. In scanning the various extant DBMSs, we see difculties with the years 2000, 2030, 2050, 2079, 2100, 4712, and 10,000. This implies that programmers will be kept busy both xing applications as these notable years approach and converting applications from one DBMS to another that takes a different approach. 3.6.2 SQL-92 SQL-92 DATEs and TIMESTAMPs both use four digits to represent the year. Applications using this standard are ne until the year 9999 C . E ., and thus exhibit the “year 10,000 problem,” but are fortunately not affected by the year 2000 transition. As will be discussed in the following section, an SQL-92 TIME value is actually a funny kind of interval. An alternative characterization is that TIME has a midnight problem: its meaning changes every midnight. In the above terminology, a TIME value has a window of 24 hours (from midnight to midnight) and a jump time of midnight. Concerning leap years, the question could be phrased several ways.   “Is the value of DATE 2000-02-29 valid?” The standard states “Within the denition of a hdatetime literali, the hdatetime valueis are constrained by the natural rules for dates and times according to the Gregorian calendar” [44, p. 75]. As the contribution of the namesake of this calendar, Pope Gregory XIII, was to specify that century years not divisible by 400 would no longer be leap years, this clearly indicates that the “natural rules” would consider the year 2000 to be a leap year. “Is (DATE 2000-03-01 - DATE 2000-02-01) DAY the value 29 days?” The SQL92 standard species datetime subtraction as “a) A [here, DATE 2000-03-1] and B [here, DATE 2000-02-1] are converted to integer scalars A2 and B2, respectively, in units Y [here, DAY] as displacements from some implementation- 68 CHAPTER THREE : INSTANTS AND INTERVALS  dependent start datetime. b) The result is determined by effectively computing A2–B2. . . ” [44, p. 137]. Is this year 2000 compliant? It all depends on what is meant by the word “converted.” Jim Melton has told me that those on the standards committee would agree that the value 29 is correct and intended, but I counter that the standard itself should be unambiguous and clear, especially on such an important question. “Is DATE 2000-03-01 - INTERVAL 29 DAY the value DATE 2000-02-01?” The SQL-92 standard species such expressions as “Arithmetic is performed so as to maintain the integrity of the datetime data type that is the result of the hdatetime value expressioni. This may involve carry from or to the immediately next more signicant hdatetime eldi” [44, p. 133]. Here, we are concerned about the carry from the DAY eld to the MONTH eld. Presumably the “integrity of the datetime data type” refers back to the denition of a DATE literal, which we saw above treats the year 2000 as a leap year. My conclusion: since the conversion for date difference is not explicitly spelled out, we don't know that the conversion will treat the year 2000 as a leap year, and so the SQL-92 standard should not be considered year 2000 compliant. What should programmers do to ensure that new code being written does not exhibit the year 2000 problem? Quite simply, use four-digit years, as the SQL-92 standard mandates. Of course, this aphorism ignores the requirement that new code work with and indeed be compatible with existing legacy programs, which might themselves use only two-digit years. As Mark Haselkorn said in an interview published in the February 1998 issue of the Institute of the IEEE: Y2K is not about hardware, rmware and operating software (platforms). It is not even about application software and even data. It is not even about users, organizations, economies and nations—it's about all of them together. You cannot change your computer to a Y2K-safe one and think you have xed the problem. You still have software that runs on it and, more importantly, data you have accumulated that has great value to you that must be part of the x. With that chastening fresh on our mind, we now turn to specic DBMS products. A critical disclaimer: these products and their level of compliance are highly uid, with new techniques being developed daily to achieve compliance. The remarks below reect the situation as this is being written, in June 1998. This material will surely be somewhat out of date when it appears in print. You are urged to contact your vendor for information on year 2000 compliance. 3.6.3 IBM DB2 Universal Database IBM DB2 UDB DATEs and TIMESTAMPs both use four-digit years, and so are year 2000 compliant. The year 2000 is considered a leap year by DB2 UDB.  DATE(2000-02-29) is a valid DB2 UDB DATE. 3.6       3.6.4 DATE(2000-02-01) DATE(2000-03-01) DATE(2000-02-01) DATE(2000-03-01) DATE(2000-02-28) DATE(2000-03-01) THE YEAR 2000 PROBLEM* 69 + 1 MONTH yields March 1, 2000. - 1 MONTH yields February 1, 2000. + 00000100. yields March 1, 2000. - 00000100. yields February 1, 2000. + 1 DAY yields February 29, 2000. - 1 DAY yields February 29, 2000. Informix Informix denes “year 2000 compliant” as . . . the use or occurrence of the dates on or after January 1, 2000, will not adversely affect the performance of the Informix products with respect to four-digit data dependent data or the ability of such products to correctly create, store, process, and output information related to such date data. The internal formats of Informix DATE and DATETIME data types both support four digits for the year. For two-digit input of dates, Informix has added the DBCENTURY environment variable. There are four values for this environment variable: past (`P'), future (`F'), closest (`C'), and present (`R'). If no value is specied, the default is present semantics. Of course, this environment variable is not used if four digits are supplied.   Present semantics (`R') The present century provides the window. The window is 00–99 and the jump date is the end of the century. DATE("1-1-1") when entered on June 22, 1998, evaluates to January 1, 1901. When entered in 2002, this literal evaluates to January 1, 2001. Past semantics (`P') The past and present centuries provide two windows and produce two expanded date values. The one that is prior to the current date is chosen. If both dates are prior to the current date, the date that is closest to the current date is chosen. DATE("1-1-99") when entered on June 22, 1998, produces January 1, 1899 and January 1, 1999; January 1, 1899 is chosen. When entered in 2002, this literal evaluates to January 1, 1999. DATE("1-1-97") when entered on June 22, 1998, produces January 1, 1897 and January 1, 1997; January 1, 1997 is chosen. While seemingly only two years before DATE("1-1-99"), the resulting four-digit date is 98 years later . When entered in 2002, DATE("1-1-97") evaluates to January 1, 1997. In our terminology, the window is the preceding 100 years (for a current date of June 22, 1998, the window extends from June 21, 1898 to June 21, 1998) and the jump date is each day (though the window only moves forward one day). DATE("6-22-98") will evaluate to June 22, 1898, exactly 100 years ago today; tomorrow that same literal will evaluate to June 22, 1998. 70 CHAPTER THREE : INSTANTS AND INTERVALS   Future semantics (`F') The present and future centuries provide two windows and produce two expanded date values. The one that is after the current date is chosen. If both dates are after the current date, the date that is closest to the current date is chosen. DATE("1-1-99") when entered on June 22, 1998, produces January 1, 1999 and January 1, 2099; January 1, 1999 is chosen. When entered in 2002, this literal evaluates to January 1, 2099. DATE("1-1-97") when entered on June 22, 1998, produces January 1, 1997 and January 1, 2097; January 1, 2097 is chosen. As before, while this literal seems to be only two years before DATE("1-1-99"), the resulting four-digit date is 98 years later . When entered in 2002, DATE("1-1-97") evaluates to January 1, 2097. The window is the following 100 years (for a current date of June 22, 1998, the window extends from June 23, 1998 to June 22, 2098) and the jump date is each day. DATE("6-22-98") will evaluate to June 22, 2098, exactly 100 years in the future; tomorrow that same literal will evaluate to June 22, 1998. Closest semantics (`C') The past, present, and future centuries provide three windows and produce three expanded date values. The one that is closest to the current date is chosen. DATE("1-1-99") when entered on June 22, 1998, produces January 1, 1899, January 1, 1999, and January 1, 2099 as candidates; January 1, 1999 is chosen. When entered in 2002, this literal evaluates to January 1, 1999. DATE("1-1-97") when entered on June 22, 1998, produces January 1, 1897, January 1, 1997, and January 1, 2097 as candidates; January 1, 1997 is chosen. Unlike with the other semantics, this literal seems to be only two years before DATE("1-1-99"), and in fact the resulting four-digit date is also two years earlier. When entered in 2002, DATE("1-1-97") evaluates to January 1, 1997. There is still anomalous behavior with this semantics; it is just distant in time. DATE("1-1-48") when entered on June 22, 1998, evaluates to January 1, 2048. DATE("1-1-49"), seemingly one year later, evaluates to January 1, 1949. The window is the 100 years centered on the current date (for a current date of June 22, 1998, the window extends from June 22, 1948 to June 22, 2048) and the jump date is each day. Actually, this brings up a slight unspecication of closest semantics. Because 2000 is a leap year, any 100-year window between 1900 and 2100 will contain an odd number of days (36,525); hence, there will be a (single) closest value. However, when the present date is after the year 2100, the current window will contain an even number of days (36,524), and there may occur two potential dates equidistant from the current date. As an example, if the current date is January 1, 2105, the current semantics provides for the value DATE("11-55") January 1, 2055, January 1, 2155, and January 1, 2255. The last date is certainly out of consideration, but the rst two are exactly 18,262 days from the current date, and so neither is preferred (or worse, both are preferred). We 3.6 THE YEAR 2000 PROBLEM* 71 simply don't know which date will be returned when this literal is evaluated on that date. It seems that the closest semantics provides the most intuitive behavior, in that the anomalies occur with distant dates. The year 2000 is considered a leap year by Informix.     3.6.5 DATE("2/29/2000") is a valid SQLServer DATETIME. DATE("3/1/2000") - DATE("2/1/2000") yields 29 days. DATE("2/28/2000") + INTERVAL(1) DAY yields February 29, 2000. DATE("3/1/2000") - INTERVAL(1) DAY yields February 29, 2000. Microsoft Access Microsoft's denition of year 2000 compliance is as follows: A Year 2000 Compliant product from Microsoft will not produce errors processing date data in connection with the year change from December 31, 1999 to January 1, 2000 when used with accurate date data in accordance with its documentation and the recommendations and exceptions set forth in the Microsoft Year 2000 Product Guide, provided all other products (e.g., other software, rmware and hardware) used with it properly exchange date data with the Microsoft product. A Year 2000 Compliant product from Microsoft will recognize the Year 2000 as a leap year. Microsoft classies its products into ve categories.  Compliant The product fully meets Microsoft's standard of compliance. May have prerequisite patch or service pack for compliance. The product meets Microsoft's standard of compliance with some disclosed exceptions that constitute minor date issues. Not compliant The product does not meet Microsoft's standard of compliance. Testing yet to be completed Product test is not yet complete or has not started but will be tested. Will not test The product will not be tested for compliance.  Compliant with minor issues    Microsoft considers both Access 95 and Access 97 to be year 2000 compliant, in terms of the above denition. Access Date/Time values have a range of 9899 years (100 A . D . to 9999 A . D .). However, Access 95 and Access 97 differ on the interpretation of two-digit dates. Access 95 by default allows two-digit and four-digit years on input. The user can dene formats, via an input mask. Included in the predened formats is a Short Date format, which forces users to enter dates in a two-digit year format. Parsing of dates is controlled by the OLEAUT32.DLL le in the system folder. The interpretation of the two-digit dates depends on the version of this le. 72 CHAPTER THREE : INSTANTS AND INTERVALS For version 2.20.4048 and lower, two-digit dates are considered to be in the same century. Hence, DateValue(01/01/00) will be interpreted as January 1, 1900. For version 2.20.2049 and higher, dates 1/1/00 through 12/31/29 are interpreted as being in the next century. So these dates would be interpreted in 1998 as 1/1/2000 through 12/31/2029. Dates 1/1/30 through 12/31/99 are interpreted in the current century, so would be interpreted in 1998 as 1/1/1930 through 12/31/1999. Effectively, this delays the year 2000 problem until the year 2030. For Access 97, there is only one possible interpretation: the window is from year 30 of this century to year 29 of the next century, and shifts at the year 2000. The year 2000 is considered a leap year by Access.       3.6.6 DateValue(2000-02-29) is a valid Access Date/Time. DateValue(2000-03-01) - DateValue(2000-02-01) yields 29 days. DateAdd("m", DateValue(2000-02-01), 1) yields March 1, 2000. DateAdd("m", DateValue(2000-03-01), -1) yields February 1, 2000. DateAdd("d", DateValue(2000-02-28), 1) yields February 29, 2000. DateAdd("d", DateValue(2000-03-01), -1) yields February 29, 2000. Microsoft SQL Server Microsoft considers SQL Server 6.5 and 7.0 to be year 2000 compliant. Microsoft SQL Server supports two temporal data types, DATETIME, with a range of 1753 to 9999, and SMALLDATETIME, with a range of January 1, 1900 to June 6, 2079. Either data type allows you to specify only the last two digits of the year, with values less than 50 interpreted as 20yy (e.g., 17 is interpreted as 2017) and values greater than 50 interpreted as 19yy (e.g., 57 is interpreted as 1957). Put another way, the window starts at 1950 and is xed, representing a “year 2050 problem,” as well as a “year 2079 problem,” beyond which SMALLDATETIMEs are not dened. Concerning the year 2000 being considered a leap year, several bugs in this regard were xed in Service Packs 2 and 5 of SQL Server 6.5.    CONVERT(DATETIME, "2000-02-29", 102) is a valid SQL Server DATETIME. DateDiff(day, CONVERT(DATETIME, "2000-02-01", 102), CONVERT(DATETIME, "2000-03-01", 102)) yields 29 days. DateAdd(month, 1, CONVERT(DATETIME, "2000-02-01", 102)) yields March 1,  DateAdd(month, -1, CONVERT(DATETIME, "2000-03-01", 102)) yields   2000. February 1, 2000. DateAdd(day, 1, CONVERT(DATETIME, "2000-02-28", 102)) yields February 29, 2000. DateAdd(day, -1, CONVERT(DATETIME, "2000-03-01", 102)) yields February 29, 2000. 3.6 3.6.7 THE YEAR 2000 PROBLEM* 73 Sybase SQLServer Sybase's denition of “century compliant” is as follows:     “General Integrity: No value for the current date will interrupt normal operation: the system returns the correct date accurate to century in response to a request for current date, and the software is unaffected by any value returned.” “Date Integrity: Correct results are returned in the operation of all legal and calendar operations of dates that span century marks within the range of the software.” “Explicit Century: The software's internal date storage format explicitly includes the century and reporting formats allow date representation in the full century format.” “Implicit Century: On encountering data that does not include the century either from transaction input or from an external data source, the century value is unambiguously inferred by the software.” Under this denition, Sybase considers SQLServer to be century compliant. Sybase SQLServer supports two temporal data types, DATETIME, with a range of 1753 to 9999, and SMALLDATETIME, with a range of January 1, 1900 to June 6, 2079. Either data type allows you to specify only the last two digits of the year, with values less than 50 interpreted as 20yy (e.g., 17 is interpreted as 2017) and values greater than 50 interpreted as 19yy (e.g., 57 is interpreted as 1957). Put another way, the window starts at 1950 and is xed, representing a “year 2050 problem,” as well as a “year 2079 problem,” beyond which SMALLDATETIMEs are not dened. The year 2000 is considered a leap year by Sybase SQLServer.    CONVERT(DATETIME, "2000-02-29", 102) is a valid SQLServer DATETIME. DateDiff(day, CONVERT(DATETIME, "2000-02-01", 102), CONVERT(DATETIME, "2000-03-01", 102)) yields 29 days. DateAdd(month, 1, CONVERT(DATETIME, "2000-02-01", 102)) yields March 1,  DateAdd(month, -1, CONVERT(DATETIME, "2000-03-01", 102)) yields February   3.6.8 2000. 1, 2000. DateAdd(day, 1, CONVERT(DATETIME, "2000-02-28", 102)) yields February 29, 2000. DateAdd(day, -1, CONVERT(DATETIME, "2000-03-01", 102)) yields February 29, 2000. Oracle8 Server The Oracle8 Server supports the DATE type, which includes a four-digit year, and so accommodates the year 2000. However, Oracle8 Server can store a maximum year of 4712; this raises the impending “year 4712 problem.” Oracle's TO DATE function takes two strings, a value string and a format string. Applications using YYYY in the format string are safe; applications using only two 74 CHAPTER THREE : INSTANTS AND INTERVALS digits (e.g., a format string of YY-MM-DD) will need to be examined, as the function will interpret such value strings as being in the current century. For example, TO DATE(450123, YYMMDD) when evaluated today (June 19, 1998) returns the value denoting January 23, 1945. This means that TO DATE(000101, YYMMDD) will evaluate to January 1, 1900. For such applications, the Oracle7 Server and the Oracle8 Server provide a special year format mask, RR. Values with years between 0 and 49 that are stored in 1998 with the RR format are interpreted to be in the twenty-rst century; for example, TO DATE(000101, RRMMDD) will evaluate to January 1, 2000. This format still experiences a shift in semantics at the millennium. Say in 1998 an application attempts to store a future date of 2051, using a value string of 550101 and a format of RR. This will be interpreted as 1955. Two years later, that same value string will be interpreted as 2055. This raises a “year 2050 problem.” Summarizing, the YY format uses centuries (years having the same rst two digits are in the same century) as both the window and the window transition. The RR format has a window starting at year 50 and going to year 49, with the window transition occurring at year 0 of the century. The year 2000 is considered a leap year by Oracle8 Server.   3.7   TO DATE(2000-02-29, YYYY-MM-DD) is a valid Oracle DATE. TO DATE(2000-03-01, YYYY-MM-DD) - TO DATE(2000-02-01, YYYY-MM-DD) yields 29 Julian days. ADD MONTHS(TO DATE(2000-02-01, YYYY-MM-DD), 1) yields March 1, 2000. ADD MONTHS(TO DATE(2000-03-01, YYYY-MM-DD), -1) yields   ADD DAYS(TO DATE(2000-02-28, YYYY-MM-DD), 1) yields February 29, 2000. ADD DAYS(TO DATE(2000-03-01, YYYY-MM-DD), -1) yields February 1, 2000. February 29, 2000. SUBTLETIES* It is critical that the limitations and subtle ramications of the representation of instants provided by the DBMS be understood. As we'll see, the meaning of a temporal value is somewhat arbitrary, with the application providing some of the semantics. 3.7.1 Datetimes While an instant is, well, instantaneous, SQL and all DBMSs assume a discrete time line of various granularities, such as second, day, and year, and indicate only the particular granule in which the instant is located. The event of an individual well sample extraction occurred at a specic instant, but we may care to record only the 3.7 SUBTLETIES* 75 B . C ., A . D ., B . C . E ., C . E ., and B . P . The prevailing system before the use of B . C .–A . D ., at least in the Western world, was A . U . C . (ab urbe condita, literally, “from the foundation of the city,” which, being in Latin, of course meant Rome). Dionysius (see page 27) pegged 1 A . D . at 754 A . U . C . There is the slight problem that King Herod died in 750 A . U . C ., which translates to 4 B . C . Since Herod was ostensibly alive at the birth of Jesus, we have the interesting oxymoron of Christ being alive in 4 B . C ., that is, four years before the birth of Christ. In an effort to be less parochial, B . C . has been retermed B . C . E . (“Before the Christian Era,” or even better, “Before the Common Era”), with A . D . renamed C . E . (“Common Era”). Even more PC is B . P. (“Before the Present”), that is, interpreted with reference to the year of publication of the source. This book will have a copyright date of 1999 (as will all books published between July 1, 1998, and June 30, 1999), so the millennium will reputedly end at 1 B . P. (since it is after the present). The problem with this scheme is that it carries with it an extra obligation for the author: if this book is delayed but a few months, I will have to adjust that B . P. date above, as well as all others that appear herein. day granule in which that event occurred. If multiple tests are performed during the day on a well sample, a time granularity, An instant has no duration, but its representation as a particular say, hour or even second, may be appropriate. An instant has no duration, but its representation, as a particular granule, always granule always does. does (when utilizing a discrete time line). The concept of an instant is independent of any particular calendar. SQL has chosen the Gregorian calendar for its representation of an instant. The use of a specic calendar, especially one so infused with politics, brings with it subtle difculties. The Gregorian calendar was proclaimed by Pope Gregory XIII in 1582, with adoption by the Catholic states within a year. However, in some places adoption was very slow. The Protestant German states adopted the Gregorian calendar in 1699, Japan in 1873, and Greece only in 1923. Muslim countries tend to retain calendars based on Islam, and Asian countries generally use lunar or hybrid (solar/lunar) calendars. Consider an art dealer who has in hand a letter written by the artist Enoch Seeman stating that his “Portrait of the Countess of Berkeley” was completed on “March 23, 1735.” The art dealer entering this date in SQL as DATE 1735-03-23 would in fact be specifying a day some 11 days before the painting was nished. The reason is that before 1752 England and its colonies used the Julian calendar, which differs from the Gregorian calendar only in the presence of century leap years (in fact, this difference between the solar year and the calendar year precipitated the construction of the Gregorian calendar). So the correct denotation in SQL is DATE 1735-04-03. Had the letter been written in, say, Paris, the same day, 76 CHAPTER THREE : INSTANTS AND INTERVALS rather than at Berkeley Castle, it would have recorded the date “April 3, 1735.” The geographical location of the historical reference supplies the calendar in force, which then implies the correction, if any, required before the date can be specied in SQL. As the Gregorian calendar was undened before 1582, SQL presumably extrapolates this calendar backwards using its rules to 1 C . E ., obtaining what some have called the “proleptic Gregorian calendar” (which as has been noted is a misnomer, because “proleptic” refers to a future act). Problems occur in the opposite direction. Because the tropical year is 365.242,191 days, and the Gregorian year (due to the rather complex leap year rules, see page 37) is 365.2425 days, the calendar year will be one day longer than the astronomical year in 4000 C . E . and two days longer in 8000 C . E . A further renement to the Gregorian calendar designating years evenly divisible by 4000 as common (not leap) years would ensure accuracy to within one day in 20,000 years. If this renement was legislated, dates after 4000 C . E . stored in the database would be off by one or two days. As it is, the vernal equinox will occur on DATE 1997-03-21, DATE 4000-03-22, and DATE 8000-03-23. While my watch tells me in which second (approximately) the current instant occurs, we desire a more precise and universal denition. As mentioned, SQL uses UTC. UTC is based on cesium atomic clocks, which are accurate to within a second in a million years. A step adjustment of a fraction of a second at the beginning of each month correlates UTC with mean solar time (the average time between noons, when the sun is directly overhead). In October 1967, the second in the International System of Weights and Measures was dened to be 9,192,631,770 periods of the radiation emitted by the transition between two hyperne states of the cesium 133 atom in the ground state. On January 1, 1972, the atomic second became the practical unit of time. The UTC clock runs just a little fast with respect to mean solar time, gaining about a second a year. UTC is adjusted by applying leap seconds on January 1 or July 1 to keep UTC within 0.7 seconds of solar time. So, what does this mean for an SQL user? The database is a model of reality. An event in reality occurs at a particular instant. The representation of that instant in the database should identify the particular day, or second, or microsecond, in which the instant occurred, to the precision chosen by the user. Say that TIMESTAMP(0) is specied. Then the user is satised if the instant can be characterized to within a second. Alternatively, if the database species that an event happened at a particular timestamp value, the user would like to identify the second in reality during which the event occurred. For times between 1958 and about 1998, this correspondence between reality and its representation in an SQL-compliant database is well dened. The problem with future time is that leap seconds are determined by a committee, after reviewing astronomical records indicating how far apart solar time is from atomic time. When the differential gets too great, a leap second is mandated. Since January 1972, 3.7 SUBTLETIES* 77 22 leap seconds have been added, the last inserted just before 12:00 A . M ., January 1, 1999 (do you remember?). Specically, the sequence of UTC markers was 1998-1231 23:59:59, 1998-12-31 23:59:60, 1999-01-01 00:00:00. While it is probable that a leap second will be added in 2000, exactly when future ones will be added is a bureaucratic decision, informed by changes, which cannot be precisely predicted, that are slowing down the earth's spin. The decision is generally made around ve months before the leap second is effected. Leap seconds imply that some minutes, such as the last minute of the year 1995, contain 61 seconds. In fact, UTC allows two leap seconds to be added, so the seconds value of a TIMESTAMP is restricted to 0.0 through 61.999. . .. UTC also allows the omission of a leap second; such minutes will only contain 59 seconds. However, a leap second has not yet been omitted in the more than two decades since UTC was dened. Since UTC is coordinated with solar time, the sun will be directly overhead within 0.7 second of 2222-01-01 12:00:00. However, the number of seconds between TIMESTAMP 1997-01-15 11:35:29.123456 and that instant is not known. As we will see later, the DBMS will provide a number that should be close, within 300 seconds or so: the DBMS will assume no leap seconds in the intervening time. The number of intervening minutes is known precisely, 118,843,224, because there are no leap minutes. Leap seconds extend the minute to which they are assigned (such as 1999-12-31 23:59:60, above); they do not accumulate into a leap minute. Before 1958, UTC is not dened. One possibility is that the denition of UTC is extrapolated backward to 1 C . E . The denition of UTC in 1958 is ephemeris seconds as measured with an atomic clock, with adjustments for changes Which second an SQL timestamp in the earth's rotation. So there are at least two possibilities. One is that the proper adjustment is made each month, in that the before 1958 denotes is not rst second of each month is a little longer or shorter than the adequately specied in the other seconds, so that the solar day is coordinated with UTC. standard. The problem with this approach is that it is impossible to correlate SQL timestamps with any other time, such as unadjusted ephemeris time, used by astronomers. A second possibility is that we can assume that each minute contains exactly 60 (unadjusted) ephemeris seconds, which emphasizes equal-sized seconds but which becomes uncorrelated with the solar day as we go back in time. The moral is that no one really knows which second in reality is denoted by an SQL timestamp before 1958. Returning to the letter written by our artist Enoch Seeman, that day could have started on the second denoted by TIMESTAMP 173503-23 00:00:00, or perhaps it started at 1735-03-23 00:00:10, or perhaps even at 1735-03-22 23:55:04. Such uncertainty is frustrating. Ideally, that date should start precisely at midnight: 1735-03-23 00:00:00. But the standard is surprisingly silent on precisely what instant in reality such a value means. 78 CHAPTER THREE : INSTANTS AND INTERVALS Given this imprecision in the standard, it is the responsibility of the application designer to supply the semantics for SQL timestamp values. When a value in a specic system—be it atomic (TAI), barycentric coordinate (TCB), barycentric dynamical (TDB), ephemeris, geocentric coordinate (TCG), mean solar, sidereal, terrestrial (TT), universal (UT0, UT1, UTC), or some other system—is stored in an SQL database, it must be converted to the semantics chosen for the application. When information from two databases, with different semantics, are combined or compared, the timestamp values must be converted to a common representation. It may very well be the case that one timestamp 1735-03-23 00:00:00 from a database and a second timestamp 1735-03-22 23:55:04 from another database denote the same exact instant! Recall that an instant is an anchored location on the time line. So, which instant is denoted by TIME 11:35:29? On this, perhaps the most critical question, the standard is entirely silent. Here is the entire specication [44, pp. 24–25]: Section 4.5.1 Datetimes Therefore, datetime data types that contain time elds (TIME and TIMESTAMP) are maintained in Universal Coordinated Time (UTC), with an explicit or implicit time zone part. . . . A TIME or TIMESTAMP that does not specify WITH TIME ZONE has an implicit time zone equal to the local time zone for the SQL-session. However, the meaning [italics retained] of the time does not change, because it is effectively in UTC. An aside: the draft Technical Corrigendum 3 replaces this explanation with an equally laconic specication [19, pp. 10–11]: Section 4.5.1 Datetimes, Draft Corrigendum The surface of the earth is divided into zones, called time zones, in which every correct clock tells the same time, known as local time [italics retained]. Local time is equal to UTC (Coordinated Universal Time) plus the time zone displacement [italics retained]. . . . A datetime value, of data type TIME or TIMESTAMP, may represent a local time or UTC. Let's assume that the user is in the Mountain Standard time zone (seven hours behind Greenwich). She species in her SQL code the literal TIME 11:35:29. This particular time occurs exactly once each day in the UTC denition. So perhaps the implied meaning is that the meaning of a TIME literal (or data value) is relative to the current day. But this assumption has two unfortunate ramications. Some TIME values are dened for only about 1 in every 500 days: leap seconds, TIME 23:59:60, have occurred 22 times thus far. So if I happen to retrieve this TIME value on one of those days, everything is well dened, but if I retrieve the same value any other day, the value indicates a nonexistent instant. The second problem is that the particular instant denoted by the value is dependent on when the value is used or retrieved from the database. Consider a transaction that starts a few minutes before midnight on Monday, January 13, 1997, and runs until a few minutes after midnight on Tuesday. The literal TIME 11:35:29 when rst retrieved by the transaction denotes the instant TIMESTAMP 1997-01-13 11:35:29. Just a few 3.7 SUBTLETIES* 79 More on the Start of the Millennium This confusion between anchored and unanchored values also appears in discussions of “the millennium.” That word translated from the Latin means simply “one thousand years,” and hence is an unanchored duration: an interval. So the years 998 and 1998 differ by a millennium. However, Webster's Dictionary notes the connection with “biennium” (“a period of two years”), dening millennium to be “a period of 1000 years,” in particular, “the thousand years mentioned in Revelation 20 during which holiness is to prevail and Christ is to reign on earth.” Many different interpretations of the millennium have been given [18]: it is unclear when this thousand years will start. This confusion between interval and period thus seems to underlie the doomsayers who claim that the world will end or other fantastic happenings will occur on January 1, 2000 (or is it January 1, 2001—see page 63). Others have started the millennial clock at the supposed start of the world. It has been calculated that Jesus was born on 4000 A . M . (Annus Mundi , or “year of the world”). Given that Jesus was born in 4 B . C . (see page 75), you may want to ponder where you were at the start of the sixth millennium, or 6000 A . M ., which started Monday, October 27, 1997. (Surely you remember that momentous transition!) minutes later, the same value denotes a different instant, TIMESTAMP 1997-01-14 11:35:29, that is, an instant 24 hours later. Values with an explicit UTC offset are safer to use. Consider again Enoch Seeman's letter; say it was written on TIMESTAMP 1735-03-23 13:23:45, in the early afternoon. Now the letter was written in Berkeley Castle, which is in the same time zone as Greenwich (using time zones as they are specied today; there were no time zones in Seeman's day). However, a user in Los Angeles who retrieved this value from the database and printed it relative to GMT would see it as having been written in the wee hours of the morning. On the other hand, had the offset (in this case, +0:00) been stored with the timestamp, the desired instant would have been correctly specied and would print out correctly in GMT. In conclusion, only DATE and TIMESTAMP WITH TIME ZONE adequately specify an instant, an anchored location on An SQL-92 TIME value is really the time line. TIME is relative to an unspecied midnight, and an interval that can be added to TIMESTAMP without an associated offset acquires the time zone midnight of a particular day to of the user when the value is manipulated. specify an instant. As another subtlety, the standard states: Subclause 6.8 hdatetime value functioni General Rule 1. The hdatetime value functionis CURRENT DATE, CURRENT TIME, and CURRENT TIMESTAMP respectively return the current date, current time, and current timestamp. 80 CHAPTER THREE : INSTANTS AND INTERVALS However, that subclause goes on to state: Subclause 6.8 hdatetime value functioni General Rule 3. If an SQLstatement generally contains more than one reference to one or more hdatetime value functionis, then all such references are effectively evaluated simultaneously. The time of evaluation of the hdatetime value functioni during the execution of the SQL-statement is implementation-dependent. So an implementation is free to adopt whatever denition of “current” it wishes, including perhaps when the statement was presented to the system, or perhaps when the database was rst dened. 3.7.2 Time Zones As we saw above, TIME WITH TIME ZONE values are safer than TIME values. A careful reading of the SQL-92 standard indicates that implicit time zone displacement “is defective, in at least one respect, is imprecisely specied, does not fully implement the approach proposed [in a prior standards meeting] and leaves unsolved a problem that was acknowledged to need a solution as long ago as 1988” [101, pp. 1–2]. In the current SQL-92 standard, for a TIME value without an explicit time zone, either AT LOCAL or GMT was assumed; the standard is unclear on which is to be used. Technical Corrigendum 3 (at the time this is being written, this document is a working draft approaching ISO approval) Use TIME (without time zones) species that a TIME (without the time zone) value does not exceedingly carefully, as the have an implicit time zone; indeed, nothing is assumed about standard is imprecise and the nonexistent time zone. While some of the identied dedefective in its application of ciencies have been addressed in this way by the Technical Corimplicit time zones. rigendum, it is doubtful that the changes have migrated into commercial products. Even when the TIME WITH TIME ZONE type is used, the user should be careful. For example, given two values v1 and v2 of type TIME WITH TIME ZONE, it is possible that v1 = v2 while EXTRACT(TIMEZONE HOUR FROM v1 ) <> EXTRACT(TIMEZONE HOUR FROM v2 ), and CAST(v1 TO TIME) <> CAST(v2 TO TIME). This unintuitive semanUse TIME WITH TIME ZONE tics results from the time zone being ignored in the equality, but carefully, as the time zone not in the latter two expressions. Since many other predicates, stored in such a value is often such as OVERLAPS, are dened in terms of equality, often the ignored. time zone stored in a value is ignored. 3.7.3 Intervals The reason given for the distinction between year-month intervals and day-time intervals is that months are not an integral number of days. Melton and Simon [71] ask the question, “What is the result of 1 year, 3 months, 19 days divided by 3.7 SUBTLETIES* 81 3?” They correctly state that the answer cannot be determined unless we know the dates spanned by that interval. However, minutes are not an integral number of seconds, due to leap seconds. What if we ask the question, “What is the result of 1 minute divided by 4, in seconds?” The answer could be 14, 15, or 16, depending on which particular times were spanned by that interval (up to 2 leap seconds can be added or subtracted from a minute). So, what does the standard have to say about this? The expression INTERVAL 1 MINUTE / 4 evaluates to INTERVAL 0 MINUTE; fractional minutes are lost. However, we can explicitly request that the calculation be done in terms of seconds, either with INTERVAL 1:00 MINUTE TO SECOND / 4 or CAST(INTERVAL 1 MINUTE TO INTERVAL MINUTE TO SECOND) / 4, with the cast being implicit or explicit. Now the question is, What does cast return? Here is the entire specication [44, p. 122]. Subclause 6.10 hcast specicationi General Rule 13.d. If SD [the data type of the source expression SV , here INTERVAL 2 MINUTE] is interval and TD [the target data type, here INTERVAL MINUTE TO SECOND] and SD have different interval precisions, then let Q be the least signicant hdatetime eldi of TD [that is, SECOND]. Let Y be the result of converting SV to a scalar in units Q according to the natural rules for intervals as dened in the Gregorian calendar. Normalize Y to conform to the datetime qualier “P TO Q ” of TD. The rub lies in deciding exactly what the “natural rules for intervals as dened in the Gregorian calendar” are in the presence of leap seconds. Presumably this expression would always evaluate to 15 seconds (assuming that the “average” minute contains 60 seconds), but the specication is not clear. However, using the same logic, “What is the result of 1 year, 3 months, 19 days divided by 3?” could just as easily be interpreted to yield 3 months, 17 days, using an average length, in days, of a year and a month in the Gregorian calendar. There are at least two ways the SQL could be interpreted in its handling of intervals in a consistent manner. One is to use “average” months, and minutes, in interval conversions, and do away with the distinction between year-month and day-time intervals. The other is to not use average months or minutes, and expand the kinds of intervals to year-month, day-minute, and second (and fractions thereof) variants. Another problem surfaces as to what values are allowed for SQL intervals. The specication is laconic on this as well [44, p. 75]: Subclause 5.3 hliterali Syntax Rule 23. Within the denition of an hinterval literali, the hdatetime valueis are constrained by the natural rules for intervals according to the Gregorian calendar. Whether or not leap seconds are included in day-time intervals is not specied in the SQL-92 standard. Most days have 24 hours. The day in April that daylight saving time kicks in has only 23 hours; the day in October that daylight saving time ends contains 25 hours. Similarly, minutes can have 62 seconds (though up to 1999 only one leap second has ever been added to any particular minute), as mentioned in this standard [44, p. 25]. 82 CHAPTER THREE : INSTANTS AND INTERVALS Section 4.5.1 Datetimes Note: On occasion, UTC is adjusted by the omission of a second or the insertion of a “leap second” in order to maintain synchronization with sidereal time. This implies that sometimes, but very rarely, a particular minute will contain exactly 59, 61 or 62 seconds. However, no such mention is made of days with 25 hours. Hence, the standard is not clear as to whether the maximum value of the hours eld is 24 or 25, or whether the maximum value of the seconds eld is 60, 61, or 62. 3.7.4 Predicates The OVERLAPS predicate could have been easily generalized, but wasn't. For example, the following forms are not permitted, even though they make perfect sense: BirthDate OVERLAPS DATE 1970-01-01 BirthDate OVERLAPS (DATE 1970-01-01, INTERVAL 0 DAY) (DATE 1970-01-01, INTERVAL 0 DAY) OVERLAPS BirthDate We could argue that all three are equivalent to BirthDate = DATE 1970-01-01 but the discussion in Section 3.3 shows that orthogonality was not a priority in SQL's design. If the intervals in the last two are replaced with a nonempty interval, say, INTERVAL 7 DAY (within a week), then they are not equivalent to the rst. Again, we could argue that those would be equivalent to (BirthDate, INTERVAL 0 DAY) OVERLAPS (DATE 1970-01-01, INTERVAL 7 DAY) (DATE 1970-01-01, INTERVAL 7 DAY) OVERLAPS (BirthDate, INTERVAL 0 DAY) or (BirthDate, NULL) OVERLAPS (DATE 1970-01-01, INTERVAL 7 DAY) (DATE 1970-01-01, INTERVAL 7 DAY) OVERLAPS (BirthDate, NULL) but it seems less desirable to require an empty or null interval. In the same vein, it would have been nice to allow equality and inequality comparisons between these period information values, such as (BirthDate, INTERVAL 7 DAY) = (DATE 1970-01-01, INTERVAL 7 DAY) (DATE 1970-01-01, INTERVAL 7 DAY) <= (BirthDate, INTERVAL 9 DAY) As it is, SQL-92 introduces these period information values with their concomitant complex syntax rules just for the OVERLAP predicate. 3.8 3.7.5 IMPLEMENTATION CONSIDERATIONS* 83 Constructors The CAST function is not symmetric, in the following way. This is being written at 4:57 P. M . on July 23, 1997. The expression CAST(TIME 12:34:56 AS TIMESTAMP(0)) yields 1997-07-23 12:34:56, that is, that time today, but CAST(DATE 1997-0101 AS TIMESTAMP(0)) yields TIMESTAMP 1997-01-01 00:00:00. This asymmetry appears to be a reasonable design decision, as chances are that something that happened at some other date probably did not happen at exactly the same time of day as “now.” 3.8 IMPLEMENTATION CONSIDERATIONS* Here we consider subtleties of instants and intervals in specic DBMSs. 3.8.1 IBM DB2 Universal Database IBM DB2 UDB will generate an error if a eld value (e.g., 60 seconds, 24 hours) was out of range. Hence, every minute in DB2 contains exactly 60 seconds; leap seconds are not accommodated. 3.8.2 Microsoft Access Access interprets the fractional portion of a DATE as a fraction of a day, effectively dividing each day into 86,400 seconds. Hence, every minute in Access contains exactly 60 seconds; Access DATEs do not take into account leap seconds. Access will generate a runtime error if the eld value (e.g., 60 seconds, 24 hours) was out of range. 3.8.3 Oracle8 Server Oracle8 Server date arithmetic takes into account the (Catholic) switch from the Julian to the Gregorian calendar, which eliminated 10 days in October 1582 (October 5 through October 14). Missing dates can be entered into the database, but are ignored in date arithmetic and treated as the next date. For example, the next day after October 4, 1582, is October 15, 1582, and the day following October 5, 1582, is October 15, 1582. Specically, all the dates between October 5 and October 14 are mapped identically to October 15. As the maximum number of seconds in a minute in Oracle8 Server is 60, Oracle DATEs do not take into account leap seconds. Instead, Oracle8 Server will generate a runtime error if the eld value (e.g., 60 seconds, 24 hours) was out of range. 84 CHAPTER THREE : INSTANTS AND INTERVALS The Adoption of the Gregorian Calendar As the Gregorian calendar was imposed by at by a sitting pope (see page 37), adoption was quick in Roman Catholic countries, but decidedly unenthusiastic in Protestant countries. Britain and its colonies (which includes what is now the United States) didn't adopt the Gregorian calendar until 1752. Because it waited so long, Parliament had to drop 11 days (September 3–13, 1752) in order to catch up. George Washington's birthday was recorded at the time as February 11, 1731; this is a Julian date because Britain hadn't yet switched over. However, President George Wash- 3.8.4 ington's birthday is celebrated in the United States on February 22, its Gregorian date (at least until a Presidents' Day was instituted covering for both Washington's birthday and Lincoln's birthday, which occurred after the switch). The U.S.S.R. didn't join the bandwagon until 1918. The “October Revolution” happened in a Julian October; until recently it has been celebrated in Gregorian November. In fact, there are many different switchover dates (e.g., Sweden, 1753; Turkey, 1927), rendering “the Gregorian calendar” an oxymoron. CD-ROM Materials Detailed explanations of the temporal types in Microsoft Access 2000, Microsoft SQL Server, IBM DB2 UDB, Informix–Universal Server, Oracle8 Server, Sybase SQLServer, and UniSQL are provided, as well as sample SQL statements illustrating operations on instants and intervals. For some of the operations that are not possible in IBM DB2 strictly in SQL, the equivalents are given as embedded SQL. A detailed explanation of Ingres is also included on the CD-ROM, but the examples have not been tested. 3.9 SUMMARY Temporal values are the stuff of which time-varying applications are made. In order to record the history of the modeled reality, it is rst necessary to be able to record the “when.” Instants are the most basic data type. An instant is a position on the time line. Virtually all DBMSs support this data type. In SQL-92, ve related data types encode instants, to various granularities: DATE, TIME, TIMESTAMP, TIME WITH TIME ZONE, and TIMESTAMP WITH TIME ZONE. Intervals are unanchored, directed portions of the time line; an interval can be added to an instant to displace that instant either into the future or back into the past. SQL-92 supports two kinds of intervals, year-month intervals and day-time intervals. 3.10 READINGS 85 A rich set of operators and predicates applies to temporal values. SQL-92 provides the following classes of predicates: equality, inequality, is null, and overlaps. It also provides arithmetic operators (`+', `-', `*', `/'), unary plus and minus, time zone conversion (AT), “now” (CURRENT TIME, CURRENT DATE, CURRENT TIMESTAMP), a variety of conversions (CAST), and eld extraction (EXTRACT). Specic DBMSs vary greatly in their support of the standard, from quite strict adherence (e.g., IBM DB2) to studied apathy (most DBMSs). While most temporal operations in SQL-92 can be simulated in the facilities of the various DBMSs (and vice versa), that simulation is often unnecessarily convoluted. Despite the care with which the SQL-92 standard has been developed and documented, it still contains dark corners and seemingly arbitrary design decisions. Most DATE and TIMESTAMP values are undened, as the standard is based on UTC, which doesn't apply before 1958. SQL-92, and virtually all DBMSs, utilize the Gregorian calendar, which was adopted in different parts of the world over a 350-year period. A TIME value does not actually represent an instant; rather, it represents a special kind of interval. Leap seconds may or may not be accommodated (the standard doesn't say); most DBMSs ignore this subtlety. 3.10 READINGS Information on the Public Petroleum Data Model can be found at www.ppdm.org. Datetime literals are based on an ISO standard, “Representation of Dates and Times” [43]. This standard uses the Gregorian calendar as well as a 24-hour clock, which also serve as the basis for SQL datetimes. While the SQL-92 standard [44] is quite lengthy, at 580 pages, only a small portion, about 30 pages, or 5 percent, concerns temporal data types and their operators. However, this portion in some ways is more complex than other parts of SQL, as evidenced by over 12 pages (almost 10 percent) of the Technical Corrigendum 3 [19]. Even with these numerous corrections, many of the deciencies discussed in Section 3.7 remain. Sykes provides a cogent discussion of the problems, and partial solutions, to time zone support in SQL-92 [101]. The temporal constructs are included in the Intermediate SQL and Full SQL levels of conformance to SQL-92; the Entry SQL level of conformance includes no temporal types. Conformance testing was initially done by the National Institute of Standards and Technology (NIST), a U.S. Department of Commerce agency. As of July 1, 1997, when NIST ceased SQL conformance testing, 11 products had been validated for conformance to FIPS publication 127-2 [73]: IBM (2 congurations), Informix (5 congurations), NCR, and Sybase (3 congurations). Unfortunately, all of these validations were at Entry FIPS 127-2, which includes no time support. The National Software Testing Laboratories (NSTL), an independent organization not 86 CHAPTER THREE : INSTANTS AND INTERVALS associated with the government, has established a testing and certication program for SQL at www.nstl.com/html/press nstl establishes sql conformance testing.html. Unfortunately, according to NSTL, “All of NSTL's testing services are conducted on a strictly condential basis. Clients. . . have used NSTL test results for promotional purposes,” so information about which products conform to the standard will come only from the vendors themselves. Books and articles on the year 2000 problem could ll an entire shelf of your library. A quick search on amazon.com turned up over several dozen titles; there is even a Year 2000 for Dummies [16]. (Some book titles to the contrary, the proper spelling is “millennium,” with two ns, from the Latin mille, “one thousand,” and annus, “year,” whereby the two ns.) The following are some useful Web sites providing further pointers:           The Year 2000 Information Center: www.year2000.com U.S. Federal Government Gateway for Year 2000 Information Directories: www.itpolicy.gsa.gov/mks/yr2000/y2khome.htm National Institute of Standards and Technology: www.nist.gov/y2k/ Information Technology Association of America (ITAA): www.itaa.org/year2000.htm Mitre's Year 2000 home page: www.mitre.org/technology/y2k/ The Federal Technology Service of the General Service Administration (GSA) of the U.S. Federal Government: www.fts.gsa.gov The IEEE Technical Activities Board (TAC) New Technologies Development Committee: www.mindspring.com/pci-inc/Year2000/y2ktech.htm IBM's Year 2000 home page: www.ibm.com/IBM/year2000/ Microsoft Year 2000 Resource Center: microsoft.com/year2000/ Newsgroup: comp.software.year-2000 The year 2000 problem isn't unique to computers. The July 1998 issue of Consumer Reports (p. 67) describes a (manual) Mead 10-year date stamp that had been purchased in March of that year. The reader subsequently found out that the date stamp was good only until December 31, 2000. As the packaging copyright says 1993, this was at best an 8-year date stamp when it was manufactured. Perhaps at the turn of the century there will be a run on ofce supply stores when all of the 10-year date stamps expire. Jones [59] lists other year 2000–like problems, many of which in a cruel irony just happen to fall right around the same time: the conversion of the euro, which started January 1, 1999, the Global Positioning System (GPS) week-counter rollover, which occurs at midnight on August 21, 1999, the use of the value 9999 as a le termination code, which might be misinterpreted as September 9, 1999, and the use in Unix of the number 999999999 as end-of-le, which can be interpreted as a 3.10 READINGS 87 Unix date of September 8, 2001. Neumann [75] provided the Multics observation on page 65. The SQL standards are denoted SQL-86, SQL-89, and SQL-92. You might think that the next standard, due out in 1999, would be named SQL-99. Logically, then, the standard following that might be named SQL-02, which might be confused with SQL2 (the project name under which SQL-92 was developed). The resolution was to term the next standard SQL:1999, thereby avoiding a year 2000 problem with the name of the standard [30]. An impressive amount of information on UTC and leap seconds can be found at tycho.usno.navy.mil/time.html. Papers by Dyreson, Howse, Quinn, and the author provide details on UTC and ephemeris time [28, 42, 79]. While UTC is dened relative to an atomic clock, an ephemeris second is a constant duration of time: 1/31,556,925.9747 of the period of time between the passage in 1899 and the passage in 1900 of the sun through the vernal equinox, when the duration of sunlight and darkness are the same. While this may seem an odd denition, the ephemeris second is actually the average value of a second calculated from astronomical observations over the 18th and 19th centuries. HAL was the computer featured prominently in Arthur C. Clarke's 2001: A Space Odyssey. Its (his?) birth date, January 12, 1997, was occasioned by the release of a book on HAL's legacy [100]. Oracle's temporal support is described well in Koch and Loney's encyclopedic reference book [63, ch. 7]. See bert.cs.pitt.edu/tawg/convert/introduction.html for a discussion of the Hijri calendar, supported by Microsoft Access. Dershowitz and Reingold's beautiful book, Calendrical Calculations [27], presents in completely algorithmic form a description of 14 calendars: the present civil calendar (Gregorian), the recent ISO commercial calendar (ISO 8061), the old civil calendar (Julian), the Coptic and Ethiopic calendars, the Islamic (Moslem) calendar, the modern Persian (solar) calendar, the Bahá'´ calendar, the Hebrew (Jewish) calendar, the Mayan calendar, the French Revolutionary calendar, the Chinese calendar, and both the old (mean) and new (true) Hindu (Indian) calendars. Included is a wealth of historical material. The mere existence of Dershowitz and Reingold's book is illustrative of the inherent complexities of the subject. CHAPTER 4 O V E R V I E W A period is a segment of the time line, starting SQL-92 has essentially one construct, OVER- at one instant and terminating at a later instant. LAPS, that is relevant to periods. However, the While there are a variety of representations draft SQL3 standard includes a period type conof periods, one particular representation is structor, period literals, predicates, and value preferable. Periods are more complex than instants, because there is no total order on periods, unlike instants. constructors. Periods A n instant has no duration. Yet facts in the database are true over a duration of time. To express when a fact holds in the enterprise, a period is associated with that fact. A period is an anchored duration of the time line. The Fall 1997 academic semester at the University of Arizona comprises the period from August 25, 1997 to December 19, 1997. This data type, while quite useful, is not supA period is an anchored duration ported directly by any commercial DBMS, nor is it in the SQL92 standard. However, periods are in the SQL3 draft standard, as of the time line. will be discussed in Section 12.4. Perhaps the reason that periods were not included with the other temporal types in SQL-92 is that they are relatively easy to simulate with datetimes. The most common representation is with a pair of instants, the rst specifying the rst day (second, microsecond) of the period and the second specifying the last day (second, microsecond) of the period. Generally the delimiting datetimes are of identical granularity. Jim Barnett utilized periods in several places in the F INDER schema. The Create Date and Last Update columns indicate when the data was stored in the database. Many tables also have Start Date and End Date columns to specify when the data was valid in reality. These two, quite different notions are explored in detail in Chapters 8 and 5, respectively. There are several variants possible even with an instant-pair representation of periods. One common representation is termed a closed-closed representation because both delimiting datetimes are in the period. For the Fall 1997 semester, the pair of dates would be [DATE 1997-08-25, DATE 1997-12-19], with the square brackets denoting a closed representation. An alternative is the closed-open representation, in which the second datetime of the pair represents the granule immediately following the last granule of the period. Our example in a closed-open representation is thus [DATE 1997-08-25, 90 CHAPTER FOUR : PERIODS DATE 1997-12-20). The ending parenthesis indicates that the ending is open. We'll examine the relative advantages of each of these representations shortly. Two less often used alternatives are open-closed and openopen. The primary representations of Yet another alternative is the starting datetime and an inperiods are closed-closed and terval specifying the duration of the period. In this approach, closed-open pairs of datetimes, and a pair of a starting datetime the Fall 1997 semester becomes (DATE 1997-08-25, INTERVAL 117 DAY). Finally, for completeness, we might use the termiand an interval, with both nating datetime and the duration, for example, (INTERVAL 117 components of the same DAY, DATE 1997-12-19). We could also consider open variants granularity. thereof, but that is not productive. The delimiting datetime(s) of a period may include a time zone, if their granularity is to the hour or smaller. The Fall 1997 semester to the second granularity in the closed-open representation with a time zone of Mountain Standard Time is [TIMESTAMP 1997-08-25 08:00:00-07:00, TIMESTAMP 1997-12-19 17:00:00-07:00). This example hints at the utility of the closed-open representation. In the closedclosed representation, the terminating timestamp would be an The time zone of a period, if any, awkward TIMESTAMP 1997-12-19 16:59:59-07:00. The two deshould be stored with the rst limiting datetimes of a stored period should have an identical datetime of the representation. time zone, for the reasons given in Section 3.7.2. 4.1 LITERALS As SQL-92 does not provide a period data type, there are no period literals in that language. Periods must instead be specied by their constituent datetime and interval literals. 4.2 PREDICATES As we saw in the previous chapter, SQL-92 supports only four classes of predicates on datetimes and intervals: equality, less-than, is null, and overlaps. Equality on periods can be implemented using their underlying components, as shown in Table 4.1. Here, the expresEquality testing on periods is sion “+ 1” denotes adding one granule at the granularity of highly dependent on their the period. At a granularity of day, this expression would be “+ underlying representation. INTERVAL 1 DAY”. Testing for is null is straightforward in any of these representations: simply apply IS NULL to the rst component, which is always a datetime. If the rst component is null, the value of the second component is irrelevant. 4.2 PREDICATES 91 Table 4.1 The equality predicate on periods. Representation [a 1 , [a 1 , [a 1 , [a 1 , [a 1 , [a 1 , (a 1 , (a 1 , (a 1 , Equality Predicate a 2 ] equals [b 1 , b 2 ] a 2 ] equals [b 1 , b 2 ) a 2 ] equals (b 1 , b ) a 2 ) equals [b 1 , b 2 ] a 2 ) equals [b 1 , b 2 ) a 2 ) equals (b 1 , b ) a ) equals [a 2 , b 1 ] a ) equals [a 2 , b 1 ) a 1 ) equals (a 2 , a 2 ) i i i i i i a1 a1 a1 a1 a1 a1 a1 a1 a1 = = = = = = + + = b 1 AND a 2 = b 2 b 1 AND a 2 + 1 = b 2 b 1 + 1 AND a 2 + 1 = b 1 + b b 1 AND a 2 = b 2 + 1 b 1 AND a 2 = b 2 b 1 + 1 AND a 2 = b 1 + b 1 = a 2 AND a 1 + a = b 1 + 1 1 = a 2 AND a 1 + a = b 1 a 2 AND a 1 = a 2 i i i i i i Unlike datetimes and intervals, periods are not ordered. There is only a partial order between periods. Consider the Fall 1997 semester and the calendar year 1997. The calendar year both starts before the semester and ends after the semester. However, the month of July 1997 denitely precedes the Fall 1997 semester. While two datetimes or intervals can be related in three ways (before, equal, and after), two periods can have one of 13 relaWhile datetimes and intervals tionships, shown in Figure 4.1. In this gure, time proceeds from are totally ordered, periods are left to right. These relationships are disjoint: only one can hold only partially ordered, with 13 between any two given periods. Note also that a overlaps b is possible relationships between more restrictive than SQL's OVERLAPS, which will be discussed two periods. shortly. These relationships can be expressed in terms of comparisons on the components of the underlying periods. Table 4.2 provides the SQL-92 equivalents for the relationships, except for equals, which was provided before, and the inverse relationships (e.g., before 1 ), which can be easily derived. This table assumes both argument periods are in the same representation, with the same granularity. Here, ai is the interval component of the period a, and a1 and a2 are its datetime components. Note the niggling “+ 1” and “<=” that keep popping up with the closed-closed representation, and the interval addition that The preferred representation of is present with the interval representation. It is for these reasons a period is a closed-open pair of that the closed-open representation is generally preferred. datetimes. As mentioned in the previous chapter, SQL-92 provides an OVERLAPS predicate, on pairs of two datetimes, corresponding to a closed-open representation, or pairs of a datetime and an interval (see page 35). In our terminology, p OVERLAPS q (the SQL-92 predicate) is equivalent to the following using the basic predicates just introduced: p overlaps q _ p overlaps 1 q _ p starts q _ p starts 1 q _ p nishes q _ p nishes 1 q _ p during q _ p during 1 q _ p equals q. 92 CHAPTER FOUR : PERIODS a before b a b b before -1 a a meets b a b b meets -1 a a a overlaps b b b overlaps -1a a b a equals b a starts b a b starts -1a b a a finishes b b finishes -1a b a a during b b during -1a b Figure 4.1 Relationships between two periods. SQL-92 also permits a BETWEEN predicate for datetimes and intervals (see page 35). Such a predicate doesn't strictly apply to periods, as it is dened in terms of less-than. We might wish to dene a between predicate on periods based on before. A period can also be compared with a datetime of identical granularity. Conceptually, a datetime is simply a very short When comparing a datetime period, comprising one granule. Five of the predicates are not with a period, consider the possible between a datetime and a period: overlaps, overlaps 1 , datetime to be a period of a during 1 , starts 1 , and nishes 1 , due to the existence of only single granule in duration. one granule in a datetime. The rest are listed in Table 4.3. Note that a datetime is considered to be analogous to a closed-closed period. In the remainder of this book, we will utilize the preferred representation of a period, that of a closed-open pair of datetimes, of identical granularity. 4.3 CONSTRUCTORS 93 Table 4.2 The inequality predicates on periods. Relationship [a 1 , [a 1 , (a 1 , [a 1 , [a 1 , (a 1 , [a 1 , [a 1 , (a 1 , SQL-92 Predicate a 2 ] before [b 1 , b 2 ] a 2 ) before [b 1 , b 2 ) a ) before (b 1 , b ) a 2 ] meets [b 1 , b 2 ] a 2 ) meets [b 1 , b 2 ) a ) meets (b 1 , b ) a 2 ] overlaps [b 1 , b 2 ] a 2 ) overlaps [b 1 , b 2 ) a ) overlaps (b 1 , b ) i i i i i i a2 a2 a1 a2 a2 a1 a1 a1 a1 + 1 < b1 < b1 + a < b1 + 1 = b1 = b1 + a = b1 < b 1 AND a 2 < b 2 AND b 1 <= a 2 < b 1 AND a 2 < b 2 AND b 1 < a 2 < b 1 AND a 1 + a < b 1 + b AND b 1 <= a 1 + a < a 1 AND a 2 < b 2 < a 1 AND a 2 < b 2 < a 1 AND a 1 + a < b 1 + b = b 1 AND a 2 < b 2 = b 1 AND a 2 < b 2 = b 1 AND a < b < a 1 AND a 2 = b 2 < a 1 AND a 2 = b 2 < a 1 AND a 1 + a = b 1 + b i i i i i [a 1 , [a 1 , (a 1 , [a 1 , [a 1 , (a 1 , [a 1 , [a 1 , (a 1 , 4.3 a 2 ] during [b 1 , b 2 ] a 2 ) during [b 1 , b 2 ) a ) during (b 1 , b ) a 2 ] starts [b 1 , b 2 ] a 2 ) starts [b 1 , b 2 ) a ) starts (b 1 , b ) a 2 ] nishes [b 1 , b 2 ] a 2 ) nishes [b 1 , b 2 ) a ) nishes (b 1 , b ) i i i i i i b1 b1 b1 a1 a1 a1 b1 b1 b1 i i i i i i CONSTRUCTORS Periods may participate in, or be returned by, temporal constructors. We organize this discussion along the types that such constructors can return. 4.3.1 Datetime Constructors The datetime constructors that involve periods are also called instant extractors, as they identify the delimiting instants of the argument period. Note especially here that the semantics of such constructors (and indeed, of all constructors, and all predicates) is independent of the representation, though their implementation is certainly highly dependent on the representation. Four such delimiting instants are relevant: the beginning instant , the last instant , the ending instant (that immediately following the last instant), and the previous instant (that immediately preceding the beginning instant). For our closed-open representation p = [a1 , a2 ), these instants can be extracted in the following fashion. Here we use the period of the Fall 1997 semester, p = [DATE1997-08-25, DATE 1997-12-20). 94 CHAPTER FOUR : PERIODS Table 4.3 Predicates on a period and a datetime. a a a a a a a a a a a a a a a a a a a a a a a a     4.3.2 Relationship SQL-92 Predicate equals [b 1 , b 2 ] equals [b 1 , b 2 ) equals (b 1 , b ) before [b 1 , b 2 ] before [b 1 , b 2 ) before (b 1 , b ) before 1 [b 1 , b 2 ] before 1 [b 1 , b 2 ) before 1 (b 1 , b ) meets [b 1 , b 2 ] meets [b 1 , b 2 ) meets (b 1 , b ) meets 1 [b 1 , b 2 ] meets 1 [b 1 , b 2 ) meets 1 (b 1 , b ) during [b 1 , b 2 ] during [b 1 , b 2 ) during (b 1 , b ) starts [b 1 , b 2 ] starts [b 1 , b 2 ) starts (b 1 , b ) nishes [b 1 , b 2 ] nishes [b 1 , b 2 ) nishes (b 1 , b ) a = b 1 AND a = b2 a = b 1 AND a + 1 = b2 a = b 1 AND b = 1 a + 1 < b1 a + 1 < b1 a < b1 b2 + 1 < a b2 < a b1 + b < a a + 1 = b1 a + 1 = b1 a = b1 b2 + 1 = a b2 = a b1 + b = a b 1 < a AND a < b2 b 1 < a AND a + 1 < b2 b 1 < a AND a < b1 + b a = b 1 AND a < b 2 a = b 1 AND a + 1 < b 2 a = b 1 AND b > 1 a = b 2 AND b 1 < a a + 1 = b 2 AND b 1 < a a + 1 = b 1 + b AND b > 1 i i i i i i i i i i i i i i i beginning: a1 (the rst day in the period) beginning(p) = DATE 1997-08-25 previous: a1 - 1 (the day immediately preceding the period) previous(p) = DATE 1997-08-24 last: a2 - 1 (the last day in the period) last(p) = DATE 1997-12-19 ending: a2 (the day immediately following the period) ending(p) = DATE 1997-12-20 Interval Constructors There are two useful interval constructors that take a period as an argument. The rst, duration, can be computed from [a1 , a2 ) as (a2 - a1 ) qual. As an example, the period of the Fall 1997 semester has a duration of (DATE 1997-12-20 - DATE 1997-08-25) DAY 4.3 True and Sidereal Days Observing the rising and setting of distant stars yields a sidereal day, or one full spin of the earth, of 23 hours and 56 minutes. But it is perhaps more natural to judge the day by the apparent motion of the sun. The true solar time or true time is the hour-angle of the sun starting from noon. The rotation of the earth around the sun adds 4 minutes to the true, or solar day: this small additional spin is necessary to return the sun to directly overhead. The true day is thus 24 hours long. Over the course of a year, the small rotations add up to a single full rotation. A sidereal year is thus composed of one more (sidereal) day than a tropical year; it is 366.2422 sidereal days long. 4.3.3 CONSTRUCTORS 95 The other useful interval constructor is time zone extraction, which returns the time zone of the argument interval, if the delimiting datetimes have an associated time zone. In SQL, this can be done by extracting the time zone hour and minute from the initial datetime, then converting to an interval: CAST(EXTRACT(TIMEZONE HOUR FROM a 1 ) AS HOUR) + CAST(EXTRACT(TIMEZONE MINUTE FROM a 1 ) AS MINUTE) The result is an interval of granularity HOUR TO MINUTE. Period Constructors There are several constructors that return a period value. Figure 4.2 illustrates some of these.           [a, a + 1) converts the datetime a into a period of one granule. [a1 , a2 ) + INTERVAL i yields [a1 + i, a2 + i). This shifts the period later by the interval, or earlier, if the interval is negative. INTERVAL i + [a1 , a2 ) yields [a1 + i, a2 + i), as addition is symmetric. [a1 , a2 ) - INTERVAL i yields [a1 - i, a2 - i). This shifts the period earlier by the specied interval. a1 extend a2 yields [a1 , a2 + 1), that is, the period from a1 to a2 . [a1 , a2 ) extend [b1 , b2 ) yields [min(a1 , b1 ), max(a2 , b2 )), that is, the period that starts the earlier of periods a and b and nishes the later of periods a and b. a extend [b1 , b2 ) yields [min(a, b1 ), max(a, b2 )), that is, the period that starts the earlier of instant a and period b and nishes the later of instant a and period b. [a1 , a2 ) extend b yields [min(a1 , b), max(a2 , b)), because extend is symmetric. By using AT LOCAL and AT TIME ZONE on the initial datetime in the period representation, the time zone offset of a period can be changed. By CASTing each of the constituent components, the granularity of a period can be changed. 96 CHAPTER FOUR : PERIODS a b b a a b b a a extend b a b a - b a a b b Figure 4.2 Period operations. The following constructors impose restrictions on the argument periods:   [a1 , a2 ) \ [b1 , b2 ) yields [max(a1 , b1 ), min(a2 , b2 )), that is, the period that starts the later of the beginning of periods a and b and nishes the earlier of the end of periods a and b. Note that this constructor is dened only if a OVERLAPS b; otherwise, an invalid period is returned, one in which the starting delimiting instant occurs after the ending delimiting instant. [a1 , a2 ) - [b1 , b2 ) yields — [b2 , a2 ) if a starts 1 — [a1 , b1 ) if a nishes b or a overlaps 1 1 b, b or a overlaps b, or — a , if a before b or a meets b or a meets 1 b or a before 1 b. Period difference results in the portion of a not overlapping with b . Note that this constructor is undened if a during b because then there are two subperiods 4.4  4.3.4 97 IMPLEMENTATION CONSIDERATIONS of a that are not in b. This constructor is also undened if a equals b or a during b , or a starts b, or a nishes b because then the result is the empty period. [a1 , a2 ) [ [b1 , b2 ) yields [min(a1 , b1 ), max(a2 , b2 )), that is, the period that starts the earlier of the starting delimiters of periods a and b and nishes the later of the ending delimiters of periods a and b. This constructor is undened if a before b or a before 1 b; otherwise, an invalid period is returned, one that contains instants that are not in either a or b . Note that under this restriction, [a1 , a2 ) [ [b1 , b2 ) = [a1 , a2 ) extend [b1 , b2 ). Character Constructors A period can be cast into a character string via casts on its constituent parts and string concatenation (“jj”). [ 4.4 jj CAST( a 1 AS CHARACTER) jj  -  jj CAST( a 2 AS CHARACTER) jj ) IMPLEMENTATION CONSIDERATIONS A period data type is not included in the SQL-92 standard, and no vendor offers support for such a data type. In the following, we show how periods can be simulated using a pair of instants. 4.4.1 IBM DB2 Universal Database We use the closed-open representation of a pair of IBM DB2 UDB DATEs (or TIMEs, or TIMESTAMPs). Table 4.4 shows how the period operations can be implemented in DB2. In the rst column, a and b denote datetime values. In the DB2 column, p1 and p 2 denote the two components of the representation of the period p , a and b denote DB2 UDB DATE values (we use a day granularity here), and i denotes a DB2 UDB DECIMAL(8,0) representing a date duration. A constraint can be used to ensure that the starting date of a period is before the ending date. 4.4.2 Informix–Universal Server We use the closed-open representation of a pair of DATEs (or DATETIMEs). Table 4.5 shows how the period operations can be implemented in Informix–Universal Server. In the rst column, a and b denote instant values. In the Informix–Universal Server column, p1 and p 2 denote the two components of the representation of the period p , a and b denote Informix DATE values (we use a day granularity here), and i denotes an Informix INTERVAL DAY representing a date duration. Some of the temporal predicates can be conveniently dened as SPL PROCEDUREs. A constraint can be used to ensure that the starting date of a period is before the ending date. 98 CHAPTER FOUR : PERIODS Table 4.4 Period operations in IBM DB2 UDB. Period Operations IBM DB2 UDB Equivalent Types: period [DATE, DATE) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q2 p nishes q p nishes 1 q p OVERLAPS q p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 p 1 - 1 DAY p 2 - 1 DAY p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i p extend q p extend a a extend p = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL [p 1 + i, p 2 + i) [p 1 + i, p 2 + i) [p 1 - i, p 2 - i) [ CASE WHEN p1 < q 1 THEN p 1 ELSE q 1 END, CASE WHEN p 2 < q 2 THEN q 2 ELSE p 2 END ) [ CASE WHEN p1 < a THEN p 1 ELSE a END, CASE WHEN p 2 <= a THEN a + 1 DAY ELSE p 2 END ) [ CASE WHEN p1 < a THEN p 1 ELSE a END, CASE WHEN p 2 <= a THEN a + 1 DAY ELSE p 2 END ) 4.4 IMPLEMENTATION CONSIDERATIONS Table 4.4 (continued) Period Operations Period Constructors, continued: a extend b p \q p-q p [q p AT TIME ZONE i p AT LOCAL Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) IBM DB2 UDB Equivalent [ CASE WHEN a < b THEN a ELSE b END, CASE WHEN a < b THEN b + 1 DAY ELSE a + 1 DAY END ) [ CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL WHEN p 1 < q 1 THEN q 1 ELSE p 1 END, CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL WHEN p 2 < q 2 THEN p 2 ELSE q 2 END ) [ CASE WHEN q 1 <= p 1 AND p 2 <= q 2 THEN NULL WHEN p 1 < q 1 AND q 2 < p 2 THEN NULL WHEN p 2 > q 2 AND p 1 < q 2 THEN q 2 ELSE p 1 END, CASE WHEN q 1 <= p 1 AND p 2 <= q 2 THEN NULL WHEN p 1 < q 1 AND q 2 < p 2 THEN NULL WHEN q 1 < p 2 AND p 2 > q 1 THEN q 1 ELSE p 2 END ) [ CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL WHEN p 1 < q 1 THEN p 1 ELSE q 1 END, CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL WHEN p 2 < q 2 THEN q 2 ELSE p 2 END ) not supported [p 1 + CURRENT TIMEZONE, p 2 + CURRENT TIMEZONE) [ a, a + 1 DAY ) [ CONCAT CHAR(p 1 ) CONCAT - CONCAT CHAR(p 2 ) CONCAT ) 99 100 CHAPTER FOUR : PERIODS Table 4.5 Period operations in Informix–Universal Server. Period Operations Informix– Universal Server Equivalent Types: period [DATETIME, DATETIME) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q2 p nishes q p nishes 1 q p OVERLAPS q p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 p 1 - INTERVAL(1) DAY p 2 - INTERVAL(1) DAY p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i p extend a p q p-q p q p AT TIME ZONE i p AT LOCAL [p 1 + i, p 2 + i) [p 1 + i, p 2 + i) [p 1 - i, p 2 - i) not possible not possible not possible not possible not supported not supported Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) [a, a + INTERVAL(1) DAY) not possible \ [ = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL 4.4 4.4.3 IMPLEMENTATION CONSIDERATIONS 101 Microsoft Access We use the closed-open representation of a pair of Microsoft Access DATEs, which are at the second granularity. Table 4.6 shows how the period operations can be implemented in Microsoft Access 2000. In the rst column, a and b denote datetime values. In the Access column, p1 and p 2 denote the two components of the representation of the period p , a and b denote Access DATE values, and j denotes an Access NUMBER representing Julian days (and fractional days). 4.4.4 Microsoft SQL Server We use the closed-open representation of a pair of Microsoft SQL Server DATETIMEs, which are at the subsecond granularity (1/300 second). Table 4.7 shows how the period operations can be implemented in SQL Server. In the rst column, a and b denote datetime values. In the Microsoft SQL Server column, p1 and p 2 denote the two components of the representation of the period p , a and b denote SQL Server DATETIME values, and i denotes an SQL Server INTEGER representing an integral number of seconds. 4.4.5 Sybase SQLServer We use the closed-open representation of a pair of Sybase SQLServer DATETIMEs, which are at the subsecond granularity. Table 4.8 shows how the period operations can be implemented in Sybase. In the rst column, a and b denote datetime values. In the Sybase column, p1 and p 2 denote the two components of the representation of the period p , a and b denote SQLServer DATETIME values, and i denotes an SQLServer INTEGER representing an integral number of seconds. 4.4.6 Oracle8 Server We use the closed-open representation of a pair of Oracle DATEs, which are at the second granularity. Table 4.9 shows how the period operations can be implemented in Oracle8 Server. In the rst column, a and b denote datetime values. In the Oracle8 Server column, p1 and p 2 denote the two components of the representation of the period p , a and b denote Oracle DATE values, and j denotes an Oracle NUMBER representing Julian days. 4.4.7 UniSQL We use the closed-open representation of a pair of UniSQL TIMESTAMPs, which are at the second granularity. Table 4.10 shows how the period operations can be implemented in UniSQL. In the rst column, a and b denote datetime values. In the UniSQL column, p1 and p 2 denote the two components of the representation 102 CHAPTER FOUR : PERIODS Table 4.6 Period operations in Microsoft Access 2000. Period Operations Microsoft Access 2000 Equivalent Types: period [DATE, DATE) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q 2 p nishes q p nishes 1 q p OVERLAPS q p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 DateAdd("D", -1, p 1 ) DateAdd("D", -1, p 2 ) p2 Interval Constructors: duration(p) extract time zone(p) = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL p 2 -p 1 or DateDiff("D", p 1 , p 2 ) (integral number of days) not supported Period Constructors: p+i i+p p-i p extend q p q p-q p q p AT TIME ZONE i p AT LOCAL [DateAdd("D", j, p 1 ), DateAdd("D", j , p 2 )) [DateAdd("D", j, p 1 ), DateAdd("D", j , p 2 )) [DateAdd("D", -j, p 1 ), DateAdd("D", -j, p 2 )) not possible not possible not possible not possible not supported not supported Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) [a, DateAdd("D", 1, a)) CONCAT("[" & Cstr(p 1) & "-" & Cstr(p 2 ) & ")") \ [ 4.4 IMPLEMENTATION CONSIDERATIONS 103 Table 4.7 Period operations in Microsoft SQL Server. Period Operations Microsoft SQL Server Equivalent Types: period [DATETIME, DATETIME) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q 2 p nishes q p nishes 1 q p OVERLAPS q p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 dateadd(second, -1, p 1 ) dateadd(second, -1, p 2 ) p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i p extend q p extend a a extend p = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL [dateadd(second, i, p 1 ), dateadd(second, i, p 2 )) [dateadd(second, i, p 1 ), dateadd(second, i, p 2 )) [dateadd(second, -i, p 1 ), dateadd(second, -i, p 2 )) [ CASE WHEN p1 < q 1 THEN p 1 ELSE q 1 END, CASE WHEN p 2 < q 2 THEN q 2 ELSE p 2 END ) [ CASE WHEN p1 < a THEN p 1 ELSE a END, CASE WHEN p 2 <= a THEN dateadd(day, 1, a) ELSE p 2 END ) [ CASE WHEN p1 < a THEN p 1 ELSE a END, CASE WHEN p 2 <= a THEN dateadd(day, 1, a) ELSE p 2 END ) 104 CHAPTER FOUR : PERIODS Table 4.7 (continued) Period Operations Period Constructors, continued: a extend b p \q p-q p [q p AT TIME ZONE i p AT LOCAL Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) Microsoft SQL Server Equivalent [ CASE WHEN a < b THEN a ELSE b END, CASE WHEN a < b THEN dateadd(day, 1, b) ELSE dateadd(day, 1, a) END ) [ CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL ELSE CASE WHEN p 1 < q 1 THEN q 1 ELSE p 1 END END, CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL ELSE CASE WHEN p 2 < q 2 THEN p 2 ELSE q 2 END END ) [ CASE WHEN q 1 <= p 1 AND p 2 <= q 2 THEN NULL ELSE CASE WHEN p 1 < q 1 AND q 2 < p 2 THEN NULL ELSE CASE WHEN p 2 > q 2 AND p 1 < q 2 THEN q 2 ELSE p 1 END END END, CASE WHEN q 1 <= p 1 AND p 2 <= q 2 THEN NULL ELSE CASE WHEN p 1 < q 1 AND q 2 < p 2 THEN NULL ELSE CASE WHEN q 1 < p 2 AND p 2 > q 1 THEN q 1 ELSE p 2 END END END ) [ CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL ELSE CASE WHEN p 1 < q 1 THEN p 1 ELSE q 1 END END, CASE WHEN p 2 <= q 1 OR q 2 <= p 1 THEN NULL ELSE CASE WHEN p 2 < q 2 THEN q 2 ELSE p 2 END END ) not supported not supported [a, dateadd(second,1,a)) "[" + convert(char(11), p 1 ) + "-" + convert(char(11), p 2 ) + ")" 4.4 IMPLEMENTATION CONSIDERATIONS Table 4.8 Period operations in Sybase SQLServer. Period Operations Sybase SQLServer Equivalent Types: period [DATETIME, DATETIME) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q2 p nishes q p nishes 1 q pq p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 dateadd(second, -1, p 1 ) dateadd(second, -1, p 2 ) p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i p p p p p p extend q q -q q AT TIME ZONE i AT LOCAL \ [ Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL [dateadd(second, i, p 1 ), dateadd(second, i, p 2 )) [dateadd(second, i, p 1 ), dateadd(second, i, p 2 )) [dateadd(second, -i, p 1 ), dateadd(second, -i, p 2 )) not possible not possible not possible not possible not supported not supported [a, dateadd(second, 1, a)) "[" + convert(char(11), p 1 ) + "-" + convert(char(11), p 2 ) + ")" 105 106 CHAPTER FOUR : PERIODS Table 4.9 Period operations in Oracle8 Server. Period Operations Oracle8 Server Equivalent Types: period [DATE, DATE) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q 2 p nishes q p nishes 1 q pq p NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 p1 - 1 p2 - 1 p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i a extend b p extend q p extend a a extend p p q p-q p q p AT TIME ZONE i p AT LOCAL [p 1 + j, p 2 + j) [p 1 + j, p 2 + j) [p 1 - j, p 2 - j) [LEAST(a, b), GREATEST(a + 1, b + 1)) [LEAST(p 1 , q 1 ), GREATEST(p 2, q 2 )) [LEAST(p 1 , a), GREATEST(p 2, a + 1)) [LEAST(a, p 1 ), GREATEST(a + 1, p 2 )) [GREATEST(p 1, q 1 ), LEAST(p 2 , q 2 )) not possible [LEAST(p 1 , q 1 ), GREATEST(p 2, q 2 )) not supported not supported Other Operators: CAST(a AS PERIOD) [a, a + 1/86400) \ [ = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL 4.4 IMPLEMENTATION CONSIDERATIONS Table 4.10 Period operations in UniSQL. Period Operations UniSQL Equivalent Types: period [TIMESTAMP, TIMESTAMP) Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q2 p nishes q p nishes 1 q pq p IS NULL p1 p2 q2 p2 q2 p1 q1 q1 p1 p1 p1 q1 p1 p1 p1 Datetime Constructors: beginning(p) previous(p) last (p) ending(p) p1 p1 - 1 p2 - 1 p2 Interval Constructors: duration(p) extract time zone(p) p2 - p1 not supported Period Constructors: p+i i+p p-i p extend q p q p-q p q p AT TIME ZONE i p AT LOCAL [p 1 + i, p 2 + i) [p 1 + i, p 2 + i) [p 1 - i, p 2 - i) not possible not possible not possible not possible not supported not supported Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) [a, a + 1) not possible \ [ = q 1 AND p2 = q 2 < q1 < p1 = q1 = p1 < q 1 AND q 1 < p 2 < p 1 AND p 1 < q 2 < p 1 AND p 2 < q 2 < q 1 AND q 2 < p 2 = q 1 AND p 2 < q 2 = q 1 AND q 2 < p 2 < p 1 AND p 2 = q 2 < q 1 AND p 2 = q 2 < q 2 AND q 1 < p 2 IS NULL 107 108 CHAPTER FOUR : PERIODS of the period p , a and b denote UniSQL TIMESTAMP values, and i denotes a UniSQL INTEGER representing seconds. 4.4.8 CD-ROM Materials The CD-ROM contains example queries in IBM DB2 UDB, Informix–Universal Server, Microsoft Access 2000, Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL illustrating how periods may be simulated using a pair of dates. For some of the operations that are not possible in IBM DB2 UDB strictly in SQL, the equivalents are given as embedded SQL. A detailed explanation of Ingres is also included, but the examples have not been tested. 4.5 SUMMARY A period is an anchored duration of the time line. It extends from a beginning instant to a last instant. Although a variety of representations are possible, including closed-closed, closed-open, open-closed, open-open, a pair of starting instant and duration, and a pair of last instant and duration, the most convenient representation is a closedopen pair of instants. Predicates are complex for periods, as they are not totally ordered. There are 13 possible relationships between two periods. The delimiting timestamps can be extracted from a period. Two periods can be unioned and intersected, and a period can be subtracted from another period. A period can be shifted by adding or subtracting an interval. SQL/Temporal, part of SQL3, provides built-in support for periods, including the period type constructor, period literals, predicates, and value constructors. Additional constructs break a period into its constituent granules and normalize a set of periods into a set of disjoint, nonadjacent periods. 4.6 READINGS James Allen showed that there are exactly 13 disjoint binary relationships possible between two periods [2]; these are now termed the Allen relations. CHAPTER 5 O V E R V I E W A valid-time state table records the history of the several kinds of temporal primary keys. The enterprise. Such a table is easily specied by ap- most natural variant is the sequenced primary pending two timestamp columns, one specify- key, which states that the value of the indicated ing when the row became valid and one spec- columns is unique at every instant of time. ifying when the row stopped being valid. The There are analogous kinds of referential in- intervening time is termed the period of validity tegrity constraints, with the most natural being of the row. again the sequenced variant. Unfortunately, The primary key must be changed when this kind is the most challenging to express in these timestamp columns are added. There are SQL. Dening State Tables I n 1992 the University of Arizona was confronted with a knotty dilemma. Its data was managed by a suite of COBOL legacy systems, each with its own underlying DBMS or le structure. Personnel records were (and continue to be) managed by PSOS (Personnel Operating System), using the Transact DBMS. Financial records, including purchasing, reorders, property management, xed assets, and the ledger, are managed by FRS (Financial Records System), which uses IDMS. Student records are contained in yet another system, SIS (Student Information System), which uses VSAM. To obtain information from a specic system, someone in the Center for Computing and Information Technology (CCIT) who was familiar with that system would be tasked to write a report program, which often took several weeks. Getting an integrated report across two or more of these databases was exceedingly difcult. About the only positive thing that could be said about this situation was that it guaranteed job security for CCIT personnel. Cheryl Bach, an impassioned and imaginative seven-year CCIT veteran, had a better idea. She proposed that a data warehouse be created in a relational DBMS, gathering sanitized information from all of these systems into a single, consistent database. Perhaps predictably, this suggestion was not embraced by the the CCIT rank and le. So Larry Rapagnani, then CCIT director, let Cheryl start a somewhat clandestine project to develop this system, to be called the University Information System (UIS), using a VAX-2000 and Rdb, which the university had been given by Digital Equipment Corporation. The hope was that this minimally funded project would produce an initial system that demonstrated the many benets of a unied database, thereby reducing the resistance encountered initially. Cheryl, working with Htay Lay and later with Chris Janton, eventually dened some 300 tables. Some tables were copied over daily from the legacy systems; others were added each pay period, each month, or even each 12 months (for those tables summarizing the scal year). The loading phase requires most of each night; access is permitted from 8 A . M . to 8 P. M . 112 CHAPTER FIVE : DEFINING STATE TABLES UIS employs a client-server architecture. Users could connect over the network to the server and run queries directly using interactive SQL, access it via COBOL programs running on their client machine, or use the graphical query facilities of their local machine. The system was initially released in December 1992. University staff were encouraged to use the system, and training was provided in the graphical user interface so that users could write their own queries. Access was also given to CCIT personnel, so that they could try it out on their own. While the response from users of direct access to this information was enthusiastic, not a single person within CCIT tried the system for the rst two and a half years. Decentralization can be quite threatening. 5.1 INITIAL SCHEMA Merging the data from each system into UIS required many technical decisions, especially as the data generally wasn't stored in tabular format in the legacy systems. We start with four tables, the EMPLOYEES table, the INCUMBENTS table, the POSITIONS table, and the JOB TITLES table. The EMPLOYEES table contains 88 columns, of which 4 are germane to this discussion: SSN, LAST NAME, FIRST NAME, and ANNUAL SALARY. The INCUMBENTS table contains 12 columns, including SSN and PCN (position control number). The POSITIONS table contains 16 columns, including PCN and JOB TITLE CODE1. The JOB TITLES table contains 11 columns. This last table is quite sizable; there are over 7000 job titles dened. The University is certainly prepared for future growth: 10 digits are allocated to the job title code! We focus on the following columns: EMPLOYEES(SSN, LAST_NAME, FIRST_NAME, ANNUAL_SALARY) INCUMBENTS(SSN, PCN) POSITIONS(PCN, JOB_TITLE_CODE1) JOB_TITLES(JOB_TITLE_CODE, JOB_TITLE) Each row of the rst table provides information on one employee, each row of the second table provides information on a job assignment for a current employee, each row of the third table describes a particular position (which can be associated with multiple job titles), and each row of the last table describes a particular job title code. The primary key of EMPLOYEES is SSN, the primary key of INCUMBENTS is (SSN, PCN), and the primary key of POSITIONS is PCN. INCUMBENTS.SSN is a foreign key to EMPLOYEES.SSN, INCUMBENTS.PCN is a foreign key to POSITIONS.PCN, and POSITIONS.JOB TITLE CODE1 is a foreign key to JOB TITLES.JOB TITLE CODE. Given these tables, nding the employee's salary is easy when a relational query language such as SQL is used: 5.2 Code Fragment 5.1 ADDING HISTORY 113 What is Bob's salary? SELECT ANNUAL_SALARY FROM EMPLOYEES WHERE FIRST_NAME = Bob To determine the employee's position, all three tables need to be consulted: Code Fragment 5.2 What is Bob's position? SELECT JOB_TITLE_CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN Cheryl also wished to record the date of birth. To do so, she added a column to the EMPLOYEES table, yielding the following schema: EMPLOYEES(SSN, LAST_NAME, FIRST_NAME, ANNUAL_SALARY, BIRTH_DATE) Finding the employee's date of birth is analogous to determining the salary: Code Fragment 5.3 What is Bob's date of birth? SELECT BIRTH_DATE FROM EMPLOYEES WHERE FIRST_NAME = Bob This illustrates the (limited) temporal support available in SQL (more precisely, in the SQL-92 standard, as well as in all major commercial DBMSs), that of the column type DATE. As we saw in Chapter 3, other SQL is adequate to handle temporal types are available for columns. This chapter will inqueries on isolated temporal vestigate how such temporal columns can be used to indicate columns. the period of validity of the other columns. 5.2 ADDING HISTORY To the INCUMBENTS table, Cheryl appended two columns. The rst column indicates when the information in the row became valid, that is, when the employee was assigned to that position. The second column indicates when the information was no longer valid, that is, when the employee was assigned to another position or left the university. (Cheryl would have preferred using a period data type, but as we saw before, such a type is not available in SQL-92, nor in Rdb. So a period is simulated with two DATEs.) 114 CHAPTER FIVE : DEFINING STATE TABLES Code Fragment 5.4 Add a period timestamp to INCUMBENTS. ALTER TABLE INCUMBENTS ADD START_DATE DATE ALTER TABLE INCUMBENTS ADD END_DATE DATE To the data model, these new columns are identical to the BIRTH DATE column, in that they are of data type DATE. However, their meaning is quite different. The BIRTH DATE column is independent of the rest of the table, except for the primary key. However, the timestamp columns (START DATE and END DATE) interact closely with the other columns, in that they specify the period of validity of the values of these columns. In the INCUMBENTS table, the timestamp columns specify the period of validity of the PCN column. This difference between the semantics of the BIRTH DATE column and the other timestamp columns has far-ranging consequences and is the primary impetus for this entire book. You might argue that the BIRTH DATE column is the start of validity of the employee, with a (not included) column DEATH DATE providing the end of validity of the employee. However, the period of validity is with respect to the fact modeled by the entire row and applies to the information of that row. The EMPLOYEES table records the employee's social security number (SSN), rst name, last name, and annual salary. Taking the SSN to be time-invariant, which is a common assumption, a row of this table associates a rst name, a last name, an annual salary, and a birth date with that SSN. The period of validity would then record when that combination of four values was valid for that SSN. If any of the four values changed—for example, a salary raise or changing the last name of the employee (say, if he or she got married)—the period of validity would be terminated and another row would state the new value. For this reason, the BIRTH DATE is simply another column and should not be considered to start the period of validity of the row. Such a table is called a valid-time table. This table records the history of the modeled reality. The original table, without temporal support, is termed a snapshot table, as it logically captures the state of the enterprise at a single point in time, much as a photographic snapshot does. Snapshot tables are generally kept up-to-date, and so capture reality “as of now.” (Jim Melton's compelling metaphor is the “last” frame of a movie still being shot.) In contrast with valid time, a column that just happens to be of a datetime data type, but that does not indicate when other columns were valid, is termed a user-dened time column. BIRTH DATE is a user-dened time column in INCUMBENTS. Table 5.1 is an excerpt of the INCUMBENTS table. The rst row species that employee 111-22-3333 (Bob) had a position 90025 (Senior Vice President, Research) starting at the beginning of 1996, and extending to June 1 of that year, when he transferred to position 120033. He stayed in that position for a total of four months, until October 1, when he transferred to position 137112, where he continues to this day (as we will see, the special date 3000-01-01 denotes “currently valid”). An- 5.2 ADDING HISTORY 115 Table 5.1 An excerpt from the INCUMBENTS valid-time state table. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 444332222 900225 120033 120033 137112 120033 1996-01-01 1996-06-01 1996-08-01 1996-10-01 1997-01-01 1996-06-01 1996-08-01 1996-10-01 3000-06-01 3000-01-01 other employee, 444-33-2222, has remained in the same position since being hired the beginning of the following year. This table has several interesting features. First, although Bob appears in four rows, he had only one position at any point in time (note that closed-open periods are used in this table). The candidate keys for this particular table are (SSN, PCN, START DATE), (SSN, PCN, END DATE), and (SSN, PCN, START DATE, END DATE). As we will see shortly, none of these capture the desired constraint. Second, neither employee has gaps in their position history (a gap represents times when there was no PCN associated with their SSN); disallowing gaps may be appropriate or unacceptable, depending on the semantics of the application. The third observation is that this table can be viewed as a compact representation of a sequence of snapshot tables, each valid on a particular day. The snapshot table valid on January 1, 1996, contains one row, (111223333, 900225). The snapshot Water Clocks table valid on September 13, 1996, also contains one row, (111223333, 120033). A sundial is useless at night and on overcast days. The table valid on February 22, 1997, conThe Mesopotamians invented the clepsydra, or watains two rows: (111223333, 137112) and ter clock, for just such situations. This clock is based (444332222, 120033). This long sequence on the principle that it takes an approximately xed of snapshot tables is very efciently enamount of time for a given amount of water to coded in these ve rows, by associating a drain through a small hole, drop by drop. (This period with each row. same principle—with a different material, sand— Also note that the second and third rows is the basis for the hourglass.) Because the length have identical SSN and PCN values, yet of a day, and thus an hour (see the Hours sidebar do not represent a duplicate in any of the in Chapter 2), can vary when measured by a sunsnapshot tables, as the periods associated dial, but is of constant length when measured with with these two rows do not overlap. Ina clepsydra, the standard hour was dened based deed, it might be possible to replace these on an equinoctial day, in which the daylight and rows with a single row, associated with the nocturnal portions were equal, and thus the hours period [1996-06-01 – 1996-10-01). were also of equal length. 116 CHAPTER FIVE : DEFINING STATE TABLES EMPLOYEES.ANNUAL SALARY records only the most recent salary the employee received. The table as it is in the personnel system is quite a bit more complicated. It also includes STATUS BEGIN DATE and STATUS END DATE, which together indicate when another included column, EMPLM STATUS, was valid, though only the most recent status is retained in the table. EMPLOYEES also includes the PRIOR SSN, as well as 17 dates, indicating when important events occurred, such as PAY CHANGE DATE. As discussed above, none of these date elds constitute the commencement or end of the period of validity. In fact, the EMPLOYEES table doesn't even have a period of validity; it is a snapshot table. When examining a particular table, you must determine which DATE columns apply to the row as a whole, via the period of validity for that row, and which DATE columns merely provide information, such as the employee's date of birth or their most recent promotion date. The PSOS legacy system, however, does record the employment history. The salary history information is included in UIS in the ZPSOS COMPENSATION HISTORY table. The compensation history table is quite difcult to decipher. Its key is (CHRONOLOGY KEY, SSN), the former a 16-character string specifying the date and time the record was inserted. There are also HISTORY START DATE and HISTORY END DATE columns, indicating when the information in the record applied (the period of validity). To get at the information desired, we dene a view that eliminates most of the columns. The WHERE clause extracts the most recently stored row for each period of validity. We are interested only in full-time employees (full-time equivalent = 1), for which the hourly rate is actually the annual salary. Code Fragment 5.5 Extract the relevant information. CREATE VIEW SAL_HISTORY AS SELECT SSN, SALARY_HOUR_RATE AS AMOUNT, HISTORY_START_DATE, HISTORY_END_DATE FROM ZPOS_COMPENSATION_HISTORY AS Z WHERE CHRONOLOGY_KEY = MAX(SELECT CHRONOLOGY_KEY FROM ZPOS_COMPENSATION AS Z2 WHERE Z2.SSN = Z.SSN AND Z2.HISTORY_START_DATE < Z.HISTORY_END_DATE AND Z.HISTORY_START_DATE < Z2.HISTORY_END_DATE) AND EMPLOYEE_FTE = 1.00 A valid-time table records the history of the modeled reality. The history can be retained by adding timestamp column(s). The value of the column(s) specifying the period of validity of a row is called the timestamp of the row; the columns themselves are called the timestamp columns, or the timestamps of the table. This term, in lowercase letters, should be distinguished from SQL-92's TIMESTAMP data type. 5.3 5.3 TEMPORAL KEYS 117 TEMPORAL KEYS The rst consequence of adding valid-time support to a table is that the primary key of such tables needs to take the timestamp into consideration. The value of the primary key of a table must be unique; that is, each value must be contained in at most one row of the table. For the original INCUMBENTS table, the value of the (SSN, PCN) pair of columns is unique, at any point in time. Hence, the following table constraint works ne. Code Fragment 5.6 The primary key of INCUMBENTS is (SSN, PCN). ALTER TABLE INCUMBENTS ADD PRIMARY KEY (SSN, PCN) Informally, this says that no employee (identied by an SSN value) can have the same position more than once simultaneously. When history is added, there may well be several rows with the same SSN and PCN. To handle this, one or both of the new The original primary key is not, temporal columns can be appended to the key. Cheryl speciby itself, a primary key of the ed the primary key of INCUMBENTS as (SSN, PCN, END DATE); the temporal table. primary key of SAL HISTORY is (SSN, HISTORY START DATE). Cheryl could have just as easily used the start date, rather than the end date. She could also have used both the start and end dates in the primary key. Unfortunately, none of these three alternatives is sufciently restrictive. The problem arises if there are overlapping periods associated with the same SSN. Consider the following table, which is consistent with all three of the possible primary keys just discussed. This table uses a closed-open representation of periods, and so, for example, the period of validity of the rst row includes the last day in May, but not the rst day in June. SSN PCN START DATE END DATE 111223333 111223333 900225 900225 1996-01-01 1996-04-01 1996-06-01 1996-10-01 We wish to specify that there can be only one (SSN, PCN) pair, at any given time. Put another way, no one can have a particular position twice at the same time. The above table violates this constraint: in May of 1996, Bob has position code 900225 twice. The primary key constraint should have disallowed this because two rows have the same SSN and PCN for any specic day during the months of April and May. Unfortunately, none of the following attempts prevent the above (INCUMBENTS) table. 118 CHAPTER FIVE : DEFINING STATE TABLES Code Fragment 5.7 Attempting to specify a primary key at any point in time. ALTER TABLE INCUMBENTS ALTER TABLE INCUMBENTS ALTER TABLE INCUMBENTS ALTER TABLE INCUMBENTS END_DATE) ADD ADD ADD ADD PRIMARY PRIMARY PRIMARY PRIMARY KEY KEY KEY KEY (SSN, (SSN, (SSN, (SSN, PCN) PCN, START_DATE) PCN, END_DATE) PCN, START_DATE, Including the start date, the end date, or both in the primary key does not prevent Bob from having a position (in this case, Adding the timestamp does not position 900225) twice in May 1996 because the rows have difserve to convert a nontemporal ferent values for both of these columns. key to a temporal key. What is needed is a sequenced constraint, which is applied at each point in time. The constraint desired is that no two rows A sequenced constraint is one have the same value for the SSN and the PCN. Because we want that is applied independently at this constraint to be satised at every point in time, it becomes each point in time. a sequenced constraint. All constraints specied on a snapshot table have sequenced counterparts, specied on the analogous valid-time state table. A sequenced primary key constraint can be specied in SQL as follows: Code Fragment 5.8 (SSN, PCN) is a sequenced primary key for INCUMBENTS. CREATE ASSERTION seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE)) AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL OR I.PCN IS NULL) ) The last two predicates in the WHERE clause constitute the overlap predicate on two periods dened by their delimiting dates. We use a COUNT aggregate to ensure that I1 and I2 aren't the exact same row. The intuition of this sequenced constraint is “no employee can have the same position more than once simultaneously.” In the nested SELECT, we could have used the SQL-92 OVERLAPS predicate, instead of the last two lines: A sequenced primary key can be expressed as an SQL assertion or table constraint. 5.4 HANDLING NOW 119 AND (I1.START_DATE, I1.END_DATE) OVERLAPS (I2.START_DATE, I1.END_DATE) If a closed-closed representation for the period of validity is used (in which case the END DATE of the above table would be the last day that PCN was valid, or 199605-30), the predicate must be altered slightly: Code Fragment 5.9 (SSN, PCN) is a sequenced primary key for INCUMBENTS, assuming a closed-closed timestamp representation. CREATE ASSERTION seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE <= I2.END_DATE AND I2.START_DATE <= I1.END_DATE)) AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL OR I.PCN IS NULL) ) All the tables shown in this book use a closed-open representation for the period of validity, unless otherwise indicated. The code fragments will also make this assumption. If some other representation for the period of validity is used, the SQL predicates must be examined and possibly changed. 5.4 HANDLING NOW It's the fabulous castle of Now. You can walk in and wander about, But it's so very thin, Once you are, then you've been— And soon as you're in, you're out. —Shel Silverstein, “The Castle” What should the timestamp be for current data? In the PSOS legacy system, current data is indicated with an end date of 00-00-00, which is the code for “not applicable.” The extraction utility replaces this with January 1, 1860. (In Rdb, the minimum value for a VMS DATE type is 1858The special value “now” can be stored as a specic instant value 11-17. However, the designers wanted this value to be a little more recognizable, so they chose the rst day of the following that will not occur otherwise. decade. They are thinking about using 1859-12-31 to represent a date that could not be correctly interpreted, such as a YYMMDD format date with 120 CHAPTER FIVE : DEFINING STATE TABLES a value of 990001.) Hence, Bob's current salary in INCUMBENTS has a START DATE of July 1, 1996, and an END DATE of January 1, 1860. One advantage is that when records are ordered by end date, current row(s) show up rst. Using this date for current data requires that the applications and queries that use UIS have to treat such values specially. Specically, to identify the current records, the following predicate can be used: WHERE INCUMBENTS.END_DATE = DATE 1860-01-01 Anyone using the database would have to be told early on about this special, and prevalent, time value. And clearly, taking this at face value is a blatantly false model of the enterprise. There are several somewhat more appealing alternatives. Rather than resorting to a particular date, NULL can be used. This yields a slightly more readable predicate. WHERE INCUMBENTS.END_DATE IS NULL The disadvantages are (1) users sometimes get confused when they encounter a date of NULL, (2) SQL states that any compar“Now” can also be represented ison with a null value returns false, with the implication that with a null value, but this rows with null values will simply be absent from the result of complicates queries. most queries that contain predicates on the timestamps, which would confuse users, and (3) other uses of NULL are no longer available. We cannot state, for example, that the end date is unknown, which is quite different from stating that the end date is “now.” Another approach, one that is used extensively, is to set the end date to the largest value in the timestamp domain (termed the end of time). The legacy nancial system, FRS, uses 99-99-99 for this purpose. The extraction process for UIS converts this to 3000-01-01. Why not 9999-12-31? The Sybase DBMS was being considered for UIS, and it doesn't support that date. Chris Janton wanted this date to be within the range of acceptable dates for all the prominent database systems available then and to be visually apparent. So he picked a millennium date that was far into the future, thereby creating the year 3000 problem. However, the designers will be long gone when this problem rears its head. Using a date (far) into the future allows CURRENT DATE to be used to identify current records: WHERE INCUMBENTS.START_DATE <= CURRENT_DATE AND CURRENT_DATE < INCUMBENTS.END_DATE “Now” can be represented with “forever,” or a close approximation. However, it still renders the data a rather inaccurate model of reality. The problem is that this model is also conspicuously fallacious. We can safely state that Bob will not have this position in the year 3000, though that is exactly what the current row records. With the lack of an entirely acceptable solution, we will use 3000-01-01 in all of our UIS examples to represent both “now” and “forever.” 5.5 5.5 UNIQUENESS REEXAMINED 121 UNIQUENESS REEXAMINED A primary key constraint states two things about the associated table. First, the value of each of the key columns in any row cannot be null. Second, there can be no two rows with the same values for the key columns. In fact, a primary key can be expressed in another way, as a pair of constraints, NOT NULL and UNIQUE. Let's examine the uniqueness constraint in the context of the INCUMBENTS table shown in Table 5.2, considering for now the Two rows are value-equivalent entire row. While in this case all columns are either key columns if the values of their or timestamp columns, the following denitions hold even in nontimestamp columns are the presence of other, data columns. identical. Value equivalence is a There are four kinds of duplicates involved, all but one of weak form of duplication. which are present in Table 5.2. All of the rows are considered value-equivalent , in that the values of all of the columns except for the timestamp columns are identical. Value equivalence is a weak form of duplication. The rst two rows illustrate a sequenced duplicate. Here, the values of nontimestamp columns, in this case SSN and PCN, are Two rows are sequenced value-equivalent and the periods of validity overlap, in this case duplicates if they are duplicates for the months of April and May of 1996. As with primary keys, at some instant. the adjective sequenced means that the operation or constraint is applied independently at every point in time. Here, Bob has two salaries for these two months, as well as for the month of December 1997. A variant of sequenced duplicate is a current duplicate, in which there are duplicate rows in the current state. It is currently March 20, 1997; there are no current duplicates because only one row, the last, is currently valid. Interestingly, whether a table contains current duplicate rows Two rows are current duplicates if they are sequenced duplicates can change over time, even if no modications are made to the table. In December 1997, a current duplicate will suddenly at the current instant. appear in Table 5.2. Table 5.2 A table containing several kinds of duplicates. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 111223333 120033 120033 120033 120033 120033 1996-01-01 1996-04-01 1996-04-01 1996-10-01 1997-12-01 1996-06-01 1996-10-01 1996-10-01 1998-01-01 1998-01-01 122 CHAPTER FIVE : DEFINING STATE TABLES Table 5.3 Implications among duplicate variants. Sequenced Sequenced Current Value-equivalent Nonsequenced p p p Current p Value-equivalent p p p p Nonsequenced p Finally, the second and third rows are nonsequenced duplicates, in which the values of all of the columns, including the timestamp columns, are identical. This adjective emphasizes that the property (in this case, duplicates) is not applied independently at each point in time, but rather is applied to the table as a whole, ignoring its temporal nature. Table 5.3 indicates how these variants interact. Each entry species whether two rows satisfying the variant on the left will also satisfy the variant listed across the top. A check mark states that the top variant will be satised; an empty entry states that it may not. For example, if two rows are nonsequenced duplicates, they will also be sequenced duplicates, for the entire period of validity. However, two rows that are sequenced duplicates are not necessarily nonsequenced duplicates, as illustrated by the rst two rows of the above INCUMBENTS table. The least restrictive form of duplication is value equivalence, as it simply ignores the timestamps. Note that in Table 5.3 this form implies no other. The most restrictive is nonsequenced duplication, as it requires all the column values to match exactly. It implies all but current duplication. SQL's UNIQUE constraint prevents value-equivalent rows. Two rows are nonsequenced duplicates if the values of all columns are identical. Code Fragment 5.10 Prevent value-equivalent rows in INCUMBENTS. CREATE TABLE INCUMBENTS ( ... UNIQUE (SSN, PCN) ) Intuitively, a value-equivalent constraint (or a value-equivalent primary key constraint) states that “once a position is assigned to an employee, it can never be repeated later,” because doing so would result in a value-equivalent row. We can also use a UNIQUE constraint to prevent nonsequenced duplicates, by simply including the timestamp columns. The SQL UNIQUE constraint prevents nonsequenced duplicates. 5.5 Code Fragment 5.11 UNIQUENESS REEXAMINED 123 Prevent nonsequenced duplicates in INCUMBENTS. CREATE TABLE INCUMBENTS ( ... UNIQUE (SSN, PCN, START_DATE, END_DATE) ) While nonsequenced duplicates are easy to prevent via SQL statements, such constraints are not that useful in practice. The intuitive meaning of the above nonsequenced unique constraint (or the closely related nonsequenced primary key constraint) is something like “an employee cannot have the same position twice over identical periods.” However, this constraint can be satised by simply starting one of the assignments a day earlier or later; the employee can still have two identical positions for overlapping periods. Current duplicates involve just a little more effort. Nonsequenced uniqueness constraints are easy to specify in SQL, but do not correspond to a naturally stated condition on the modeled reality. Code Fragment 5.12 Prevent current duplicates in INCUMBENTS. CREATE TABLE INCUMBENTS ( ... CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE <= CURRENT_DATE AND CURRENT_DATE < I1.END_DATE AND I2.START_DATE <= CURRENT_DATE AND CURRENT_DATE < I2.END_DATE))) ) Here the intuition is that no employee can have two identical positions. The present tense is used to indicate “at the current time.” As mentioned above, the problem with a current uniqueness constraint is that it can be satised today but violated tomorrow, even if there are no changes made to the underlying table. If we know that the application will never store future data, we can approximate a current uniqueness constraint by simply appending the END DATE. Current uniqueness constraints require an SQL constraint or assertion, and are rather fragile. Code Fragment 5.13 Prevent current duplicates in INCUMBENTS, assuming no future data. CREATE TABLE INCUMBENTS ( ... UNIQUE (SSN, PCN, END_DATE) ) 124 CHAPTER FIVE : DEFINING STATE TABLES The SQL UNIQUE constraint with the end date prevents current duplicates, if future data is never stored. Code Fragment 5.14 This works because all current data will have the same END DATE (the special value DATE 3000-01-01). As a primary key is just a combination of UNIQUE and NOT NULL, we can prevent sequenced duplicates by removing the NOT NULL portion from CF-5.8. Prevent sequenced duplicates in INCUMBENTS. CREATE TABLE INCUMBENTS ( ... CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE))) ) The intuition behind a sequenced unique (or sequenced primary key) constraint is that “at no time can an employee have two identical positions.” This constraint is a natural one. A sequenced constraint is the logical extension of a conventional constraint on a nontemporal table. Sequenced uniqueness If we know that the application will make only current modiconstraints are also specied cations, that is, will only modify the current state, then we can with an SQL constraint or express a sequenced constraint via a current constraint. There assertion. Such constraints are are three cases to consider to see that this holds: past, current, analogous to conventional and future. Future data cannot be stored, and so the sequenced uniqueness constraints on constraint will never be violated in the future. For current data, nontemporal tables. the current constraint will ensure the sequenced constraint. For past data, that data at one time was current data, and so satises the constraint. Hence, a current constraint will imply a sequenced constraint, if only current modications were made, and if the current constraint was present from the denition of the table. For sequenced uniqueness, we saw above (CF-5.13) that current uniqueness could be specied by appending the END DATE. This also works for sequenced duplicates, under the stated assumptions. Code Fragment 5.15 Prevent sequenced duplicates in INCUMBENTS, assuming only current modications. CREATE TABLE INCUMBENTS ( ... UNIQUE (SSN, PCN, END_DATE) ) 5.5 UNIQUENESS REEXAMINED 125 To review, let's consider briey the integrity constraint “Each employee has at most one position.” (Contrast this with the constraint discussed above: “Each employee can have a position at most once,” which allows an employee to have two positions at one time.) On a snapshot table, this is expressed with UNIQUE(SSN) The sequenced variety, “At any time, an employee has at most one position,” is violated by the following temporal table: SSN PCN START DATE END DATE 111223333 111223333 120033 900225 1996-01-01 1996-04-01 1996-06-01 1996-10-01 To avoid such situations, the following expresses the sequenced constraint. Code Fragment 5.16 INCUMBENTS.SSN is sequenced unique. CREATE ASSERTION seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE)) AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL) ) The nonsequenced variant is “an employee cannot have more than one position over two identical periods.” This is expressed as follows: Code Fragment 5.17 INCUMBENTS.SSN is nonsequenced unique. UNIQUE(SSN, START_DATE, END_DATE) Finally, the current variant is “an employee has [note present tense] at most one position,” expressed as follows: 126 CHAPTER FIVE : DEFINING STATE TABLES Code Fragment 5.18 INCUMBENTS.SSN is current unique. CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I1 WHERE AND START_DATE <= CURRENT_DATE AND CURRENT_DATE < END_DATE AND 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I2.START_DATE <= CURRENT_DATE AND CURRENT_DATE < I2.END_DATE))) 5.6 REFERENTIAL INTEGRITY A referential integrity constraint species that the value of the specied column in every row of the referencing table appears as the value of a specied column in a row of the referenced column. How such constraints are expressed depends heavily on whether the referencing and referenced tables are temporal tables. There are four cases, depending on whether the referencing table is temporal and whether the referenced table is temporal. Case 1 Neither table is temporal. If neither table is temporal, then SQL's constructs are perfectly adequate. Assuming for the moment that the INCUMBENTS table has no timestamp columns, the fact that INCUMBENTS.PCN is a foreign key for POSITIONS.PCN can be expressed as follows: Code Fragment 5.19 INCUMBENTS.PCN is a foreign key for POSITIONS.PCN (neither table is temporal). CREATE TABLE INCUMBENTS ( ... PCN CHAR(6) REFERENCES POSITIONS, ... ) Case 2 Only the referencing table is temporal. If the referencing table is temporal, but the referenced table is not, the same code works as well. Returning to INCUMBENTS being a valid-time state table, with columns START DATE and END DATE, the above REFERENCES fragment works ne. Here the assumption is that the nontemporal table contains time-invariant data, that is, data that doesn't vary over time. 5.6 Case 3 REFERENTIAL INTEGRITY 127 Both tables are temporal. If the referenced table is temporal, the situation is considerably more complex. In order to discuss this, we render POSITIONS temporal by adding START DATE and END DATE columns. It turns out that in UIS position code numbers are sometimes invalidated, and occasionally a PCN is reused. However, UIS only maintains the current state of the POSITIONS table, so when a PCN is reused, an old value will incorrectly be matched to a new job title code. The same holds for the job title code. In fact, there are (at the time this was written) 881 job titles that appear in POSITIONS.JOB TITLE CODE1 that are not associated with any rows in JOB TITLES. We wish to avoid this situation by dening appropriate referential integrity constraints. As with keys and duplicates, there are three kinds of referential integrity constraints on temporal tables: current, sequenced, and nonsequenced. Current referential integrity (“the PCN of all current incumbents must be listed in the current positions”) is straightforward, using the trick of converting a predicate of the form 8P into :9(:P). For a current foreign key, P is “a current incumbent that has a current position,” and :P is “a current incumbent whose position is not current.” Code Fragment 5.20 INCUMBENTS.PCN is a current foreign key for POSITIONS.PCN (both tables are temporal). CREATE ASSERTION INCUMBENTS_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.END_DATE = DATE 3000-01-01 AND NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.END_DATE = DATE 3000-01-01)) ) Here we just extract the current state on which to apply the constraint. Mirroring the current uniqueness constraint, current referential integrity can be satised today yet be violated tomorrow, even if no changes are made to either table. As with primary keys and duplicates, if future data is never present, current referential integrity still requires the above asCurrent referential integrity sertion because the referenced and referencing tables can change requires an SQL constraint or independently. For the nonsequenced referential integrity conassertion. straint (“for each value of INCUMBENTS.PCN, there existed at some, possibly different, time that value in POSITIONS.PCN”), CF-5.19 works perfectly well. The fact that POSITIONS is temporal means that past positions have become 128 CHAPTER FIVE : DEFINING STATE TABLES invalid. Nonsequenced referential integrity ignores this time-varying behavior and is content to match current incumbents with out-of-date positions. The temporal analog of a nontemporal referential integrity constraint is the sequenced constraint: “At each point in time, Nonsequenced referential each incumbent's PCN is valid at that time.” This statement integrity is easy to express, but applies the intuition of referential integrity to time-varying inis unnatural. formation. As with primary keys and duplicates, stating a sequenced referential integrity constraint in English is natural, but stating it in SQL is challenging. Asserting a sequenced foreign key The key is a sequenced foreign key if, for all rows r in the referencing table,    there is a row with that key value valid in the referenced table when r started, there is a row with that key value valid in the referenced table when r stopped, and there are no gaps when there are no rows in the referenced table, during r 's period of validity, that have that key value. Code Fragment 5.21 INCUMBENTS.PCN is a sequenced foreign key for POSITIONS.PCN (both tables are temporal). CREATE ASSERTION INCUMBENTS_Sequenced_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I -- there was a row valid in POSITIONS when I started WHERE NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.START_DATE <= I.START_DATE AND I.START_DATE < P.END_DATE) -- there was a row valid in POSITIONS when I ended OR NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.START_DATE < I.END_DATE AND I.END_DATE <= P.END_DATE) -- there are no gaps in POSITIONS during Is period of validity OR EXISTS ( 5.6 ) REFERENTIAL INTEGRITY 129 SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND I.START_DATE < P.END_DATE AND P.END_DATE < I.END_DATE AND NOT EXISTS ( SELECT * FROM POSITIONS AS P2 WHERE P2.PCN = P.PCN AND P2.START_DATE <= P.END_DATE AND P.END_DATE < P2.END_DATE))) This assertion may be read as follows. The outermost NOT EXISTS states that no row I of INCUMBENTS fails the referential inSequenced referential integrity tegrity test. The three predicates in the WHERE clause provide is the natural extension to ways for row I to fail the test. First, the test fails if there is no time-varying tables, but row in POSITIONS valid at the start of row I's period of validity. requires a complex SQL Second, the test fails if there is no row in POSITIONS valid at the assertion. end of row I's period of validity. Third, the test fails if there is a gap during row I's period of validity, a time when no row of POSITIONS was valid. A gap exists if there is a row P that ends during row I's period of validity that is not “extended” (towards I.END DATE) by another row. If we are assured that the histories in the referenced table are contiguous, that is, that there are no gaps in these histories, then sequenced referential integrity is easier to express as two assertions. Code Fragment 5.22 POSITIONS.PCN denes a contiguous history. CREATE ASSERTION POSITIONS_Contiguous_History CHECK (NOT EXISTS ( SELECT * FROM POSITIONS AS P, POSITIONS AS P2 WHERE P.END_DATE < P2.START_DATE AND P.PCN = P2.PCN AND NOT EXISTS ( SELECT * FROM POSITIONS AS P3 WHERE P3.PCN = P.PCN AND (((P3.START_DATE <= P.END_DATE) AND (P.END_DATE < P3.END_DATE)) OR ((P3.START_DATE < P2.START_DATE) AND (P2.START_DATE <= P3.END_DATE))))) ) 130 CHAPTER FIVE : DEFINING STATE TABLES Requiring a contiguous history is a nonsequenced constraint. Unlike a sequenced constraint, which must be true indepenExploiting contiguous histories in the referenced table simplies dently at each point in time, a nonsequenced constraint requires examining the table at multiple points of time. The absence of sequenced referential integrity a PCN on a particular day constitutes a gap in the history only when both tables are temporal. if there is a PCN for this SSN present both before and after this date. Given that there are no gaps, we can check for containment of the referencing period of validity by the contiguous history in the referenced table by simply checking the delimiting instants of the referencing period of validity. Code Fragment 5.23 INCUMBENTS.PCN is a sequenced foreign key for POSITIONS.PCN (both tables are temporal, version 2). CREATE ASSERTION INCUMBENTS_Sequenced_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.START_DATE <= I.START_DATE AND I.START_DATE < P.END_DATE) OR NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.START_DATE < I.END_DATE AND I.END_DATE <= P.END_DATE))) Case 4 Only the referenced table is temporal. The nal case to consider is when the referencing table (here, INCUMBENTS) is a nontemporal table and the referenced table (here, POSITIONS) is a temporal table. The current constraint is easy to express. Code Fragment 5.24 INCUMBENTS.PCN is a current foreign key for POSITIONS.PCN (only POSITIONS is temporal). CREATE ASSERTION INCUMBENTS_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE NOT EXISTS ( 5.7 CONSTRAINT ATTRIBUTES* 131 More Water Clocks Water clocks have their disadvantages. They are susceptible to frost, and hence are not practical in Europe or other northern climes. Indeed, it has been argued that the mechanical clock had to be invented in Europe, a place where the prior technology of sundials and water clocks was inadequate on cloudy, cold days. Arguably among the most intricate of water clocks was Su Song's astronomical clock, completed in 1094 C . E . This clock, which weighed several tons and lled a 40-foot tower, reproduced the ) movements of the sun, the moon, and selected stars, as well as indicating hours and k'o, each of which equals 14 minutes and 24 seconds of our time. Mongols invaded some 30 years later and carried away some of the clock, and within 50 years, this magnicent clock was forgotten, to await rediscovery by Joseph Needham in 1954. Although it would be appealing for Song's clock to be a forerunner of the European mechanical clock, no such connection has yet been uncovered. SELECT * FROM POSITIONS AS P WHERE I.PCN = P.PCN AND P.END_DATE = DATE 3000-01-01)) The nonsequenced constraint is, again, expressed using CF-5.19. For the sequenced constraint, we need to be more precise on what “at each point in time” means for a nontemporal table. The case where the referencing There are at least two reasonable interpretations. One is that table is nontemporal but the the nontemporal table records current data, in which case a sereferenced table is temporal quenced constraint is equivalent to a current constraint. A difreduces to the other cases just ferent interpretation is that the nontemporal table contains described. time-invariant data. In that case, CF-5.19 works ne. For the INCUMBENTS table, the most appropriate interpretation is that this table records current data, in which case CF-5.20 sufces. 5.7 CONSTRAINT ATTRIBUTES* SQL-92 and some DBMSs provide attributes on constraints and assertions. A given constraint can be specied as DEFERRABLE or NOT DEFERRABLE. It is critical that the constraints (and assertions) exemplied in this chapter be DEFERRABLE. Otherwise, the constraint is checked at the end of every SQL statement, which is undesirable 132 CHAPTER FIVE : DEFINING STATE TABLES because most modications on temporal tables require several SQL statements to implement. As we shall see in Chapter 7, a Temporal constraints and single logical deletion requires one or two UPDATE statements, assertions should be a DELETE statement, and possibly an INSERT statement. While DEFERRABLE INITIALLY the database may be consistent at the end of this series of stateDEFERRED, with each ments, it most likely will not be at the end of the intermediate transaction containing a SQL statements. modication resetting this via a Similarly, the constraint must be set to INITIALLY DEFERRED SET CONSTRAINTS ALL for the same reason (INITIALLY IMMEDIATE requests perDEFERRED. statement checking). Neither of these is the default. One must request DEFERRABLE INITIALLY DEFERRED for each constraint on a temporal table. 5.8 IMPLEMENTATION CONSIDERATIONS The code fragments in this chapter were implemented on a variety of DBMSs. 5.8.1 IBM DB2 Universal Database IBM DB2 supports a UNIQUE constraint (see CF-5.10 and CF-5.11) only in version 5 (Universal Database); in prior versions, such constraints must be expressed as triggers, or as PRIMARY KEY constraints if it is also desired that the indicated columns are not nullable. Here is the DB2 UDB version of CF-5.10. Even in IBM UDB 5, UNIQUE requires NOT NULLABLE, and so is equivalent to a primary key constraint. Code Fragment 5.25 Prevent value-equivalent rows in INCUMBENTS, in DB2 UDB 5. CREATE TABLE INCUMBENTS ( SSN DECIMAL(9,0) NOT NULL, PCN DECIMAL(6,0) NOT NULL, START_DATE DATE, END_DATE DATE, PRIMARY KEY (SSN, PCN) ) IBM DB2 UDB also does not support assertions, nor a SELECT statement within a CHECK constraint; triggers are used to implement these checks. As an example, CF-5.8 may be implemented as the following DB2 UDB trigger. 5.8 Code Fragment 5.26 IMPLEMENTATION CONSIDERATIONS 133 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in DB2 UDB. CREATE TRIGGER seq_primary_key NO CASCADE BEFORE INSERT ON INCUMBENTS REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL WHEN (EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN = N.SSN AND I.PCN = N.PCN AND I.START_DATE < N.END_DATE AND N.START_DATE < I.END_DATE) OR N.SSN IS NULL OR N.PCN IS NULL) SIGNAL SQLSTATE 70003 (Violates Sequenced primary key) Using triggers instead of CHECK constraints can signicantly complicate matters. As an example, to specify current referential integrity (CF-5.20) in DB2 UDB requires four triggers—INSERT and UPDATE triggers on INCUMBENTS and DELETE and UPDATE triggers on POSITIONS—instead of the single fairly simple CHECK constraint given earlier. 5.8.2 Microsoft Access “Forever” in Microsoft Access 97 and Access 2000 is 23:59:59 December 31, 9999 C.E. Neither version of Microsoft Access supports assertions. Assertion checking can be implemented in Access via Visual Basic functions that are activated by events provided in Access forms, in particular, the After Insert event. As an example, the following is the Visual Basic code to implement a sequenced primary key (CF-5.8). Code Fragment 5.27 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in Access. Function Sequenced_Primary_Key() Dim dbs As Database, rst As Recordset Dim rst2 As Recordset Set dbs = CurrentDb Set rst = & & & & & & dbs.OpenRecordset("SELECT I1.SSN " _ "FROM INCUMBENTS AS I1 " _ "WHERE 1 < ( SELECT COUNT (SSN) " _ "FROM INCUMBENTS AS I2 " _ "WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN " _ "AND I1.START_DATE < I2.END_DATE " _ "AND I2.START_DATE < I1.END_DATE); ") continued on page 134 134 CHAPTER FIVE : DEFINING STATE TABLES continued from page 133 Set rst2 = dbs.OpenRecordset("SELECT * " _ & "FROM INCUMBENTS AS I " _ & "WHERE I.SSN IS NULL " _ & "OR I.PCN IS NULL ;") If (rst1.EOF And rst1.BOF) Or (rst2.EOF And rst2.BOF) Then MsgBox ("Insertion completed") Else MsgBox ("You entered an invalid input") End If End Function If the result of the query (the OpenRecordset) is empty, then the assertion is satised. Microsoft Access 97 also doesn't support full nesting of SQL statements. Some complex queries have to be divided into several one-statement queries, then combined in Visual Basic functions. For example, here is the Access equivalent of CF-5.21. Code Fragment 5.28 INCUMBENTS.PCN is a sequenced foreign key for POSITIONS.PCN (both tables are temporal), in Access. Function Sequenced_Foreign_Key( ) Dim Dim Dim Dim Dim dbs As Database rst1 As Recordset rst2 As Recordset rst3 As Recordset Record_Number As Long Set dbs = CurrentDb Set rst1 = dbs.OpenRecordset("SELECT * " _ & "FROM INCUMBENTS AS I " _ & "WHERE NOT EXISTS ( SELECT * " _ & "FROM POSITIONS AS P " _ & "WHERE I.PCN = P.PCN " _ & "AND P.START_DATE <= I.START_DATE " _ & "AND I.START_DATE < P.END_DATE ) ") Set rst2 = dbs.OpenRecordset("SELECT * " _ & "FROM INCUMBENTS AS I " _ & "WHERE NOT EXISTS ( SELECT * " _ & "FROM POSITIONS AS P " _ 5.8 IMPLEMENTATION CONSIDERATIONS 135 & "WHERE I.PCN = P.PCN " _ & "AND P.START_DATE < I.END_DATE " _ & "AND I.END_DATE <= P.END_DATE ) ") Set rst3 = dbs.OpenRecordset("SELECT * " _ & "FROM INCUMBENTS AS I " _ & "WHERE EXISTS ( SELECT * " _ & "FROM POSITIONS AS P " _ & "WHERE I.PCN = P.PCN " _ & "AND I.START_DATE < P.END_DATE " _ & "AND P.END_DATE < I.END_DATE " _ & "AND NOT EXISTS ( " _ & "SELECT * " _ & "FROM POSITIONS AS P2 " _ & "WHERE P2.PCN = P.PCN " _ & "AND P2.START_DATE <= P.END_DATE " _ & "AND P.END_DATE < P2.END_DATE )) ") If (rst1.EOF And rst1.BOF) Or (rst2.EOF And rst2.BOF) Or (rst3.EOF And rst3.BOF) Then MsgBox ("Insertion completed") Else MsgBox ("You entered an invalid input") End If End Function Each OpenRecordset handles one of the NOT EXISTS clauses of CF-5.21. Microsoft Access 2000 does support nested SQL statements. While the above function will work in Access 2000, a single OpenRecordset statement is also acceptable. 5.8.3 Microsoft SQL Server Microsoft SQL Server does not support ASSERTIONs; these must be implemented as triggers. As an example, CF-5.8 may be implemented as the following SQL Server trigger. Code Fragment 5.29 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in Microsoft SQL Server. CREATE TRIGGER Seq_Primary_Key ON INCUMBENTS FOR INSERT, UPDATE, DELETE AS continued on page 136 136 CHAPTER FIVE : DEFINING STATE TABLES continued from page 135 BEGIN IF (( EXISTS ( SELECT I1.SSN FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(I2.SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE))) OR ( EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL OR I.PCN IS NULL)) ) RAISERROR(Transaction violates sequenced constraint, 1, 2) ROLLBACK TRANSACTION END 5.8.4 Sybase SQLServer Sybase SQLServer does not support ASSERTIONs; these must be implemented as triggers. As an example, CF-5.8 may be implemented as the following Sybase trigger. Code Fragment 5.30 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in Sybase. CREATE TRIGGER Seq_Primary_Key ON INCUMBENTS FOR INSERT, UPDATE, DELETE AS BEGIN IF (( EXISTS ( SELECT I1.SSN FROM INCUMBENTS AS I1 WHERE 1 < (SELECT COUNT(I2.SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE))) OR ( EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL OR I.PCN IS NULL)) ) RAISERROR(Transaction violates sequenced constraint, 1, 2) ROLLBACK TRANSACTION END 5.8 IMPLEMENTATION CONSIDERATIONS 137 Another approach is to use the syb identity function to differentiate rows, similar to rowid in Oracle (compare with CF-5.31, below). To use this, “auto identity” must be turned on via sp_dboption database name, "auto identity", "true" Otherwise, a column must be added to the table. ALTER TABLE INCUMBENTS ADD row_id NUMERIC(5,0) IDENTITY 5.8.5 Oracle8 Server “Forever” in Oracle8 Server is 23:59:59 December 31, 4712 C . E . This avoids the year 2000 problem and the year 3000 problem, and even the year 4000 problem. Oracle8 Server does not support assertions nor complex CHECK constraints; triggers must be used to implement these. As an example, CF-5.8 may be implemented as the following Oracle trigger. Code Fragment 5.31 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in Oracle. CREATE OR REPLACE TRIGGER seq_primary_key AFTER INSERT OR UPDATE ON INCUMBENTS DECLARE valid INTEGER; BEGIN SELECT 1 INTO valid FROM DUAL WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS I1 , INCUMBENTS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.START_DATE < I2.END_DATE AND I2.START_DATE < I1.END_DATE AND I1.rowid <> I2.rowid ) AND NOT EXISTS ( SELECT * FROM INCUMBENTS I1 WHERE I1.SSN IS NULL OR I1.PCN IS NULL); EXCEPTION WHEN NO_DATA_FOUND THEN RAISE_APPLICATION_ERROR ( -20001 , SSN and PCN are sequenced primary keys ); END; 138 CHAPTER FIVE : DEFINING STATE TABLES In this trigger, if the WHERE clause is not satised, then the exception will be raised, causing the transaction to abort. (DUAL is a dummy system table provided by Oracle8 Server for exactly this kind of situation.) This example also illustrates the use of Oracle8 Server's rowid facility, which eliminates the need of COUNT (which appeared in the original CF-5.8) to ensure no duplicates. Another relevant limitation is that there can be only one INSERT/UPDATE trigger per table in Oracle8 Server, so multiple CHECK constraints or ASSERTIONs on a table must be merged into a single trigger. 5.8.6 UniSQL UniSQL does not support ASSERTIONs; these must be implemented as triggers. As an example, CF-5.8 may be implemented as the following UniSQL trigger. Code Fragment 5.32 (SSN, PCN) is a sequenced primary key for INCUMBENTS, in UniSQL. CREATE TRIGGER seq_primary_key BEFORE COMMIT IF (EXISTS ( SELECT I1.SSN FROM Incumbents AS I1 WHERE 1 < (SELECT COUNT(SSN) FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN AND I1.PCN = I2.PCN AND I1.StartDate < I2.EndDate AND I2.StartDate < I1.EndDate)) OR EXISTS ( SELECT * FROM INCUMBENTS AS I WHERE I.SSN IS NULL OR I.PCN IS NULL) ) EXECUTE REJECT; 5.8.7 CD-ROM Materials The CD-ROM contains all the code fragments in this chapter in IBM DB2 UDB, Microsoft Access 2000, Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL. 5.9 5.9 SUMMARY 139 SUMMARY A valid-time state table retains the history of the modeled reality. A table is rendered temporal by appending one or more timestamp columns, to specify the period of validity of each row. As SQL doesn't (yet) provide a period data type, generally two datetime columns are appended, indicating the start and end of the period. The representation can be closed-closed or closed-open, with the latter preferred. The end time for current data should be the logical value “now.” SQL supports CURRENT DATE in queries, but not as a stored value. Possibilities include using a distinguished value (UIS uses 1860-01-01 and 3000-01-01) or the value NULL. The best approach is to use a value approximating “forever.” In Section 7.5 we will see another approach that obviates the need to store “now.” The original primary key of the table is not the primary key of the temporal table. Unfortunately, adding the start column, or the end column, or both, generally does not sufce to dene the primary key. The central notion of a key is the absence of duplicates. There are four kinds of uniqueness constraints: 1. Current: No two currently valid rows have the same value for the key columns. 2. Value-equivalent: No two rows have the same value for their nontimestamp columns. 3. Sequenced: No two rows have the same value for the key columns at any instant. 4. Nonsequenced: No two rows have the same value for all their columns. The database designer should rst determine which uniqueness constraint is required by the application. Then the appropriate code fragment can be used as a template. Value-equivalent and nonsequenced uniqueness can be specied using the UNIQUE construct. An SQL constraint or assertion is required to specify current and sequenced constraints. (In the restricted case where future information will never be stored, adding the end column sufces for a current primary key.) A sequenced primary key is the natural analog of a primary key on a nontemporal table and is what is usually desired. If the application only modies the current state, then column(s) that comprise a current primary key will also satisfy the sequenced primary key constraint. In that case, the end time should be included in the constraint (see CF-5.13). If any application will store future or past data, then the general constraint for sequenced primary keys (CF-5.8) or sequenced uniqueness (CF-5.14) is required. 140 CHAPTER FIVE : DEFINING STATE TABLES Table 5.4 Referential integrity code fragments. Nontemporal Referenced Table Temporal Current Nonsequenced Sequenced Referencing Nontemporal 5.19 5.24 5.19 5.20 or 5.19 Table Temporal 5.19 5.20 5.19 5.21 or 5.22 + 5.23 How to express a referential integrity constraint depends on whether the referencing and referenced tables are temporal tables. Six code fragments were given to illustrate the possibilities. Table 5.4 identies which code fragment applies in each situation. In many cases, a simple constraint sufces. However, when both tables are temporal, the most natural referential constraint is a sequenced one, where a complex assertion (CF-5.21) or pair of assertions (CF-5.22, CF-5.23) is required. All such constraints should be specied as DEFERRABLE INITIALLY DEFERRED. 5.10 READINGS Ensor and Stevenson [32] recommend storing a distant date for now, as do we in Section 5.4. They recommend that the end date column be used for a primary key. As we saw in Section 5.5, this works only when future data will never be inserted into the table, and then, only to enforce a current primary key. They also recommend that the end date column be added for referential integrity, which has the same problems as using this approach with the primary key. They also consider the related problem of avoiding gaps in the history of an entity. If gaps cannot occur, then referential integrity reduces to ensuring that the combined period of validity for the entity in the referenced table (identied by the foreign key) contains the period of validity of the row that references it (see CF-5.23). 5.10 READINGS 141 Clifford et al. show how CURRENT DATE can be stored directly as a column value, thereby providing support for “now” [23]. This approach requires a few changes to the underlying DBMS. Böhlen differentiates between intrastate integrity constraints, which “enforce the consistency of (all) snapshots of a valid time database,” and interstate integrity constraints, which “relate and restrict arbitrary snapshots of a valid time database,” [11]. (A snapshot of a valid-time table at a specic time instant consists of the rows that were valid at that time.) A sequenced constraint is thus an intrastate constraint, and a nonsequenced constraint is thus an interstate constraint. We discuss Böhlen's taxonomy in more detail on page 341. Barnert et al. provide an analysis of the checking required during various kinds of modications to ensure sequenced referential integrity [4]. David Landes tells the exciting story of Needham's discovery of Su Song's clepsydra [65]. CHAPTER 6 O V E R V I E W With the history stored in a valid-time state For each current query, for example, “Who table, the most prevalent queries are still of the makes more than $50,000 annually?” there is form “What is true now?” Such current queries an analogous sequenced query that asks for the are easy to convert into SQL. A related kind of history, for example, “Who makes or has made query is, “What is true at a point in time other more than $50,000 annually, and when?” Conthan now?” These easy to convert. time-slice queries are also verting such queries to SQL can be challenging. Querying State Tables I n the previous chapter, we saw that there are three kinds of constraints you can specify for a temporal table: current, sequenced, and nonsequenced, with nonsequenced constraints the easiest to specify yet the least useful. A similar situation exists for queries and modications applied to temporal tables. Here we examine common queries over temporal tables, from extracting the current state, to extracting previous states, to evaluating several kinds of sequenced queries. In the following chapter, we then turn to modications, examining the three variants there. We assume that the INCUMBENTS and SAL HISTORY tables are valid-time state tables. 6.1 EXTRACTING THE CURRENT STATE Executing a query on the current state of a temporal table requires an additional predicate. Code Fragment 6.1 Queries on the original table (before it was timestamped to render it as a valid-time table) correspond to queries that extract the current state of the valid-time table. To determine Bob's (current) position, we take the original query (CF-5.2) and add a predicate to the WHERE clause. What is Bob's current position? SELECT JOB_TITLE_CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND END_DATE = DATE 3000-01-01 144 CHAPTER SIX : QUERYING STATE TABLES Note that only one of the tables used in this query is temporal: INCUMBENTS. Hence the test for the particular date need only be applied to that table. We could use the same approach when “now” is represented with NULL. The query on a table using the end of time (“forever”) to represent “now” is more general, as it will work even after the year 3000, thus avoiding the Y3K problem. Code Fragment 6.2 What is Bob's current position? SELECT JOB_TITLE_CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND START_DATE <= CURRENT_DATE AND CURRENT_DATE < END_DATE The last two lines of the predicate are equivalent to requiring that the current date overlap the period of validity. Note that BETWEEN cannot be used here, because it would permit the END DATE to equal CURRENT TIMESTAMP, which is incorrect because we are using a closed-open representation for period timestamps. Joins over the current state of temporal tables can be handled similarly to queries involving one temporal table. To obtain Current joins over two temporal tables are not that much harder. the employee's (current) position and salary, the current state of both the INCUMBENTS and the SAL HISTORY tables must be used. (We could have also gotten the current salary from the EMPLOYEES table, but that wouldn't have been as fun.) Code Fragment 6.3 What is Bob's current position and salary? SELECT JOB_TITLE_CODE1, AMOUNT FROM EMPLOYEES, INCUMBENTS, POSITIONS, SAL_HISTORY WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND START_DATE <= CURRENT_DATE AND CURRENT_DATE < END_DATE AND HISTORY_START_DATE <= CURRENT_DATE AND CURRENT_DATE < HISTORY_END_DATE AND SAL_HISTORY.SSN = EMPLOYEES.SSN This same trick works for more complex queries, including those with subqueries. Code Fragment 6.4 What employees currently have no position? SELECT FIRST_NAME FROM EMPLOYEES WHERE NOT EXISTS ( SELECT * 6.3 SEQUENCED QUERIES 145 FROM INCUMBENTS WHERE EMPLOYEES.SSN = INCUMBENTS.SSN AND START_DATE <= CURRENT_DATE AND CURRENT_DATE < END_DATE) In such queries, every temporal table has to be restricted to the current state. 6.2 EXTRACTING PRIOR STATES The queries just discussed are termed current time-slice queries. More accurately, the class is termed a current valid time-slice query, as such queries select the state valid at a particular time. Time-slice queries need not be restricted to the current state. A common query requests information valid at the beginning of the year. Code Fragment 6.5 What was Bob's position at the beginning of 1997? SELECT JOB_TITLE_CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND START_DATE <= DATE 1997-01-01 AND DATE 1997-01-01 < END_DATE If “now” is represented with a particular value, we have to augment the predicate, replacing the last line with AND (DATE 1997-01-01 Time-slice queries, over a previous state, require an additional predicate for each temporal table. 6.3 <= END_DATE OR END_DATE = DATE 1860-01-01) Using NULL as a proxy for “now” is handled analogously in such queries: AND (DATE 1997-01-01 <= END_DATE OR END_DATE IS NULL) For queries involving multiple temporal tables, the WHERE clause most closely associated with the FROM clause that denes a correlation name over a temporal table should be augmented as shown above to select the previous state of that table. SEQUENCED QUERIES The above queries take time-varying tables and extract a state at a particular point in time. Once that state is available, it can be manipulated conventionally. 146 CHAPTER SIX : QUERYING STATE TABLES We now consider queries in which the resulting table is a valid-time table. The query will be over one or more temporal tables and produce a temporal result. Here we consider sequenced variants of basic operations: selection, projection, union, sorting, join, difference, and duplicate elimination. Sequenced selection is particularly easy: no change is necessary. Code Fragment 6.6 Who makes or has made more than $50,000 annually? SELECT * FROM SAL_HISTORY WHERE AMOUNT > 50000 In this code fragment we focus on selection by using a target list of `*', which will return all the columns, including the desired timestamp columns. This is in contrast to a current query, which should A selection (a predicate over a return a snapshot state, without timestamp columns (compare nontimestamp column) is a with CF-6.3 and CF-6.4), or with a prior valid time-slice query sequenced selection on a (e.g, CF-6.5, which also doesn't include the timestamp columns). temporal table. Sequenced projection is also easy: simply include the timestamp column(s) in the select list. The following query performs a projection on SSN. Code Fragment 6.7 List the social security numbers of current and past employees. SELECT SSN, HISTORY_START_DATE, HISTORY_END_DATE FROM SAL_HISTORY A sequenced projection of specied columns in the SELECT clause can be effected by including the timestamp columns. Code Fragment 6.8 Note that duplicates resulting from the projection are retained. Adding DISTINCT will remove these duplicates, but is probably not what is desired. Section 6.5 will examine the fascinating subtleties of removing duplicates from temporal tables, including describing why adding DISTINCT is not sufcient. Sequenced sorting requires the result to be ordered, at each point in time. This can easily be accomplished by appending the start and end times to the sort columns in the ORDER BY clause. Sequenced sort INCUMBENTS on the position code (rst version). SELECT * FROM INCUMBENTS ORDER BY PCN, START_DATE, END_DATE Table 6.1 shows the result for ve sample rows. For each point in time, the state at that time, taken in the same sequence as the underlying table, will be ordered by PCN. 6.3 SEQUENCED QUERIES 147 Table 6.1 An excerpt of INCUMBENTS. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 111223333 120033 137112 341288 723401 908654 1996-10-01 1996-01-01 1995-03-01 1997-10-01 1997-06-01 1997-06-01 1996-10-01 1996-01-01 1998-01-01 1998-01-01 Table 6.2 A sorted version of Table 6.1. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 111223333 341288 137112 120033 908654 723401 1995-03-01 1996-01-01 1996-10-01 1997-06-01 1997-10-01 1996-01-01 1996-10-01 1997-06-01 1998-01-01 1998-01-01 The valid time-slice over this table on November 19, 1997 will be the following, which indeed is ordered by PCN: SSN PCN 111223333 111223333 723401 908654 Putting the timestamp columns rst, ORDER BY START_DATE, END_DATE, PCN will not work. Applying such an order to Table 6.1 results in Table 6.2. Now take a valid time-slice on November 19, 1997, preserving the underlying order. Two rows result, SSN PCN 111223333 111223333 908654 723401 which are not correctly sorted. 148 CHAPTER SIX : QUERYING STATE TABLES So, our conclusion is that appending the timestamp columns to the end of the composite sort key results in a sequenced sort. Interestingly, sequenced sorting can also be accomplished by omitting the timestamp columns. Code Fragment 6.9 Sequenced sort INCUMBENTS on the position code (second version). SELECT * FROM INCUMBENTS ORDER BY PCN The result is still ordered by the sort columns at all points in time. This can be argued by contradiction. Take a valid time-slice at any point in time of the result of CF-6.9, respecting the order of that table. If the PCN of two successive rows of that time-slice are not ordered by PCN, then the associated rows of the result of CF-6.9 must also not be ordered by PCN, which is impossible. The same considerations hold for sequenced union (if duplicates are retained). A query using ORDER BY is automatically sequenced, whether or not the timestamp columns are retained. Code Fragment 6.10 Who makes or has made more than $50,000 annually or less than $10,000? SELECT * FROM SAL_HISTORY WHERE AMOUNT > 50000 UNION ALL SELECT * FROM SAL_HISTORY WHERE AMOUNT < 10000 It is appealing that the selection, projection (without duplicate elimination), sorting, and union-all queries are all automatically A UNION ALL over temporal sequenced, without change. tables is automatically A UNION without ALL eliminates duplicates but is surprissequenced if the timestamp ingly difcult to express in SQL. Section 6.5 will show how to columns are retained. do that. But before we confront that challenging query, let's consider sequenced join queries. 6.3.1 Sequenced Joins In Section 6.1, we showed how you can produce the join of the current states of two valid-time tables (see CF-6.3). A more challenging query is to perform the join itself in a temporal fashion. What is desired here is to combine the history from the two tables, termed a sequenced join. As an example, to determine the salary and position history for each employee, we must determine, for each point in time, the employee's salary and position. 6.3 149 SEQUENCED QUERIES Mean Solar Time Minutes One problem with true solar time (see page 95) is that the motion of the sun is not uniform because the orbit of the earth is an ellipse rather than a circle. Sometimes the earth moves faster, and sometimes it moves slower, with the result that some days are slightly shorter or longer than others. This variability is vexing to those who use mechanical clocks, which when working well tick off hours that are very similar in duration. Mean solar time, or mean time, is a calculated time, determined by averaging true solar time over the year. The difference between mean solar time and true solar time, termed the equation of time, peaks at +14 minutes in February, and is smallest at 16 minutes at the beginning of November (see Figure 6.1). To calibrate your watch, take the true time indicated by a sundial and add the value for the equation of time for the current day. Without this correction, a sundial is absolutely accurate only four times a year—around April 16, June 14, September 1, and December 25. +15 +12 +9 +6 +3 0 -3 -6 -9 -12 -15 J F M A M J J A S O N D J Figure 6.1 The equation of time. (Redrawn from Sundials: History, Theory, and Practice by René R.J. Rohr. Dover Publications, 1996.) The salary comes from SAL HISTORY.AMOUNT, and the position is available in INCUMBENTS.PCN. However, to do this on a point-by-point basis would be extremely inefcient, as well as wasteful, because the salary and position remain unchanged for many consecutive days. So we will instead compute the history using the periods themselves. We initially assume that there are no duplicate rows in either of the underlying temporal tables. This is probably the case for the SAL HISTORY table; it is doubtful that an employee has two salaries at one time. The fact that an employee can have multiple positions (e.g., a department head who is also a faculty member) is accommodated via the position control number. The POSITIONS table maps each PCN to JOB TITLE CODE1 through JOB TITLE CODE4; indeed, this is the primary rationale 150 CHAPTER SIX : QUERYING STATE TABLES SAL_HISTORY INCUMBENTS Result Figure 6.2 First case of a sequenced join. SAL_HISTORY INCUMBENTS Result Figure 6.3 Second case of a sequenced join. for that table. On page 112 we listed only the JOB TITLE CODE1 column; we now mention these other three columns to make the point that no employee has two PCN values at the same time in the POSITIONS table. In summary, in the case of a sequenced join between the SAL HISTORY and POSITIONS tables, there are no duplicate rows to contend with. Using SQL, the query must do a case analysis of how the period of validity of each row of SAL HISTORY overlaps the period of validity of each row of INCUMBENTS; there are four possible cases. In the rst case, the period associated with the SAL HISTORY row is entirely contained in the period associated with the INA sequenced join requires four SELECT statements and complex CUMBENTS row. Since we are interested in those times when both the salary and the department are valid, the intersection of the inequality predicates. two periods is the contained period, that is, the period from S.HISTORY START DATE to S.HISTORY END DATE. We illustrate this case in Figure 6.2, with the right end emphasizing the closed-open representation. In the second case, neither period contains the other (shown in Figure 6.3). The other cases similarly identify the overlap of the two periods. 6.3 Code Fragment 6.11 SEQUENCED QUERIES 151 Provide the salary and position history for all employees. SELECT S.SSN, AMOUNT, PCN, S.HISTORY_START_DATE, S.HISTORY_END_DATE FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND INCUMBENTS.START_DATE <= S.HISTORY_START_DATE AND S.HISTORY_END_DATE <= INCUMBENTS.END_DATE UNION ALL SELECT S.SSN, AMOUNT, PCN, S.HISTORY_START_DATE, INCUMBENTS.END_DATE FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND S.HISTORY_START_DATE >= INCUMBENTS.START_DATE AND INCUMBENTS.END_DATE < S.HISTORY.END_DATE AND S.HISTORY_START_DATE < INCUMBENTS.END_DATE UNION ALL SELECT S.SSN, AMOUNT, PCN, INCUMBENTS.START_DATE, S.HISTORY_END_DATE FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND INCUMBENTS.START_DATE > S.HISTORY_START_DATE AND S.HISTORY.END_DATE <= INCUMBENTS.END_DATE AND INCUMBENTS.START_DATE < S.HISTORY_END_DATE UNION ALL SELECT S.SSN, AMOUNT, PCN, INCUMBENTS.START_DATE, INCUMBENTS.END_DATE FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND INCUMBENTS.START_DATE > S.HISTORY_START_DATE AND INCUMBENTS.END_DATE < S.HISTORY_END_DATE When a sequenced join is applied to the INCUMBENTS excerpt in Table 6.1 and the SAL HISTORY excerpt in Table 6.3, Table 6.4 results. The rst row, for example, results from the intersection of the period [1995-03-01 – 1996-01-01) from the INCUMBENTS table and [1995-03-01 – 1996-05-01) from the SAL HISTORY table. As an alternative way of viewing the result, consider the date January 1, 1997. One row in the INCUMBENTS table is valid on that day, with a PCN of 120033. One row from the SAL HISTORY table is also valid on that date, with an amount of 16.25. This date thus appears once in the result, in the period of validity of row four. This query requires care to get the 10 inequalities and the four select lists correct. The cases are designed to partition the possible interactions between the SAL HISTORY and INCUMBENTS rows. Specically, the rst case covers s finishes i _ s during i _ s starts i _ s equals i, the second case s overlaps 1 i _ s starts 1 i, the third case s overlaps i _ s finishes 1 i, and the last case s during 1 i (see 152 CHAPTER SIX : QUERYING STATE TABLES Table 6.3 An excerpt from the SAL HISTORY valid-time state table. SSN AMOUNT HISTORY START DATE HISTORY END DATE 111223333 111223333 111223333 15.75 16.25 17.00 1995-03-01 1996-05-01 1997-06-01 1996-05-01 1997-06-01 1998-01-01 Table 6.4 Result of the sequenced join. SSN AMOUNT PCN START DATE END DATE 111223333 111223333 111223333 111223333 111223333 111223333 15.75 15.75 16.25 16.25 17.00 17.00 341288 137112 137112 120033 908654 723401 1995-03-01 1996-01-01 1996-05-01 1996-10-01 1997-06-01 1997-10-01 1996-01-01 1996-05-01 1996-10-01 1997-06-01 1998-01-01 1998-01-01 page 92 for an illustration of these operators). Because none of these relationships is covered by more than one case, no duplicates will be generated. For this reason, we use UNION ALL, which is generally more efcient than UNION, which does a lot of work to remove the (nonoccurring) duplicates. The above code fragments assume that the underlying temporal tables contain no duplicates. If that assumption does not hold, we have three choices: 1. Retain duplicates in the result. 2. Use CF-6.11, replacing UNION ALL with UNION, and eliminate the duplicates after the join, as discussed in the next section. 3. Eliminate duplicates before the join, then use CF-6.11. The SQL-92 CASE expression allows this query to be written as a single statement, thereby avoiding the complexities of UNION versus UNION ALL. Code Fragment 6.12 Provide the salary and position history for all employees, using CASE. SELECT S.SSN, AMOUNT, PCN, CASE WHEN S.HISTORY_START_DATE > INCUMBENTS.START_DATE THEN S.HISTORY_START_DATE ELSE INCUMBENTS.START_DATE END, CASE WHEN S.HISTORY_END_DATE > INCUMBENTS.END_DATE THEN INCUMBENTS.END_DATE 6.3 SEQUENCED QUERIES 153 ELSE S.HISTORY_END_DATE END FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND (CASE WHEN S.HISTORY_START_DATE > INCUMBENTS.START_DATE THEN S.HISTORY_START_DATE ELSE INCUMBENTS.START_DATE END) < (CASE WHEN S.HISTORY_END_DATE > INCUMBENTS.END_DATE THEN INCUMBENTS.END_DATE ELSE S.HISTORY_END_DATE END) The rst CASE expression simulates a last instant function of two arguments; the second, a rst instant function of the two arguments. The additional WHERE predicate ensures the period of validity is well formed, that its starting instant occurs before its ending instant. As we will see later, the rst instant and last instant functions are available (under different names) from some vendors as SQL extensions. They can also be implemented as SQL/PSM (persistent stored module) FUNCTIONs. Code Fragment 6.13 Dene a first instant function. CREATE FUNCTION first_instant (one DATE, two DATE) RETURNS DATE LANGUAGE SQL RETURN CASE WHEN one > two THEN one ELSE two END A last instant function can be similarly dened. In fact, we can exploit polymorphism in SQL/PSM by dening a host of first instant and last instant functions, each taking two parameters of each of the various temporal types (e.g., TIME, TIMESTAMP, TIMESTAMP(3)) and returning the same type. With these functions, the sequenced join is considerably simplied. Code Fragment 6.14 Provide the salary and position history for all employees, using first instant and last instant. SELECT S.SSN, AMOUNT, PCN, last_instant(S.HISTORY_START_DATE, INCUMBENTS.START_DATE), first_instant(S.HISTORY_END_DATE, INCUMBENTS.END_DATE) FROM SAL_HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND last_instant(S.HISTORY_START_DATE, INCUMBENTS.START_DATE) < first_instant(S.HISTORY_END_DATE, INCUMBENTS.END_DATE) 154 6.3.2 CHAPTER SIX : QUERYING STATE TABLES Sequenced EXCEPT A join of two tables repeatedly takes a row from each and applies a predicate to both to determine whether the rows contribute to the result. The NOT EXISTS construct of SQL is similar, with the critical distinction that the row from the second table must not exist. This distinction renders the sequenced NOT EXISTS more challenging than a sequenced join. As before, let's start with a nontemporal query and convert it to its sequenced analog. Assume that employees have multiple positions, as an example, a department head (a PCN of 455332) who is also a professor (a PCN of 821197). We wish to identify the exceptions, that is, the department heads who are not also professors. Code Fragment 6.15 List the employees who are department heads but are not also professors (nontemporal version). SELECT SSN FROM INCUMBENTS AS I1 WHERE PCN = 455332 AND NOT EXISTS (SELECT * FROM INCUMBENTS AS I2 WHERE I2.SSN = I1.SSN AND I2.PCN = 821197) For the sequenced version, we wish to identify when the department heads were not professors. Employees are promoted to department head, remain a few years, then someone else becomes department head. Somewhat independently, employees are promoted to the rank of professor; very occasionally, they are demoted to associate professor. Hence, the two SELECT clauses in the above code fragment evaluate to time-varying tables; the NOT EXISTS must perform the relational difference conceptually at each point in time. The result will be a valid-time state table; the challenge is to restate the query so that it computes the timestamps of this table correctly. As an aside, the SQL NOT EXISTS is closely tied to the EXCEPT construct: Code Fragment 6.16 List the employees who are department heads but are not also professors (an equivalent nontemporal version). SELECT SSN FROM INCUMBENTS WHERE PCN = 455332 EXCEPT SELECT SSN FROM INCUMBENTS WHERE PCN = 821197 6.3 SEQUENCED QUERIES 155 This is the relational difference operator, expressed in SQL. The transformation we give for NOT EXISTS is also applicable for EXCEPT. NOT EXISTS is also closely related to NOT IN: Code Fragment 6.17 List the employees who are department heads but are not also professors (an equivalent nontemporal version). SELECT SSN FROM INCUMBENTS AS I1 WHERE PCN = 455332 AND 821197 NOT IN (SELECT PCN FROM INCUMBENTS AS I2 WHERE I1.SSN = I2.SSN) Returning to the EXCEPT query (CF-6.15), let's focus on a row output by the sequenced version of this query. As illustrated in Figure 6.4, there are four ways in which an output row could result. In the rst case, the employee starts being a department head when he or she is still an associate professor; the output row ends when the person is promoted to professor. In the second case, the department head, who was a professor, was for some reason demoted. The third case is a combination of the rst two: the department head was demoted, then subsequently promoted back to professor. In all three cases, there must not exist another row with a rank of professor that overlaps the resulting row (otherwise, the NOT EXISTS would not hold). In the last case, the department head was never a professor during his or her tenure, so the entire period of validity should be returned. These cases allow us to compute the delimiting timestamps of the resulting row. Each of these cases requires a separate SELECT statement in the sequenced version. A sequenced NOT EXISTS (EXCEPT, NOT IN) requires four SELECT statements, each with a nested NOT EXISTS. Code Fragment 6.18 List the employees who are or were department heads but were not also professors (sequenced version). SELECT I1.SSN, I1.START_DATE, I3.START_DATE AS END_DATE FROM INCUMBENTS AS I1, INCUMBENTS AS I3 WHERE I1.PCN = 455332 AND I3.PCN = 821197 AND I1.SSN = I3.SSN AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I4 WHERE I4.SSN = I1.SSN AND I4.PCN = 821197 AND I1.START_DATE < I4.END_DATE AND I4.START_DATE < I3.START_DATE) continued on page 156 156 CHAPTER SIX : QUERYING STATE TABLES continued from page 155 UNION SELECT I1.SSN, I2.END_DATE AS START_DATE, I1.START_DATE AS END_DATE FROM INCUMBENTS AS I1, INCUMBENTS AS I2 WHERE I1.PCN = 455332 AND I2.PCN = 821197 AND I1.SSN = I2.SSN AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I4 WHERE I4.SSN = I1.SSN AND I4.PCN = 821197 AND I2.END_DATE < I4.END_DATE AND I4.START_DATE < I1.END_DATE) UNION SELECT I1.SSN, I1.END_DATE AS START_DATE, I3.START_DATE AS END_DATE FROM INCUMBENTS AS I1, INCUMBENTS AS I2, INCUMBENTS AS I3 WHERE I1.PCN = 455332 AND I2.PCN = 821197 AND I3.PCN = 821197 AND I1.SSN = I2.SSN AND I1.SSN = I3.SSN AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I4 WHERE I4.SSN = I1.SSN AND I4.PCN = 821197 AND I2.END_DATE < I4.END_DATE AND I4.START_DATE < I3.START_DATE) UNION SELECT SSN, START_DATE, END_DATE FROM INCUMBENTS AS I1 WHERE PCN = 455332 AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I4 WHERE I4.SSN = I1.SSN AND I4.PCN = 821197 AND I1.START_DATE < I4.END_DATE AND I4.START_DATE < I1.END_DATE) The cases are quite similar; they differ in the specic timestamps chosen in the target lists and in the timestamps used in the NOT EXISTS subqueries. 6.4 NONSEQUENCED VARIANTS We have seen current and sequenced versions of selection, projection, join, union, and sorting. As with the integrity constraints discussed in the previous chapter, nonsequenced versions of these operators on temporal tables are straightforward. Such queries ignore the time-varying nature of the tables. 6.4 NONSEQUENCED VARIANTS 157 Output row Department head Case 1 Professor Department head Case 2 Professor Department head Case 3 Professor Case 4 Professor Department head Figure 6.4 Current update cases, with the period of validity of the row shown. Code Fragment 6.19 List all the salaries, past and present, of employees who had been a hazardous waste specialist at some time. SELECT AMOUNT FROM INCUMBENTS, POSITIONS, SAL_HISTORY WHERE INCUMBENTS.SSN = SAL_HISTORY.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND JOB_TITLE_CODE1 = 20730 158 CHAPTER SIX : QUERYING STATE TABLES The phrases “past and present” and “at some time” indicate that the query is a nonsequenced one. The periods of validity of both INCUMBENTS and SAL HISTORY are simply ignored in this query. Some nonsequenced queries do examine the timestamps. However, they are evaluated all at once, rather than at a specied time (a time-slice query) or at each point in time (a sequenced query). A common example is determining when change occurred by observing consecutive periods that signify that change. Code Fragment 6.20 When did employees receive raises? SELECT S2.SSN, S2.HISTORY_START_DATE AS RAISE_DATE FROM SAL_HISTORY AS S1, SAL_HISTORY AS S2 WHERE S2.AMOUNT > S1.AMOUNT AND S1.SSN = S2.SSN AND S1.HISTORY_END_DATE = S2.HISTORY_START_DATE This is not a sequenced query because each result row is derived from information from two different times. The query does not view the underlying table as a sequence of states; rather, it views the underlying table as one with additional timestamp columns that can be used in the query. When evaluated on the SAL HISTORY excerpt in Table 6.3, the following result is returned: A nonsequenced query considers the timestamp columns as just additional columns. SSN RAISE DATE 111223333 111223333 1996-05-01 1997-06-01 Sequenced, current, and nonsequenced variants also exist for other operators. As shown in Section 6.1, any conventional query can be converted into a current query by adding a predicate for each correlation name. Sequenced variants of many operations were given in Sections 6.3 and 6.3.1. For selection, projection, union, and sorting, the sequenced and nonsequenced variants are identical. For joins, difference (EXCEPT, NOT EXISTS, NOT IN), aggregates, and subqueries, the sequenced and nonsequenced variants are quite different. For duplicate elimination, the analysis is more subtle; we now turn to this intriguing topic. 6.5 ELIMINATING DUPLICATES Duplicates may be present in the underlying table or may arise in the result of operations such as union, projection, and some implementations of sequenced join. 6.5 ELIMINATING DUPLICATES 159 In some cases, the presence of duplicates will change the result of the query, as in the COUNT aggregate. One approach to duplicate elimination is to use the SQL facilities directly. However, that didn't work for the analogous situation of dening a primary key, which as a side effect prevents duplicates. In Section 5.3 we saw that the primary key must be changed when valid-time support is added to a table. We also saw that it wasn't sufcient to simply add either the start time or the end time, or both, to the primary key. Section 5.5 amplied on this, by showing that there were four different kinds of uniqueness constraints. Such considerations also come into play in duplicate elimination. 6.5.1 Easy Duplicate Elimination SQL is perfectly adequate to remove some duplicate variants. Code Fragment 6.21 Remove nonsequenced duplicates from INCUMBENTS. SELECT DISTINCT * FROM INCUMBENTS Value equivalence, which is more useful, is handled similarly, except that the timestamps are not included. Code Fragment 6.22 Remove value-equivalent rows from INCUMBENTS. SELECT DISTINCT SSN, PCN FROM INCUMBENTS Current duplicates involve just a little more effort. Recall that a row is currently valid in the INCUMBENTS table if its END DATE is the special value DATE 3000-01-01. Code Fragment 6.23 Remove current duplicates from INCUMBENTS. SELECT DISTINCT SSN, PCN FROM INCUMBENTS WHERE END_DATE = DATE 3000-01-01 Removing sequenced duplicates turns out to be quite difcult. Before we show how to do this, we discuss coalescing, which is closely related to duplicate elimination. 6.5.2 Coalescing Consider again Table 5.2, copied here as Table 6.5. All ve rows have the same values for the SSN and PCN columns, and hence are value-equivalent. The second and third rows also have the same values for the START DATE and END DATE columns, making them nonsequenced duplicates. 160 CHAPTER SIX : QUERYING STATE TABLES Table 6.5 A table containing several kinds of duplicates. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 111223333 120033 120033 120033 120033 120033 1996-01-01 1996-04-01 1996-04-01 1996-10-01 1997-12-01 1996-06-01 1996-10-01 1996-10-01 1998-01-01 1998-01-01 Now consider the third and fourth rows. As just observed, these rows are value-equivalent, yet are neither sequenced duplicates (the periods of validity do not overlap) nor nonsequenced duplicates (their periods of validity are not identical) nor current duplicates. We focus on these rows because their periods of validity meet (that is, the END DATE of the third row equals the START DATE of the fourth row), and so the two rows could be merged. Coalescing combines value-equivalent rows into a single row with a combined period of validity. Coalescing would merge these two rows into a single row valid from April 1, 1996 to December 31, 1997. Duplicate elimination and coalescing are somewhat orthogonal because in most cases eliminating duplicates (of whatever variant) does not result in a coalesced table, and coalescing can be done without removing duplicates. There are two variants of coalescing: removing and retaining (sequenced) duplicates. After the former is done, there will be Coalescing may remove or retain no sequenced, current, or nonsequenced duplicates. The latter sequenced duplicates. retains the sequenced duplicates present at each point in time. It changes the timestamps, eliminating value-equivalent rows whose periods of validity meet. The objective is to pare down the table to the minimum number of rows necessary to represent the number of duplicates present at each point in time. To illustrate this, let's apply coalescing and duplicate elimination separately on Table 6.5. Coalescing Table 6.5 while removing duplicates results in the following table, merging the ve rows into one: Coalescing reduces the number of rows by merging the periods of validity of value-equivalent rows. SSN PCN START DATE END DATE 111223333 120033 1996-01-01 1998-01-01 Note that the resulting table happens to have no duplicates of any kind, though in general value-equivalent rows are possible (such rows will not overlap or meet). Coalescing Table 6.5 while retaining duplicates results instead in Table 6.6. 6.5 ELIMINATING DUPLICATES 161 Table 6.6 Retaining duplicates while coalescing. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 120033 120033 120033 120033 1996-01-01 1996-04-01 1996-04-01 1997-12-01 1996-06-01 1996-10-01 1998-01-01 1998-01-01 Table 6.7 Another way to retain duplicates while coalescing. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 120033 120033 120033 120033 1996-01-01 1996-04-01 1996-04-01 1997-12-01 1998-01-01 1996-06-01 1996-10-01 1998-01-01 The original table and the coalesced table are snapshot-equivalent: all of their snapshots, resulting from a time-slice at a single instant, are identical. Since duplicates are retained, the snapshot of the result at each instant will have the same number of duplicates as the snapshot of the original table at that instant. Consider a time-slice at January 3, 1996, of Table 6.5. The snapshot contains a single row, (111223333, 120033). The time-slice at that day on Table 6.6 also contains that single row. Now consider May 25, 1996. The time-slice on that date of Table 6.5 contains three rows (you should verify this), as does the time-slice of Table 6.6. In the original table, Table 6.5, and in the coalesced table, Table 6.6, there is one row in the snapshots valid from January 1, 1996 to March 30, 1996, then three rows valid until May 31, 1996, then two rows valid until September 30, 1996, then one row valid until November 30, 1997, then two rows valid until December 31, 1997. These two tables are snapshot-equivalent. Informally, they model the same information, the same history of the enterprise. The only difference: Table 6.6 has fewer rows and thus requires less space on disk. When duplicates are retained, there will be at least as many rows in the resulting table as the maximum number of rows valid at any one time. In this case, the result does not happen to have any nonsequenced duplicates, though such duplicates are possible. When coalescing while removing sequenced duplicates, only one resulting table is possible. However, when coalescing while retaining duplicates, the resulting table is not always unique. Table 6.7 retains the duplicates from Table 6.5 and also contains the minimum number of rows possible: four. 162 CHAPTER SIX : QUERYING STATE TABLES Table 6.6 resulted from merging pairs of value-equivalent rows that met. In Table 6.7, the timestamps experience a more radical adjustment. The one remaining question is, How do you guarantee that the coalesced table is minimized and thus contains the smallest number of rows possible? The answer is simple. It turns out that (repeatedly) merging pairs of value-equivalent rows that meet will always result in a coalesced table with the minimum number of rows. To summarize, we have described three operations that minimize the number of rows: remove sequenced duplicates, coalesce while removing sequenced duplicates, and coalesce while retaining duplicates. If you are going to eliminate duplicates in the rst place, it is just as easy to coalesce at the same time. 6.5.3 Coalescing While Removing Duplicates One intuition behind coalescing is that we identify those time periods with the same SSN and PCN values that overlap or are adjacent, and merge those periods by extending the earlier period. This process is repeated until maximal periods are constructed. The nonmaximal periods are then removed. Coalescing while removing duplicates Repeat, until no rows are updated, Change a row's end date to that of the value-equivalent row that overlaps it that extends the furthest in the future. Remove those rows whose period of validity is entirely contained in that of a valueequivalent row. Remove those rows that are nonsequenced duplicates. Code Fragment 6.24 Coalesce INCUMBENTS while removing duplicates (in PSM). PROCEDURE Do_COALESCE () LANGUAGE SQL; CREATE TABLE Temp(SSN CHAR(9), PCN INT, START_DATE DATE, END_DATE DATE); INSERT INTO Temp SELECT * FROM INCUMBENTS; -- Extend rows end date BEGIN DECLARE EXIT HANDLER FOR NOT FOUND BEGIN END; 6.5 ELIMINATING DUPLICATES 163 LOOP UPDATE Temp AS T1 SET (T1.END_DATE) = (SELECT MAX(T2.END_DATE) FROM Temp AS T2 WHERE T1.SSN = T2.SSN AND T1.PCN = T2.PCN AND T1.START_DATE < T2.START_DATE AND T1.END_DATE >= T2.START_DATE AND T1.END_DATE < T2.END_DATE) -- Make sure there is at least one end date to extend the row WHERE EXISTS (SELECT * FROM Temp AS T2 WHERE T1.SSN = T2.SSN AND T1.PCN = T2.PCN AND T1.START_DATE < T2.START_DATE AND T1.END_DATE >= T2.START_DATE AND T1.END_DATE < T2.END_DATE) END LOOP; END; -- Remove wholly contained rows DELETE FROM Temp AS T1 WHERE EXISTS (SELECT * FROM Temp AS T2 WHERE T1.SSN = T2.SSN AND T1.PCN = T2.PCN AND ((T1.START_DATE > T2.START_DATE AND T1.END_DATE <= T2.END_DATE) OR (T1.START_DATE >= T2.START_DATE AND T1.END_DATE < T2.END_DATE))); CREATE TABLE Temp2 (SSN CHAR(9), PCN INT, START_DATE DATE, END_DATE DATE); INSERT INTO Temp2 SELECT DISTINCT *; FROM Temp; END; The loop maximally extends a row's end date. This loop terminates when no row is updated (the exit handler accomplishes this). To illustrate, we apply this algorithm to Table 6.5. The Temp table would initially contain the value-equivalent rows shown in Figure 6.5. After the rst iteration of the repeat-until loop, the Temp table would contain the rows shown in Figure 6.6. Note how the end time is extended when a valueequivalent row meets or overlaps it. After the second iteration, some periods are further extended (Figure 6.7). The next iteration does not change any end time, and so the repeat-until loop is terminated. The DELETE statement removes the nonmaximal value-equivalent periods, retaining only the rst one shown in Figure 6.7. 164 CHAPTER SIX : QUERYING STATE TABLES 96-1 96-6 96-4 96-10 96-4 96-10 96-10 98-1 97-12 98-1 Figure 6.5 Initial Temp table. Figure 6.6 After the rst iteration. Figure 6.7 After the second iteration. 6.5 ELIMINATING DUPLICATES 165 One problem with this approach is that it uses a PSM PROCEDURE. For a time, it was thought impossible to express this query completely in SQL. A solution was discovered independently by several people just a few years ago, involving complex, multiply nested NOT EXISTS subclauses. Coalesce entirely in SQL Select those start and end dates such that   there are no gaps between these dates, no value-equivalent row overlaps the period between the selected start and end dates and has an earlier start date or a later end date. Code Fragment 6.25 Coalesce INCUMBENTS while removing duplicates (entirely in SQL). CREATE TABLE Temp(SSN CHAR(9), PCN INT, START_DATE DATE, END_DATE DATE) INSERT INTO Temp SELECT * FROM INCUMBENTS; SELECT DISTINCT F.SSN, F.PCN, F.START_DATE, L.END_DATE FROM Temp AS F, Temp AS L WHERE F.START_DATE < L.END_DATE AND F.SSN = L.SSN AND F.PCN = L.PCN -- There are no gaps between F.END_DATE and L.START_DATE AND NOT XISTS (SELECT * FROM Temp AS M WHERE M.SSN = F.SSN AND M.PCN = F.PCN AND F.END_DATE < M.START_DATE AND M.START_DATE < L.START_DATE AND NOT EXISTS (SELECT * FROM Temp AS T1 WHERE T1.SSN = F.SSN AND T1.PCN = F.PCN AND T1.START_DATE < M.START_DATE AND M.START_DATE <= T1.END_DATE)) -- Cant be extended further continued on page 166 166 CHAPTER SIX : QUERYING STATE TABLES F L T1 M Figure 6.8 A common scenario. continued from page 165 AND NOT EXISTS (SELECT * FROM Temp AS T2 WHERE T2.SSN = F.SSN AND T2.PCN = F.PCN AND ((T2.START_DATE < F.START_DATE AND F.START_DATE <= T2.END_DATE) OR (T2.START_DATE <= L.END_DATE AND L.END_DATE < T2.END_DATE))) In this query, we search for two (possibly the same) value-equivalent rows (represented by the correlation names F, for rst, and L, for last ) dening start point F.START DATE and end point L.END DATE of a coalesced row. The rst NOT EXISTS ensures that there are no gaps between F.END Coalescing with duplicate DATE and L.START DATE (i.e., no time points where the respective removal can be done with a single (complex) SQL statement. fact does not hold). This guarantees that all start points M.START DATE between F.END DATE and L.START DATE of value-equivalent rows are extended (towards F.END DATE) by a value-equivalent row, T1. This is illustrated in Figure 6.8. In this subclause, T1 may in fact be F. It may also be the case that F itself overlaps L, in which case the NOT EXISTS is certainly true. Finally, M need not overlap L, in which case there must exist another M that does. The second NOT EXISTS ensures that only maximal periods result (i.e., F and L cannot be part of a larger value-equivalent row T2). It is instructive to compare this code fragment with CF-5.21 on page 128. In both cases, a nested NOT EXISTS is used to detect a gap in time. Yet another approach uses a COUNT aggregate in place of the nested NOT EXISTS. Code Fragment 6.26 Coalesce INCUMBENTS while removing duplicates (entirely in SQL, using COUNT). CREATE VIEW V1 (SSN, PCN, START_DATE, END_DATE) AS SELECT F.SSN, F.PCN, F.START_DATE, L.END_DATE FROM INCUMBENTS AS F, INCUMBENTS AS L, INCUMBENTS AS E WHERE F.END_DATE <= L.END_DATE AND F.SSN = L.SSN AND F.SSN = E.SSN 6.5 ELIMINATING DUPLICATES 167 AND F.PCN = L.PCN AND F.PCN = E.PCN GROUP BY F.SSN, F.PCN, F.START_DATE, L.END_DATE HAVING COUNT(CASE WHEN (E.START_DATE < F.START_DATE AND F.START_DATE <= E.END_DATE) OR (E.START_DATE <= L.END_DATE AND L.END_DATE < E.END_DATE) THEN 1 END) = 0 CREATE TABLE Temp(SSN CHAR(9), PCN INT, START_DATE DATE, END_DATE DATE) INSERT INTO Temp SELECT SSN, PCN, START_DATE, MIN(END_DATE) FROM V1 GROUP BY SSN, PCN, START_DATE The correlation names in the view denote “rst” (F), “last” (L), and “extends” (E). The view collects periods that are maximal, in that there is no row E that extends it either to the left (the rst part of the WHEN predicate) or to the right (the second part of the WHEN predicate). COUNT = 0 is equivalent to NOT EXISTS. The WHERE predicate ensures that the period is a correct one and that we only consider rows with the appropriate SSN and PCN. The INSERT command then ensures that there are no gaps within the period, by selecting the minimum end date. While this solution, at 19 lines, is somewhat shorter than CF-6.25 at 27 lines, the three-way join and the grouped aggregate may impact performance. A fourth alternative is to use SQL only to open a sorted cursor on the table. Coalesce via a cursor Retain the initial row in the cursor as the previous row . While the cursor returns a row: Output the previous row if there is a gap between it and the start of the row in the cursor. Make the row associated with the cursor the previous row. Output the previous row. Here we use Oracle's PL/SQL to express the cursor and the WHILE loop. 168 CHAPTER SIX : QUERYING STATE TABLES Code Fragment 6.27 Coalesce INCUMBENTS while removing duplicates (using a cursor in Oracle PL/SQL). CREATE TABLE Temp(SSN, PCN, START_DATE, END_DATE); DECLARE CURSOR INC_CURSOR IS SELECT * FROM INCUMBENTS ORDER BY SSN, PCN, START_DATE; StartRow PrevRow CurrRow INC_CURSOR%ROWTYPE; INC_CURSOR%ROWTYPE; INC_CURSOR%ROWTYPE; BEGIN IF NOT INC_CURSOR%ISOPEN THEN OPEN INC_CURSOR; END IF; FETCH INC_CURSOR INTO PrevRow; StartRow := PrevRow; FETCH INC_CURSOR INTO CurrRow; WHILE INC_CURSOR%FOUND LOOP IF (StartRow.SSN <> CurrRow.SSN OR StartRow.PCN <> CurrRow.PCN) OR (PrevRow.END_DATE < CurrRow.START_DATE) THEN INSERT INTO Temp VALUES (StartRow.SSN, StartRow.PCN, StartRow.START_DATE, PrevRow.END_DATE); StartRow := CurrRow; END IF; PrevRow := CurrRow; FETCH INC_CURSOR INTO CurrRow; END LOOP; INSERT INTO Temp VALUES (StartRow.SSN, StartRow.PCN, StartRow.START_DATE, PrevRow.END_DATE); CLOSE INC_CURSOR; END; 6.6 IMPLEMENTATION CONSIDERATIONS 169 This loop extracts a row from the sorted INCUMBENTS table. If this row (CurrRow) is value-equivalent with the start row and if the current row overlaps or meets the previous row, then it should be coalesced with the previous row, which is the default action. Otherwise, the coalesced row (from StartRow.START DATE to PrevRow.END DATE) is added to Temp. Because the cursor is sorted, coalescing with duplicate removal requires but a single scan of the underlying table. 6.5.4 Coalescing While Retaining Duplicates To coalesce while retaining duplicates, it is necessary to merge value-equivalent rows whose periods of validity meet. Coalescing while retaining (sequenced) duplicates turns out to be conceptually simpler, yet is more difcult to implement. As mentioned in Section 6.5.2, a table is coalesced with duplicates if it has the minimum possible number of rows, while still retaining the duplicates at each point in time. As there may be many coalesced versions of a temporal table, our task is to produce one of those versions. It should be clear that if two value-equivalent rows meet, the table is not coalesced (with duplicates) because these two rows can be merged, thereby reducing the number of rows by one. More surprising is the stronger result that a coalesced table results if all pairs of value-equivalent rows that meet (are adjacent) are merged. Coalescing while retaining duplicates requires iterating over the table several times via a cursor. Doing so efciently requires highly system-dependent approaches. As an example, the Oracle8 Server PL/SQL code is some 80 lines long. 6.6 IMPLEMENTATION CONSIDERATIONS We implemented these code fragments on several DBMSs. 6.6.1 IBM DB2 Universal Database UDB's recursive queries provide yet another way to effect coalescing with duplicate elimination. Code Fragment 6.28 Coalesce INCUMBENTS while removing duplicates, in DB2 UDB. WITH DTR (SSN, PCN, START_DATE, END_DATE) AS (SELECT SSN, PCN, START_DATE, END_DATE FROM INCUMBENTS UNION ALL SELECT I.SSN, I.PCN, I.START_DATE, J.END_DATE FROM INCUMBENTS I, DTR J continued on page 170 170 CHAPTER SIX : QUERYING STATE TABLES continued from page 169 WHERE I.SSN = J.SSN AND I.PCN = J.PCN AND ((I.START_DATE < J.START_DATE AND J.START_DATE < I.END_DATE AND I.END_DATE < J.END_DATE) OR I.END_DATE = J.START_DATE) UNION ALL SELECT I.SSN, I.PCN, I.START_DATE, J.END_DATE FROM INCUMBENTS J, DTR I WHERE I.SSN = J.SSN AND I.PCN = J.PCN AND ((I.START_DATE < J.START_DATE AND J.START_DATE < I.END_DATE AND I.END_DATE < J.END_DATE) OR I.END_DATE = J.START_DATE)) SELECT DISTINCT I.SSN, I.PCN, I.START_DATE, I.END_DATE FROM DTR I WHERE NOT EXISTS (SELECT 1 FROM DTR J WHERE I.SSN = J.SSN AND I.PCN = J.PCN AND ((J.START_DATE <= I.START_DATE AND I.END_DATE < J.END_DATE) OR (J.START_DATE < I.START_DATE AND I.END_DATE <= J.END_DATE))) So, what is going on here? The base part of the recursion is the initial SELECT. The second SELECT is the rst recursive part, the third SELECT is the second recursive part, and the nal SELECT is the main query, evaluated over the result of the recursion. The rst recursive part combines the periods of value-equivalent rows where the I row starts before the common row (from the base part, J). The second recursive part combines the periods where the I row starts after the base part. The recursion keeps extending the ending time of the base tuples until they change no more. Then the main query removes those periods that are contained in another period. The PERIOD abstract data type in IBM DB2 UDB could simplify many of the algorithms in this chapter, because the overlaps predicate can be done directly. 6.6.2 Informix–Universal Server While Informix–Universal Server does not support SQL-92's CASE expression, it does support the user-dened procedures first instant and last instant, which were shown earlier as SQL/PSM functions dened in CF-6.13. Code Fragment 6.29 Dene first instant and last instant in Informix. CREATE PROCEDURE first_instant (one DATE, two DATE) 6.6 IMPLEMENTATION CONSIDERATIONS 171 RETURNING DATE; IF one < two THEN RETURN one; ELSE RETURN two; END IF END PROCEDURE; CREATE PROCEDURE last_instant (one DATE, two DATE) RETURNING DATE IF one > two THEN RETURN one; ELSE RETURN two; END IF END PROCEDURE; A PERIOD datablade in Informix–Universal Server would simplify many algorithms in this chapter because the OVERLAPS constructor can then be done directly within the SQL statement. 6.6.3 Microsoft SQL Server Microsoft SQL Server does not support user-dened functions, so CF-6.14 and CF-6.24 are not possible. A cursor-based approach works for coalescing. Code Fragment 6.30 Coalesce INCUMBENTS while removing duplicates, in Microsoft SQL Server. CREATE TABLE Tempo (SSN CHAR(11), PCN CHAR(6), START_DATE DATETIME, END_DATE DATETIME) DECLARE Inc_Cursor CURSOR FOR SELECT * FROM INCUMBENTS ORDER BY SSN, PCN, START_DATE DECLARE DECLARE DECLARE DECLARE @S_SSN CHAR(11) @S_PCN CHAR(6) @S_START_DATE DATETIME @S_END_DATE DATETIME DECLARE DECLARE DECLARE DECLARE @P_SSN CHAR(11) @P_PCN CHAR(6) @P_START_DATE DATETIME @P_END_DATE DATETIME DECLARE @C_SSN CHAR(11) DECLARE @C_PCN CHAR(6) DECLARE @C_START_DATE DATETIME continued on page 172 172 CHAPTER SIX : QUERYING STATE TABLES continued from page 171 DECLARE @C_END_DATE DATETIME BEGIN OPEN Inc_Cursor FETCH NEXT FROM Inc_Cursor INTO @P_SSN, @P_PCN, @P_START_DATE, @P_END_DATE SELECT SELECT SELECT SELECT @S_SSN = @P_SSN @S_PCN = @P_PCN @S_START_DATE = @P_START_DATE @S_END_DATE = @P_END_DATE FETCH NEXT FROM Inc_Cursor INTO @C_SSN, @C_PCN, @C_START_DATE, @C_END_DATE WHILE (@@FETCH_STATUS <> -1) BEGIN IF ((@S_SSN <> @C_SSN OR @S_PCN <> @C_PCN) OR (@P_END_DATE < @C_START_DATE)) BEGIN INSERT INTO Tempo VALUES (@S_SSN, @S_PCN, @S_START_DATE, @P_END_DATE) SELECT @S_SSN = @C_SSN SELECT @S_PCN = @C_PCN SELECT @S_START_DATE = @C_START_DATE SELECT @S_END_DATE = @C_END_DATE END SELECT @P_SSN = @C_SSN SELECT @P_PCN = @C_PCN SELECT @P_START_DATE = @C_START_DATE SELECT @P_END_DATE = @C_END_DATE FETCH NEXT FROM Inc_Cursor INTO @C_SSN, @C_PCN, @C_START_DATE, @C_END_DATE END INSERT INTO Tempo VALUES (@S_SSN, @S_PCN, @S_START_DATE, @P_END_DATE) CLOSE Inc_Cursor END 6.7 6.6.4 SUMMARY 173 Sybase SQLServer Sybase SQLServer does not support user-dened functions within SQL statements, so CF-6.14 and CF-6.24 are not possible. 6.6.5 Oracle8 Server While Oracle8 Server does not support SQL-92's CASE expression, it does support the functions GREATEST and LEAST, which are generalizations of the last instant and first instant SQL/PSM functions dened in CF-6.13. Code Fragment 6.31 Provide the SSN and position history for all employees, using GREATEST and LEAST. SELECT S.SSN, AMOUNT, PCN, GREATEST(S.HISTORY_START_DATE, INCUMBENTS.START_DATE), LEAST(S.HISTORY_END_DATE, INCUMBENTS.END_DATE) FROM SAL_HISTORY S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN AND GREATEST(S.HISTORY_START_DATE, INCUMBENTS.START_DATE) < LEAST(S.HISTORY_END_DATE, INCUMBENTS.END_DATE) 6.6.6 UniSQL UniSQL does not provide CURRENT DATE, so the actual date must be supplied, via a parameter, in such queries as CF-6.1. 6.6.7 CD-ROM Materials The CD-ROM contains the code fragments in this chapter in IBM DB2 UDB, Microsoft Access 97 and Access 2000, Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL. 6.7 SUMMARY This chapter examined a wide variety of useful queries on valid-time state tables. We rst naturally ask, What is true now? Queries over the current state, even complex ones, can be converted to apply to temporal tables with the addition of a predicate for each correlation name, requesting the overlap with “now.” Queries over a single prior, or future, state also follow, with the overlap requested at a specied point in time. Such queries are termed time-slice queries; current queries are time-slice queries at “now.” 174 CHAPTER SIX : QUERYING STATE TABLES Sequenced queries are also natural ones. For every query over the current state, such as “list the salary and position for all employees,” an analogous sequenced query that asks for the history of that relationship can be specied, such as “provide the salary and position history for all employees” (CF-6.11). To convert a current query to a sequenced query requires decomposing that query into its underlying operations. Each operation is converted, then the query is stitched back together. Some basic operations are easy to convert: selection (no change is necessary), projection (simply include the timestamp columns in the SELECT list), sorting (no change is necessary), and union (no change is necessary). Sequenced join requires unioning four SELECT statements; sequenced difference (EXCEPT, NOT EXISTS) requires unioning four SELECT statements, each containing its own NOT EXISTS subquery. Duplicate elimination is a topic unto itself. Removing current, value-equivalent, and nonsequenced duplicates is easy. Coalescing is related to duplicate elimination, in that both reduce the number of rows by eliminating “extraneous” rows. But you can coalesce while retaining (sequenced) duplicates, or you can coalesce while removing such duplicates. Both are challenging in SQL. The cursor-based approach (CF-6.27) is preferred. Nonsequenced queries, which treat the timestamps as regular columns, are generally difcult to express in English, but relatively straightforward to express in SQL. Such queries do not have current analogs. 6.8 READINGS SQL-92 includes an unrelated COALESCE operator that is shorthand of CASE that replaces NULL values with other values [71]. SQL's stored procedures (SQL/PSM) is now an ISO standard [45] and is thoroughly described by Melton [70]. Ensor and Stevenson discuss extracting the current state in Oracle, examining both SQL and procedural variants [32]. They conclude that the biggest advantage of the procedural approach is that it can stop when the (single) qualifying row is found. Current queries were termed temporally upward compatible queries by Bair et al. [3] in their discussion of supporting legacy applications when time support was added. The notion of value equivalence was introduced by the author [86]. That paper also introduced the notion of snapshot reducibility, which relates two queries, a query qt on a temporal table and a query qs on a time-slice of that table. As an example, let qs be CF-6.17 and let qt be CF-6.18. qt is said to be snapshot-reducible to qs if the time-slice of the result of qt at a time instant i is identical to the result of qs on the time-slice of the underlying table at instant i, for all possible instants i. This is 6.8 READINGS 175 precisely the notion of a sequenced query. The sequenced EXCEPT simulates the nontemporal EXCEPT at each instant of time. The terms “sequenced” and “nonsequenced” rst appeared in a change proposal for SQL3 [92]. Coalescing was rst studied in depth by Böhlen et al. [15], though many temporal data models and temporal query languages have implicitly or explicitly assumed or provided coalescing. CF-6.25 uses an idea discovered independently by Böhlen [10] and by Rozenshtein, Abramovich, and Birger [82]. CF-6.26 uses an idea proposed by Romley [21]. The recursive query solution using DB2 UDB (CF-6.18) was suggested by Leung and Pirahesh [66]. There has been some work on implementing temporal joins within the DBMS [97]. Milton Stoneman's Easy-to-Make Wooden Sundials [99] provides ve delightful sundial designs, explaining how to construct these sundials and how to adjust the sundial to your latitude. CHAPTER 7 O V E R V I E W A major thread of this exposition is the classi- tion requires an INSERT, two UPDATEs, and cation of statements (queries, integrity con- a DELETE. Updates are more complex: a curstraints) into current, sequenced, and non- rent update is implemented as three SQL statesequenced variants. This taxonomy also bene- ments; sequenced updates require ve SQL ts modications. statements. Mentioning other temporal tables SQL has three modication statements: IN- makes things even more exciting. Finally, we SERT, DELETE, and UPDATE. Interestingly, a cur- consider the pros and cons of breaking up a rent deletion is implemented as an UPDATE valid-time table into a current portion and a followed by a DELETE, and a sequenced dele- historical portion, each a separate table. Modifying State Tables W e now turn to implementing modications to a valid-time table. We consider separately current modications (those on the current, and future, states), sequenced modications (those evaluated, conceptually at least, at each point in time), and nonsequenced modications (those explicitly mentioning the timestamp columns). We apply these modications to the INCUMBENTS table. We also examine how primary key and referential integrity constraints can be maintained across these modications. One approach, exemplied in Chapter 5, is to specify an assertion. Any violating modication results in the rollback of the transaction (assuming the assertion is immediate; see Section 5.7), thereby guaranteeing that the database remains consistent with the integrity constraint. Of course, the problem is that this is an all-or-nothing proposition: one improper modication derails the entire transaction. A second approach is to code the modication to ensure that the integrity constraint is not violated, perhaps reducing the execution time required to check the constraint. In this chapter, we rst show how to perform the modication, then consider additions that also ensure uniqueness, primary key, and referential integrity constraints remain satised. We continue with the INCUMBENTS table, repeated as Table 7.1. 7.1 CURRENT MODIFICATIONS A current modication concerns something that happens right now. A current modication concerns something that happens now and applies into the future. In a conventional, nontemporal table, all modications are current modications. 178 CHAPTER SEVEN : MODIFYING STATE TABLES Table 7.1 An excerpt from the INCUMBENTS valid-time state table. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 444332222 900225 120033 120033 137112 120033 1996-01-01 1996-06-01 1996-08-01 1996-10-01 1997-01-01 1996-06-01 1996-08-01 1996-10-01 3000-06-01 3000-01-01 In showing how integrity constraints can be ensured within the modication, we consider two cases: the general case where any modication is allowed and the restricted case where only current modications are performed on the table. The cases differentiate the data upon which the modication is performed and consider whether a noncurrent modication might have been performed in the past. Often we know a priori that only current modications are possible, which tells us something about the data we can exploit in the (current) modication now being performed. 7.1.1 Current Insertions A current insertion requires only that the start date and end date be specied. Code Fragment 7.1 Bob joins as associate director of the Computer Center. INSERT INTO INCUMBENTS VALUES (111223333, 999071, CURRENT_DATE, DATE 3000-01-01) This statement provides a timestamp from “now” to the end of time. Maintaining a sequenced primary key is easy if only the current state of the table is ever modied. Code Fragment 7.2 Bob joins as associate director of the Computer Center, ensuring the primary key, in the restricted case. INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT 111223333, 999071, CURRENT_DATE, DATE 3000-01-01 FROM DUAL WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE SSN = I2.SSN AND PCN = I2.PCN AND I2.END_DATE = DATE 3000-01-01) 7.1 CURRENT MODIFICATIONS 179 This works because all rows that are current now extend to “forever”; there are no rows that start in the future and end before “forBabylonian sundials counted the hours since sunever.” As mentioned on page 138, DUAL is rise. The Italians of the Middle Ages started a new a dummy system table provided by Oracle. day at sunset. In Germany during the Renaissance, It can be simulated in other DBMSs for use the custom was to count in Babylonic hours during here by creating a one-column table and the day and Italic hours during the night. On many inserting a single row into it. cathedrals, in particular in Strasbourg and Basel, Alternatively, a sequenced primary key sundials indicate both Italic and Babylonic hours. In in the restricted case can be stated as a prifact, with such sundials, you can determine (1) the mary key constraint, appending the END number of hours elapsed since sunrise: the BabyDATE, as exemplied in CF-5.15. lonic hour, (2) the number of hours left till sunset: This statement doesn't insert a row if the Italic hour, (3) the length of the day, by adding Bob currently has that position. An alterthe two together, (4) the day of the year, from the native approach would be to rst (current) position of the shadow at high noon, (5) the true delete his position, then perform the inhour of sunrise, from the noon line, and (6) the true sertion. Yet another approach would be to hour of sunset, also from the noon line. (current) update his position. Both options will be discussed shortly. Ensuring uniqueness requires Ensuring referential integrity in the restricted case is also a WHERE predicate, an straightforward. Only an insertion in the referencing table augmented primary key can possibly violate referential integrity. (We assume in this constraint, or a uniqueness discussion that both tables, referencing and referenced, are constraint. temporal.) Babylonic and Italic Hours Ensuring uniqueness and referential integrity in the restricted case Add this row to the table if a duplicate row is not already present (i.e., no key violation) and if there is a corresponding row in the referenced table (i.e., no foreign key violation). We use as an example the referential integrity constraint from INCUMBENTS.PCN to POSITIONS.PCN, for which an insertion into the referencing table (here, INCUMBENTS) can violate the constraint. 180 CHAPTER SEVEN : MODIFYING STATE TABLES Code Fragment 7.3 Bob joins as associate director of the Computer Center, also ensuring referential integrity, in the restricted case. INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT 111223333, 999071, CURRENT_DATE, DATE 3000-01-01 FROM POSITIONS WHERE PCN = 999071 AND END_DATE = DATE 3000-01-01 AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE SSN = I2.SSN AND PCN = I2.PCN AND I2.END_DATE = DATE 3000-01-01) If the position is valid at “forever,” it is also valid now, and so fully covers the period being inserted into INCUMBENTS. If the referential integrity would have been violated (because the position isn't current in POSITIONS), the statement inserts nothing. An alternative strategy is to ll the gap in the referenced table (where the PCN is not present in POSITIONS) with null values for the other columns, effectively dening a new position with a null JOB TITLE CODE1, so that Bob's position can be inserted into INCUMBENTS. Ensuring referential integrity with a current insertion in the restricted case requires an additional WHERE predicate. Code Fragment 7.4 Fill the gap (in the restricted case) in the POSITIONS table for the position of associate director of the Computer Center. INSERT INTO POSITIONS (PCN, JOB_TITLE_CODE1, START_DATE, END_DATE) SELECT DISTINCT 999071, NULL, CURRENT_DATE, DATE 3000-01-01 FROM DUAL WHERE NOT EXISTS ( SELECT * FROM POSITIONS WHERE PCN = 999071 AND END_DATE = DATE 3000-01-01) We need to ll the period between “now” and “forever” with this row, but only if there isn't a row already there. If the gap is Filling the gap in the referenced rst lled, then there is no need to check for referential integrity table is an easy way to ensure in the original INSERT statement (into INCUMBENTS). referential integrity for current We have thus far looked at the restricted case where only curinsertions into the referencing rent modications are allowed. Such a situation is quite comtable. mon. Envision an application that operates on a nontemporal table. Now the table is converted to retain the history, say, by adding a start and an end date column, and the modications and queries in the application are also converted. Since the application did not before concern itself with history, all the modications are current modications, on the current state. 7.1 CURRENT MODIFICATIONS 181 The Fundamental Insight The design of early sundials and water clocks reected the seemingly continuous nature of time. The gnomon's shadow traced a path across the etchings of the sundial, and the water (or sand) owed in a steady stream. Su Song's water clock, while simultaneously intricate and massive, was hobbled in its accuracy by this ow, which lacked both precision and power. The European insight, by some as yet unknown genius, was to abandon reliance on an accumulative approach, and instead focus on periodically stopping the fall of a weight that pulled a rope wound round a cylinder. In this way, the weight doesn't continue to accelerate in its descent. If the stops were timed correctly, the cylinder would rotate slowly, a revolution every hour or every day. This transition from an analog model to a digital model was every bit as invigorating to the society of the 15th century as the transition from analog electronics (i.e., vacuum tubes) to digital electronics (i.e., transistors and integrated circuits) in the 20th century. Now let's consider the more general case. In the restricted case, all modications are current modications. This implies that there are only two kinds of rows in the table: those that started in the past and ended in the past, and those that started in the past and are still valid, that is, have an END DATE of “forever.” The general case allows other kinds of modications, thereby permitting two additional kinds of rows: those that started in the past and end sometime in the future (but before “forever”), and those that start sometime in the future and end sometime in the future, including “forever.” Such rows represent planning information, or scheduled changes. These two new kinds of rows are problematic, in that they introduce gaps in the future behavior. The possibility of gaps in the future impacts the modications that are applied to the table. So, the task before us is to implement a current insertion in the general case. We rst consider ensuring solely the primary key constraints. Code Fragment 7.5 Bob was assigned the position of associate director of the Computer Center, ensuring the primary key, in the unrestricted case. INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT 111223333, 999071, CURRENT_DATE, DATE 3000-01-01 FROM DUAL WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE SSN = I2.SSN AND PCN = I2.PCN AND I2.END_DATE > CURRENT_DATE) 182 CHAPTER SEVEN : MODIFYING STATE TABLES We don't perform the insertion if doing so would violate the primary key constraint. I2 violates this constraint (in the context of the row being inserted) if its period of validity overlaps that of the inserted row. This will occur if I2 stops in the future or is currently valid, in which case the end date is “forever,” in this case the year 3000. (If “forever” was represented with a particular date in the past, such as 1860, the above predicate would not be sufcient.) We now turn our attention to the referential integrity constraint. As before, only an insertion in the referencing table can possibly violate referential integrity. In this case, a predicate must be added to the WHERE clause of the above code fragment asserting that there are no gaps in the POSITIONS table for the position code of 999071 for “now” to “forever.” This predicate is a simple modication of CF-5.21 (see also CF-7.14, below). Alternatively, the gap(s) can be lled, in which case no such predicate is required in the current insertion. In the restricted When unrestricted case, either a row was valid for the entire period from “now” to modications are possible, such “forever,” or the PCN was not valid for the entire period. In the modications may generate general case, there can be gaps, due to the possibility of perigaps that must be lled to ods starting or ending sometime in the future. Recall that COensure referential integrity. ALESCE in SQL-92 evaluates to the value of the rst argument, unless that value is NULL, in which case it evaluates to the value of the second argument, and so on. Code Fragment 7.6 Fill gaps in the POSITIONS table for the position of associate director of the Computer Center, in the general case. INSERT INTO POSITIONS SELECT 999071, NULL, END_DATE AS START_DATE, COALESCE((SELECT MIN(START_DATE) FROM POSITIONS AS P2 WHERE P2.PCN = 999071 AND P2.START_DATE > P.START_DATE), DATE 3000-01-01) AS END_DATE FROM POSITIONS AS P WHERE P.PCN = 999071 AND P.END_DATE > CURRENT_DATE AND P.END_DATE < DATE 3000-01-01 AND NOT EXISTS ( SELECT * FROM POSITIONS AS P3 WHERE P3.PCN = 999071 AND P3.START_DATE <= P.END_DATE AND P.END_DATE < P3.END_DATE) 7.1 CURRENT MODIFICATIONS 183 The start of a gap is identied where a row ends, but there is no overlapping row that extends the period of validity. The end of the gap is either the start of the rst period or, in the absence of such a period, “forever.” 7.1.2 Current Deletions Current deletions apply from “now” to “forever.” In the restricted case of only current modications being allowed on tables, a current deletion is translated into an update. Code Fragment 7.7 Bob was just red as associate director of the Computer Center (only current modications assumed). UPDATE INCUMBENTS SET END_DATE = CURRENT_DATE WHERE SSN = 111223333 AND PCN = 999071 AND END_DATE = DATE 3000-01-01 Let's say Bob was previously hired as associate director of the Computer Center on January 1, 1998. Assuming only current modications, there cannot be future appointments in the table, so the most recent appointment in the INCUMBENTS table is In the restricted case, a current deletion is converted into an update of the end date. SSN PCN START DATE END DATE 111223333 999071 1998-01-01 3000-01-01 Bob was red on March 13, 1998 (Friday!). This logical deletion updates that row to SSN PCN START DATE END DATE 111223333 999071 1998-01-01 1998-03-13 In the general case, deletions are implemented as an update and a delete. Deletion in the general case For those rows that started in the past and end in the future, reset the end date to “now.” Delete entirely those rows that start in the future. 184 CHAPTER SEVEN : MODIFYING STATE TABLES Code Fragment 7.8 Bob was just red as associate director of the Computer Center. UPDATE INCUMBENTS SET END_DATE = CURRENT_DATE WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < CURRENT_DATE AND END_DATE > CURRENT_DATE DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE >= CURRENT_DATE These two statements can be performed in either order, as they affect disjoint sets of rows. The DELETE statement eliminates those states that become true in the future. If only current modications are applied to the INCUMBENTS table, such states cannot occur, and the DELETE statement is not then necessary. Note also that in the general case, the UPDATE predicate is more complex. Ensuring the primary key constraints (specically, no duplicates) is trivial, because deletions cannot cause duplicates. There is also no problem ensuring referential integrity for the referencing table. For the referenced table (e.g., deleting a row of the POSITIONS table), a cascading current delete on the referencing table (in this case, on the INCUMBENTS table) of all rows referencing that PCN value will ensure referential integrity. In the general case, a current deletion is implemented as an update, for those currently valid periods, and a delete, for those periods starting in the future. 7.1.3 Current Updates A current update in the restricted case is implemented by an update to end the current row at “now” and an insertion of the new values. Code Fragment 7.9 An update is logically a delete coupled with an insert. (Things get complicated in the presence of triggers. In this discussion, we assume no triggers have been dened on the temporal table.) A current update changes the value for the period of validity from “now” to “forever.” A current update is the analog of a nontemporal update, such as the following: Today Bob was promoted to director of the Computer Center (nontemporal version). UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 7.1 CURRENT MODIFICATIONS 185 If only current modications are applied to INCUMBENTS, then all the affected rows extend to “forever.” We terminate the current position at “now” and insert the new position, from “now” to “forever.” Code Fragment 7.10 Today Bob was promoted to director of the Computer Center (assuming only current modications). INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT SSN, 908739, CURRENT_DATE, DATE 3000-01-01 FROM INCUMBENTS WHERE SSN = 111223333 AND END_DATE = DATE 3000-01-01 UPDATE INCUMBENTS SET END_DATE = CURRENT_DATE WHERE SSN = 111223333 AND START_DATE < CURRENT_DATE The update must occur after the insertion. Alternatively, the portion up to “now” could be inserted and the update could change the explicit column(s) and the start date to “now.” As we'll see, simple modications such as CF-7.9 transmute into a series of modications. Here, the temporal version of an update consists of two modication statements. Later we'll see a six-line nontemporal UPDATE explode into eight (!) statements and 77 lines of SQL. These statements in concert effect the desired results. Unfortunately, it is often the case that intermediate states, after some of the statements have executed but before the rest of the statements, may not satisfy stated integrity constraints. As a specic example, the sequenced primary key constraint of CF-5.8 on page 118 is violated between the INSERT and the UPDATE statements of CF-7.10. For this reason, as discussed in Section 5.7, assertion checking should be delayed to the end of the transaction, or at least until after all the modication statements implementing a temporal modication complete. Let's return to the previous example table, with the following row: SSN PCN START DATE END DATE 111223333 999071 1998-01-01 3000-01-01 186 CHAPTER SEVEN : MODIFYING STATE TABLES We promote Bob to director on Friday, March 13 (now this is his lucky day!). SSN PCN START DATE END DATE 111223333 111223333 999071 908739 1998-01-01 1998-03-13 1998-03-13 3000-01-01 If arbitrary modications are permitted on INCUMBENTS, then there may exist rows that start in the future, as well as rows that end before “forever.” For the former, only the PCN need be changed. For the latter, the END DATE must be retained on the inserted row. We emphasize that a current update has a period of applicability of “now” to “forever.” A row that starts in the future may be a planned transfer that shouldn't be impacted by the update, in which case a sequenced update, to be discussed in Section 7.2.3, with a shorter period of applicability, is more appropriate. Figure 7.1 shows the three cases. If a row's period of validity terminates in the past, then the update will not affect that row. If the row is currently valid, then the portion before “now” must be terminated at “now,” and a new row, with the updated values, inserted, with the period of validity starting at “now” and terminating when the original row did. If the row starts in the future, the row can be updated as usual. Current update in the general case Insert new information valid from “now” until the row ended. Terminate the current row at “now.” Update any rows that start in the future with the new values. Code Fragment 7.11 Today Bob was promoted to director of the Computer Center. INSERT INTO INCUMBENTS SELECT SSN, 908739, CURRENT_DATE, END_DATE FROM INCUMBENTS WHERE SSN = 111223333 AND START_DATE <= CURRENT_DATE AND END_DATE > CURRENT_DATE UPDATE INCUMBENTS SET END_DATE = CURRENT_DATE WHERE SSN = 111223333 AND START_DATE < CURRENT_DATE 7.1 CURRENT MODIFICATIONS 187 AND END_DATE > CURRENT_DATE UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 AND START_DATE > CURRENT_DATE The second UPDATE statement can appear anywhere, but the rst UPDATE statement must occur after the insertion. A current update in the general The impact of an update on a primary key constraint is best case is implemented by two judged by viewing the update as a delete followed by an insert. updates and an insertion. The delete cannot violate the constraint, but the insertion can. The approaches described in Section 7.1.1 apply to updates as well. When examining the impact of an update on a referential integrity constraint, the insertion portion of an update on the referencing table is of concern, as is the deletion portion of an update on the referenced table. Case 1 Result: (unchanged) Case 2 Result: update end date and insert new PCN Case 3 Result: update PCN Now Figure 7.1 Current update cases, with the period of validity of the row shown. 188 7.2 CHAPTER SEVEN : MODIFYING STATE TABLES SEQUENCED MODIFICATIONS A current modication applies from “now” to “forever.” A sequenced modication generalizes this to apply over a specied period, termed the period of applicability. This period could be in the past, in the future, or overlap “now.” Most of the previous material applies to sequenced modications, with CURRENT DATE replaced with the start of the period A current modication is simply a sequenced modication with a of applicability of the modication and with DATE 3000-0101 replaced with the end of the period of applicability. Here period of applicability of “now” we discuss only the signicant differences between current and to “forever.” sequenced modications, and will discuss the unrestricted case, where periods may start or end in the future. 7.2.1 Sequenced Insertions In a sequenced insertion, the application provides the period of applicability. Code Fragment 7.12 Bob was assigned the position of associate director of the Computer Center for 1997. INSERT INTO INCUMBENTS VALUES (111223333, 999071, DATE 1997-01-01, DATE 1998-01-01) Note that as usual we are using a closed-open representation for periods. To ensure a primary key, we need to look for duplicates anytime during the period of applicability. This requires a slight generalization of CF-7.5. Code Fragment 7.13 Bob was assigned the position of associate director of the Computer Center for 1997, ensuring the primary key. INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT 111223333, 999071, DATE 1997-01-01, DATE 1998-01-01 FROM DUAL WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE SSN = I2.SSN AND PCN = I2.PCN AND I2.START_DATE < DATE 1998-01-01 AND DATE 1997-01-01 < I2.END_DATE) Here we just check for overlap with the period of applicability. For preserving referential integrity, we again have two choices. We can disallow the insertion if the constraint would be violated, or we can ll the gaps before the insertion. 7.2 SEQUENCED MODIFICATIONS 189 Disallowing a violation of the constraint requires a hefty predicate, drawn from CF-5.21. Sequenced insertion ensuring uniqueness and referential integrity Insert a row if no duplicate exists during the period of applicability, and if there is a row in the referenced table at the start of the period of applicability, and if there is a row at the end of the period of applicability, and if there are no gaps during the period of applicability. Code Fragment 7.14 Bob was assigned the position of associate director of the Computer Center for 1997, also ensuring referential integrity. INSERT INTO INCUMBENTS (SSN, PCN, START_DATE, END_DATE) SELECT DISTINCT 111223333, 999071, DATE 1997-01-01, DATE 1998-01-01 FROM POSITIONS WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE SSN = I2.SSN AND PCN = I2.PCN AND I2.START_DATE < DATE 1998-01-01 AND DATE 1997-01-01 < I2.END_DATE) AND EXISTS ( SELECT * FROM POSITIONS AS P WHERE P.PCN = 999071 AND P.START_DATE <= DATE 1997-01-01 AND DATE 1997-01-01 < P.END_DATE) AND EXISTS ( SELECT * FROM POSITIONS AS P WHERE P.PCN = 999071 AND P.START_DATE < DATE 1998-01-01 AND DATE 1998-01-01 <= P.END_DATE) AND NOT EXISTS ( SELECT * FROM POSITIONS AS P WHERE P.PCN = 999071 AND DATE 1997-01-01 < P.END_DATE AND P.END_DATE < DATE 1998-01-01 AND NOT EXISTS ( SELECT * FROM POSITIONS AS P2 WHERE P2.PCN = 999071 AND P2.START_DATE <= P.END_DATE AND P.END_DATE < P2.END_DATE)) 190 CHAPTER SEVEN : MODIFYING STATE TABLES There are four components to the predicate. The rst states that there are no duplicates over the period of applicability. The second states that the new position is valid at the start of the period of applicability. The third states that the new position is valid at the end of the period of applicability. The last component (the NOT EXISTS) states that there is no gap during the period of applicability. As before, a gap exists if there is a row P that ends during the period of applicability that is not extended (towards the beginning of 1998) by another row of POSITIONS. The other approach, of lling gaps, requires modifying CF-7.6, substituting CURRENT DATE with DATE 1997-01-01 and DATE 3000-01-01 with DATE 199801-01. 7.2.2 Sequenced Deletions We start with the following nontemporal deletion: Code Fragment 7.15 Bob was removed as associate director of the Computer Center (nontemporal version). DELETE FROM INCUMBENTS WHERE SSN=111223333 AND PCN = 999071 We now wish to convert this to a sequenced deletion, over a period of applicability of the year 1997: “Bob was removed as associate director of the Computer Center for 1997.” Recall that a current deletion in the general case is implemented as an update, for the currently valid periods, and a delete, for periods starting in the future. For a sequenced deletion, there are four cases, as shown in Figure 7.2. In each case, the period of validity of the original tuple is shown above the period of applicability for the deletion. In Case 1, the original row covers the period of applicability, so both the initial and nal periods need to be retained. The initial period is retained by setting the end date to the beginning of the period of applicability; the nal period is inserted. In Case 2, only the initial portion of the period of validity of the original row is retained. Symmetrically, in Case 3, only the nal portion of the period need be retained. And in Case 4, the entire row should be deleted, as the period of applicability covers it entirely. Sequenced deletion Insert the old values from the end of the period of applicability to the end of the period of validity of the original row. Update the end date to end at the beginning of the period of applicability. Update the start date to begin at the end of the period of applicability. Delete entirely rows that are covered by the period of applicability. 7.2 SEQUENCED MODIFICATIONS 191 PV Case 1 PA Result: PV Case 2 PA Result: PV Case 3 PA Result: PV Case 4 PA Result: entire row deleted Figure 7.2 Sequenced deletion cases, with the period of validity (PV) and period of applicability (PA) shown. Code Fragment 7.16 Bob was removed as associate director of the Computer Center for 1997. INSERT INTO INCUMBENTS SELECT SSN, PCN, DATE 1998-01-01, END_DATE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1998-01-01 continued on page 192 192 CHAPTER SEVEN : MODIFYING STATE TABLES continued from page 191 UPDATE INCUMBENTS SET END_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1997-01-01 AND END_DATE >= DATE 1997-01-01 UPDATE INCUMBENTS SET START_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1998-01-01 AND END_DATE >= DATE 1998-01-01 DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE >= DATE 1997-01-01 AND END_DATE <= DATE 1998-01-01 Case 1 is reected in the rst two statements; the second statement also covers Case 2. The third statement handles Case 3, and the fourth, Case 4. As a simple example, we start with Bob having been promoted on March 13 to director: SSN PCN START DATE END DATE 111223333 111223333 999071 908739 1998-01-01 1998-03-13 1998-03-13 3000-01-01 He is given a leave of absence for the month of March 1998, which corresponds to a sequenced deletion with a period of applicability of [1998-03-01 – 1998-04-01). The result is SSN PCN START DATE END DATE 111223333 111223333 999071 908739 1998-01-01 1998-04-01 1998-03-01 3000-01-01 The rst row is handled by the rst UPDATE (Case 2), and the second row is handled by the second UPDATE (Case 3). 7.2 SEQUENCED MODIFICATIONS 193 Table 7.2 The leave of absence was for the month of April. SSN PCN START DATE END DATE 111223333 111223333 111223333 999071 908739 908739 1998-01-01 1998-03-13 1998-05-01 1998-03-13 1998-04-01 3000-01-01 Now let's consider instead that the leave of absence is the month of April. The result then is Table 7.2. This utilizes only Case 1, which is implemented as an INSERT and an UPDATE. Note that a sequenced primary key will be temporarily violated (by the INSERT statement), but will be satised after the A sequenced deletion is nal DELETE statement, which implies that the constraint should implemented by four be temporarily deferred during this modication. All four statestatements: an insertion, two ments must be evaluated in the order shown. They have been updates, and a deletion. carefully designed to cover each case exactly once. Concerning referential integrity, a sequenced deletion may introduce a gap, violating a foreign key referencing the table A sequenced deletion can on which the deletion is applied. Concerning duplicates, a deleviolate a nonsequenced uniqueness constraint. It cannot tion applied on a snapshot table cannot cause a uniqueness constraint to be violated. The same holds for a sequenced violate a current or sequenced uniqueness constraint. However, a sequenced deletion can viouniqueness constraint. late nonsequenced uniqueness because deleting the middle out of a single period results in two disconnected periods. As an example, the following table contains no nonsequenced duplicates (it does contain value-equivalent rows and sequenced duplicates, but that is not the focus here): SSN PCN START DATE END DATE 111223333 111223333 120033 120033 1998-04-01 1998-04-01 1998-06-01 1998-10-01 If a sequenced deletion with a period of applicability of June 1, 1998 through July 31, 1998, is applied, the resulting table (Table 7.3) does violate nonsequenced uniqueness! Table 7.3 June and July 1998 were deleted. SSN PCN START DATE END DATE 111223333 111223333 111223333 120033 120033 120033 1998-04-01 1998-04-01 1998-08-01 1998-06-01 1998-06-01 1998-10-01 194 7.2.3 CHAPTER SEVEN : MODIFYING STATE TABLES Sequenced Updates A sequenced update is the temporal analog of a nontemporal update, with a specied period of applicability. Let us again consider the following update: Code Fragment 7.17 Bob was promoted to director of the Computer Center (nontemporal version). UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 We now convert this to a sequenced update: Bob was promoted only for the calendar year 1997. As with sequenced deletions, there are more cases to consider for sequenced updates as compared with current updates. The A sequenced update is four cases in Figure 7.2 are handled differently in an update. In implemented by ve Case 1 of Figure 7.3, the initial and nal portions of the period statements: two insertions of validity are retained (via two insertions), and the affected porand three updates. tion is updated. In Case 2, only the initial portion is retained; in Case 3, only the nal portion is retained. In Case 4, the period of validity is retained, as it is covered by the period of applicability. Sequenced update Insert the old values from the start date to the beginning of the period of applicability. Insert the old values from the end of the period of applicability to the end date. Update the explicit columns of rows that overlap the period of applicability. Update the start date to begin at the beginning of the period of applicability of rows that overlap the period of applicability. Update the end date to end at the end of the period of applicability of rows that overlap the period of applicability. Code Fragment 7.18 Bob was promoted to director of the Computer Center for 1997. INSERT INTO INCUMBENTS SELECT SSN, PCN, START_DATE, DATE 1997-01-01 FROM INCUMBENTS WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 7.2 SEQUENCED MODIFICATIONS 195 INSERT INTO INCUMBENTS SELECT SSN, PCN, DATE 1998-01-01, END_DATE FROM INCUMBENTS WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS SET START_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS SET END_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 The rst INSERT statement handles the initial portions of Cases 1 and 2; the second handles the nal portions of Cases 2 and 3. The rst update handles the update for all four cases. The second and third updates adjust the starting (for Cases 1 and 2) and ending dates (for Cases 1 and 3) of the updated portion. Note that the last three UPDATE statements will not impact the row(s) inserted by the two INSERT statements, as the period of validity of those rows lies outside the period of applicability. Again, all ve statements must be evaluated in the order shown. Returning again to our simple example, SSN PCN START DATE END DATE 111223333 111223333 341288 908739 1998-01-01 1998-03-13 1998-03-13 3000-01-01 Bob was given a temporal assignment of PCN = 999071 for the month of March 1998. The result (Table 7.4) contains four rows. Study this result carefully to convince yourself that it is indeed what is desired. 196 CHAPTER SEVEN : MODIFYING STATE TABLES PV Case 1 PA Old value retained: Updated portion: PV Case 2 PA Old value retained: Updated portion: PV Case 3 PA Old value retained: Updated portion: PV Case 4 PA Result: entire row updated Figure 7.3 Sequenced update cases, with the period of validity (PV) and period of applicability (PA) shown. Table 7.4 Result of the sequenced update. SSN PCN START DATE END DATE 111223333 111223333 111223333 111223333 341288 999071 999071 908739 1998-01-01 1998-03-01 1998-03-13 1998-04-01 1998-03-01 1998-03-13 1998-04-01 3000-01-01 7.3 NONSEQUENCED MODIFICATIONS 197 Effecting this result requires the following changes to the original two rows: 1. Insert the rst row of the result (the rst INSERT of CF-7.18, Case 2 of Figure 7.3, old value retained). 2. Insert the fourth row of the result (the second INSERT, Case 3, old value retained). 3. Change the PCN of both of the original rows to 999071, forming new rows 2 and 3 (the rst UPDATE, Cases 2 and 3, updated portion). 4. Change the start date of the rst original row to 1998-03-01, to form the second row of the result (the second UPDATE, Case 2, old value retained). 5. Change the end date of the second original row to 1998-04-01, to form the third row of the result (the third UPDATE, Case 3, old value retained). Amazingly, this does produce the correct result, in all cases. Concerning duplicates and referential integrity, a sequenced update can again be considered to be a combination of a sequenced deletion followed by a sequenced insertion. The deletion is relevant for referenced tables (e.g., of concern if we updated the POSITIONS table); the insertion is relevant for uniqueness and for referencing tables (e.g., for an insertion we would need to check that the PCN was in the POSITIONS table). 7.3 NONSEQUENCED MODIFICATIONS As with constraints and queries, a nonsequenced modication treats the timestamps identically to the other columns. Code Fragment 7.19 Delete Bob's records that include 1997 stating that he was associate director of the Computer Center. DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE <= DATE 1997-12-31 AND DATE 1997-01-01 < END_DATE Nonsequenced modications are usually difcult to state in English because they are expressed in terms of the representation, but easier to express in SQL for the same reason. Let's compare this statement with the current variant, CF-7.8, “Bob was red as associate director of the Computer Center,” and with the sequenced variant, CF-7.16, “Bob was removed as associate director of the Computer Center for 1997.” The current and sequenced deletes mention what happened in reality because they model changes. The nonsequenced statement concerns the specic representation (deleting particular records). Conversely, the associated SQL statements for the current and sequenced variants are much more complex than that for the 198 CHAPTER SEVEN : MODIFYING STATE TABLES nonsequenced delete, for the same reason: the latter is expressed in terms of the representation. Most modications will be rst expressed as changes to the enterprise being modeled (some fact becomes true, or will be true sometime in the future; some aspect changes, now or in the future; some fact is no longer true). Such modications are either current or sequenced modiNonsequenced modications cations. Nonsequenced modications, while generally easier to are rare. express in SQL, are rare. The ramications (e.g., ensuring uniqueness and referential integrity) of a current modication impact the period from “now” to “forever”; those for sequenced modications impact the period of applicability. Since nonsequenced modications manipulate the timestamps in arbitrary ways, their impact must be judged on a case-by-case basis. Consider the following simple SQL update: Code Fragment 7.20 Extend Bob's position as associate director of the Computer Center for an additional year. UPDATE INCUMBENTS SET END_DATE = END_DATE + INTERVAL 1 YEAR WHERE SSN = 111223333 AND PCN = 999071 Note that Bob might have had this position multiple times (perhaps he went on leave or had a temporary assignment elseCorrectly implementing a where); this statement will change all such records. Unlike the nonsequenced modication in sequenced update (CF-7.18, “Bob was promoted to director of the presence of sequenced the Computer Center for 1997”), it is probable that the nonseconstraints is difcult and must be done on a case-by-case basis. quenced update just listed will result in (sequenced) duplicates (Bob having two positions at a point in time). How do we avoid such integrity violations? In this case, we would need to either augment the UPDATE statement to check for sequenced duplicates (and not do the update if one was found), or rst delete the offending duplicates before doing the update. Either way, it is not possible to give a general algorithm; the specic code depends entirely on how the modication manipulates the timestamp column(s). 7.4 MODIFICATIONS THAT MENTION OTHER TABLES* The examples given in this chapter have been simple ones, with predicates and the SET clause limited to simple equalities involving other columns in the table being modied. What if predicate or SET clause(s) involve subqueries, or mention other tables? To convert such complex modications, a combination of the techniques from this chapter and the previous chapter on queries must be applied. 7.4 7.4.1 MODIFICATIONS THAT MENTION OTHER TABLES* 199 Complex Current Modications Recall from Chapter 6 that a current query merely requires an additional predicate: START_DATE <= CURRENT_DATE AND CURRENT_DATE < END_DATE Predicates and SET clauses in a current modication that mention other temporal tables can use this same comparison. The following query assumes we don't know the PCN, but can look it up in the POSITIONS table, given the JOB TITLE CODE1, which is available from the (nontemporal) table JOB TITLES. We rst show the modication ignoring time. Code Fragment 7.21 Bob is promoted to director of the Computer Center getting the PCN from POSITIONS (nontemporal version). UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB_TITLES WHERE POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER) WHERE SSN = 111223333 The following is the current version of this modication; compare it with CF-7.11. Code Fragment 7.22 Bob is promoted to director of the Computer Center getting the PCN from POSITIONS (current version). INSERT INTO INCUMBENTS SELECT SSN, I.PCN, CURRENT_DATE, I.END_DATE FROM INCUMBENTS AS I, POSITIONS, JOB_TITLES WHERE SSN = 111223333 AND I.START_DATE <= CURRENT_DATE AND I.END_DATE > CURRENT_DATE AND POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER AND POSITIONS.START_DATE <= CURRENT_DATE AND CURRENT_DATE < POSITIONS.END_DATE UPDATE INCUMBENTS SET END_DATE = CURRENT_DATE WHERE SSN = 111223333 AND PCN <> (SELECT PCN FROM POSITIONS, JOB_TITLES WHERE POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER continued on page 200 200 CHAPTER SEVEN : MODIFYING STATE TABLES continued from page 199 AND POSITIONS.START_DATE <= CURRENT_DATE AND CURRENT_DATE < POSITIONS.END_DATE) AND INCUMBENTS.START_DATE < CURRENT_DATE AND INCUMBENTS.END_DATE > CURRENT_DATE UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB_TITLES WHERE POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER AND POSITIONS.START_DATE <= CURRENT_DATE AND CURRENT_DATE < POSITIONS.END_DATE) WHERE SSN = 111223333 AND START_DATE >= CURRENT_DATE Current modications that mention other tables require an additional overlap predicate for each correlation name. 7.4.2 Two changes were made to CF-7.11. The rst replaced the two occurrences of a PCN of 908739 with the SELECT statement that looks up this value from the POSITIONS and JOB TITLES tables. The second change added the overlap test with CURRENT DATE for the POSITIONS correlation name. No such test is required of JOB TITLES because this table doesn't record history. Complex Sequenced Modications Sections 6.3 and 6.3.1 showed how to express sequenced selection, projection, union, sorting, join, and duplicate elimination. Section 7.2 showed how to implement sequenced insertions, deletions, and updates. We now consider implementing sequenced modications that refer to other tables. Doing so requires combining these techniques. We warn you that sequenced modications over multiple time-varying tables are exceedingly knotty. That is little consolation to the application developer who is expected to produce such queries. Here we walk through the steps taking a nontemporal multitable update (at 6 lines) to its sequenced equivalent (at 76 lines!). This section can be safely skipped; you can return here when required to write such an update. If a SET or WHERE clause mentions another temporal table, the predicate in the context of a sequenced modication will be valid for the periods of validity of the relevant rows of that table. Multiple rows contribute various periods of validity, which must be accounted for. There are three periods that are involved. The rst is the period of validity contributed by the row being modied. The second is the period of applicability for the 7.4 MODIFICATIONS THAT MENTION OTHER TABLES* 201 Escapements The mechanism that periodically stops the unwinding of the clock, and thus keeps the time, is termed the “escapement.” The rst escapement, invented in the 15th century, was the verge-and-foliot, or recoil escapement. The rotating cylinder has notches or teeth on it, which push (hence the name, “recoil”) a weighted bar, the foliot, in one direction, twisting a wire. When the wire untwists, it pushes the foliot in the other direction, releasing the cylin- der (called the crown wheel) to turn until the escapement hits the next notch. Twist-untwist, ticktock. The escapement ensures that the crown only advances one unit at a time and serves to impulse the foliot, keeping the clock going. All escapements have these two tasks: regulate the advancement, and “kick” the oscillating body. A wonderous diversity of escapements has been invented over the last 600 years. modication. The third is the period of validity of the row of the table mentioned in the SET or WHERE clause. We are primarily interested in regions where these three periods intersect. Times outside the period of validity of the row being modied are obviously of no concern. The SET clause or WHERE clause is dened only for the period of validity of the mentioned table. The modication affects those times within the period of applicability. Note however that those times outside the period of applicability but within the period of validity of the modied row are still relevant, for we wish to retain the old values for the columns during these times. Hence, to convert a query mentioning other table(s) to be a sequenced query (the most useful kind), a case analysis on the interaction of these three periods is required. Figures 7.2 and 7.3 illustrated the possible ways that the period of validity of the modied row and the period of applicability can interact. To this analysis we must add the period of validity of the mentioned rows. Each type of interaction generally necessitates an insertion or update. Periods outside the period of applicability require inserts to retain the old column values. Before, there was only one period from the row being modied within the period of applicability; here, because of the other referenced tables, there may be many such periods. These periods are also inserted (for a sequenced insertion or update). The exception is the rst period within the period of applicability, which is updated (again, for a sequenced update), both of the column values, to effect the update, and the start and end timestamp columns. As an example, we convert the above nontemporal update (CF-7.21) to a sequenced update, using a period of applicability of the calendar year 1997. Doing so effectively requires a sequenced join between INCUMBENTS and POSITIONS. Here is the original, nontemporal update. 202 CHAPTER SEVEN : MODIFYING STATE TABLES INCUMBENTS Period of applicability (1997) 1 POSITIONS 2 3 Result: Insert old values Update to 1 Insert new 2 Insert new 3 Insert old values Figure 7.4 Case 1 of sequenced update, mentioning another temporal table. Code Fragment 7.23 Bob was promoted to director of the Computer Center. UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB_TITLES WHERE POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER) WHERE SSN = 111223333 As just mentioned, there are four base cases for sequenced updates (see Figure 7.3). Let's examine how the period of validity for the POSITIONS table interacts with the period of validity for INCUMBENTS and with the period of applicability. In Figure 7.4, we focus on Case 1. In this example, the PCN in POSITIONS for director of the Computer Center changes several times (from 1 to 2 to 3) over the course of 1997. This particular update will result in a single row from INCUMBENTS being replaced with ve rows. The rst and last rows will be identical to the original row except for the start and end times. The PCN column of the second row will be 1, of the third row, 2, and of the fourth row, 3, all drawn from the POSITIONS table. Since we need 7.4 MODIFICATIONS THAT MENTION OTHER TABLES* 203 to derive ve rows (in this case) from one original row, this modication will be performed via four inserts and four updates (one to update the PCN column, one to update the START DATE column, and two to update the END DATE column), a total of eight modication statements. Sequenced update mentioning another table Insert old values before period of applicability begins. Insert old values after period of applicability ends. Perform update on rst period representing the intersection of the period of validity for the row, the period of applicability, and the period of validity of the mentioned row(s). Insert new values for the remainder of the period of applicability (two subcases). Update its start date (one update) and end date (two subcases). Code Fragment 7.24 Bob was promoted to director of the Computer Center for 1997 (sequenced version). INSERT INTO INCUMBENTS SELECT SSN, PCN, DATE 1998-01-01, END_DATE FROM INCUMBENTS WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 INSERT INTO INCUMBENTS SELECT SSN, PCN, START_DATE, DATE 1997-01-01 FROM INCUMBENTS WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB_TITLES WHERE POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER AND POSITIONS.START_DATE <= DATE 1997-01-01 AND DATE 1997-01-01 < POSITIONS.END_DATE) continued on page 204 204 CHAPTER SEVEN : MODIFYING STATE TABLES continued from page 203 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1997-01-01 INSERT INTO INCUMBENTS SELECT SSN, POSITIONS.PCN, POSITIONS.START_DATE, POSITIONS.END_DATE FROM INCUMBENTS, POSITIONS, JOB_TITLES WHERE SSN = 111223333 AND INCUMBENTS.START_DATE <= DATE 1998-01-01 AND INCUMBENTS.END_DATE > DATE 1998-01-01 AND POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER AND DATE 1997-01-01 <= POSITIONS.START_DATE AND INCUMBENTS.START_DATE <= POSITIONS.START_DATE AND POSITIONS.END_DATE < DATE 1998-01-01 AND POSITIONS.END_DATE < INCUMBENTS.END_DATE INSERT INTO INCUMBENTS SELECT SSN, POSITIONS.PCN, POSITIONS.START_DATE, DATE 1998-01-01 FROM INCUMBENTS, POSITIONS, JOB_TITLES WHERE SSN = 111223333 AND INCUMBENTS.START_DATE <= DATE 1998-01-01 AND INCUMBENTS.END_DATE > DATE 1998-01-01 AND POSITIONS.JOB_TITLE_CODE1 = JOB_TITLE_CODE AND JOB_TITLE = DIRECTOR, COMPUTER CENTER AND DATE 1997-01-01 <= POSITIONS.START_DATE AND DATE 1998-01-01 < POSITIONS.END_DATE UPDATE INCUMBENTS SET START_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS SET END_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 AND NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 7.4 MODIFICATIONS THAT MENTION OTHER TABLES* WHERE AND AND AND 205 INCUMBENTS.SSN = I2.SSN INCUMBENTS.PCN = I2.PCN INCUMBENTS.START_DATE < I2.END_DATE I2.START_DATE < INCUMBENTS.END_DATE) UPDATE INCUMBENTS SET END_DATE = (SELECT MIN(I2.START_DATE) FROM INCUMBENTS AS I2 WHERE INCUMBENTS.SSN = I2.SSN AND INCUMBENTS.PCN <> I2.PCN AND INCUMBENTS.START_DATE < I2.START_DATE) WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 AND EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE INCUMBENTS.SSN = I2.SSN AND INCUMBENTS.PCN <> I2.PCN AND INCUMBENTS.START_DATE < I2.END_DATE AND I2.START_DATE < INCUMBENTS.END_DATE) In comparison with the original sequenced version (CF-7.18), we added here mention of the POSITIONS and JOB TITLES tables, impacting only the latter three UPDATE statements of the original version. Since POSITIONS is time-varying, we are really doing a sequenced join between that table and the table being updated, INCUMBENTS. The rst INSERT statement handles the initial portion (the rst row in Figure 7.4); the second handles the nal portion (the last row in the gure). The rst update changes the PCN to the value found in the POSITIONS table valid at the beginning of the period of applicability (1997). The following two insertions add intermediate periods during the period of applicability, the former from row(s) of the POSITIONS table that end before the end of applicability, the latter from rows that end after the period of applicability. The following three updates adjust the starting and ending dates of the initial portion with the new PCN value. This case analysis identies for which periods the old values should be inserted, for which periods the new values should be inserted, and for which single period the columns should be updated to the new values, with the start and end times changed. We illustrated the most complex case, that of update; deletion is simpler, and insertion simpler still. 206 7.5 CHAPTER SEVEN : MODIFYING STATE TABLES TEMPORAL PARTITIONING* As discussed on page 120, the value 3000-01-01 (“forever”) is used in INCUMBENTS.END DATE to represent currently valid data, Sequenced updates referring to that is, data valid until “now.” What we really desire is to store other tables are complex to CURRENT DATE as the column value. Unfortunately, neither convert into SQL. SQL nor any extant DBMS allows this because the value has the habit of changing once each day. While quite inconvenient for the DBMS vendor, this property is what the user wants. Bob's position could change tomorrow, but at least we know that the position recorded in the database is valid today. As an aside, using CURRENT DATE is close, but is not entirely accurate. The UIS is updated every night with the previous day's value. So what we really want to model is that we know Bob's position up to yesterday; it could change today, in which case we would hear about the change tomorrow. So what is really needed is the now-relative value CURRENT DATE - INTERVAL 1 DAY, which is also not supported as a column value by DBMSs. Since we can't store the value we want, we come at the problem a different way. By using temporal partitioning , we can avoid Temporal partitioning nesses the limitation of CURRENT DATE the necessity of storing an end time of “now.” We partition INCUMBENTS into two tables, INCUMBENTS CURRENT and INCUMnot being permitted as column BENTS PAST. The latter table, termed the history store, contains values by splitting a valid-time no current information; hence, the END DATE is always a specic, table into a current store known date. In the former table, termed the current store, we containing only current have no need for that column, so we omit it. The START DATE information and a history store. is still present in the INCUMBENTS CURRENT table, as we need to know when the current information became valid. These two tables are not as expressive as the original INCUMBENTS table: they cannot record future data. Say Bob receives a promotion postactively, that is, to go into effect at some future time. Postactive promotions are common in universities; many are announced in late spring, to go into effect at the beginning of the following scal year (which for the University of Arizona is July 1). Bob's new position could be recorded in INCUMBENTS, with a START DATE of July 1. Such data cannot be stored in INCUMBENTS PAST, nor is such data appropriate for INCUMBENTS CURRENT because the position is not yet current. 7.5.1 Queries If temporal partitioning is used, current queries are simpler: just apply the query to the current store. 7.5 Code Fragment 7.25 TEMPORAL PARTITIONING* 207 What is Bob's current position? SELECT JOB_TITLE_CODE1 FROM EMPLOYEES, INCUMBENTS_CURRENT, POSITIONS WHERE FIRST_NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS_CURRENT.SSN AND INCUMBENTS_CURRENT.PCN = POSITIONS.PCN The disadvantage of temporal partitioning, as we will see below, is that queries over the history must reference both tables. However, sometimes the data is naturally partitioned at the source of that data. Recall that while SAL HISTORY (see page 116) contains the salary history, the EMPLOYCurrent queries are simplied EES table contains the current salary, as well as the PAY CHANGE when applied to a partitioned DATE. An important design issue, which we'll just mention now, valid-time table. is whether to replicate current information in the past table. While all of these approaches are similar in length (around 30 lines of SQL code), the query becomes much more complex when temporal partitioning is used on one or both of the underlying tables. If the INCUMBENTS table is partitioned into INCUMBENTS PAST and INCUMBENTS CURRENT, then the temporal join mushrooms to a 50-line query. Code Fragment 7.26 Provide the salary and department history for all employees. ( Insert CF-6.11 from page 151, substituting INCUMBENTS PAST for INCUMBENTS) UNION SELECT S.SSN, AMOUNT, PCN, S.HISTORY START DATE, S.HISTORY END DATE FROM SAL HISTORY AS S, INCUMBENTS CURRENT AS I WHERE S.SSN = I.SSN AND I.START DATE <= S.HISTORY START DATE UNION SELECT S.SSN, AMOUNT, PCN, I.START DATE, S.HISTORY END DATE FROM SAL HISTORY AS S, INCUMBENTS CURRENT AS I WHERE S.SSN = I.SSN AND I.START DATE > S.HISTORY START DATE AND S.HISTORY. END DATE <= DATE 3000-01-01 AND I.START DATE < S.HISTORY END DATE UNION SELECT S.SSN, AMOUNT, PCN, I.START DATE, S.HISTORY END DATE FROM SAL HISTORY AS S, INCUMBENTS CURRENT AS I WHERE S.SSN = I.SSN AND I.START DATE > S.HISTORY START DATE AND DATE 3000-01-01 < S.HISTORY END DATE 208 CHAPTER SEVEN : MODIFYING STATE TABLES If the history store does not include current data, then sequenced and nonsequenced queries are more complex. Otherwise, such data must be replicated across both tables. 7.5.2 There are two major changes made to CF-6.11 to produce the portion here. INCUMBENTS.END DATE is replaced with DATE 300001-01. With this substitution, the second case in the original doesn't apply to INCUMBENTS CURRENT, and so is omitted. If the INCUMBENTS PAST also includes the current data, then CF-6.11 with INCUMBENTS PAST substituted for INCUMBENTS sufces. This approach favors query simplicity, at the expense of modication complexity, as will now be shown. Modications Current inserts into partitioned tables are even easier. Code Fragment 7.27 Bob was assigned the position of associate director of the Computer Center (partitioned). INSERT INTO INCUMBENTS_CURRENT VALUES (111223333, 6201945234, CURRENT_DATE) Here we only have to record when the fact became valid. We assume in this code fragment that duplicates were allowed. If duplicates are not allowed, then there are two choices. One approach is to dene a constraint or assertion disallowing duplicates, which will then prevent duplicates from being inserted. This works ne for current and nonsequenced duplicates, as well as for value-equivalent duplicates. For sequenced duplicates (where no duplicates are allowed at each point in time), using a constraint, such as that shown in CF-5.14, is overkill because a duplicate present at any instant will prevent the insertion at all instants. The second approach is to extend the above INSERT statements to insert facts only if there is no duplicate. For current Current insertions only impact the current store of a partitioned and nonsequenced duplicates, this is easy. For sequenced duplicates, where duplicates must be avoided at each point in time, table. ensuring this is easy for the partitioned table. If there is a valueequivalent row in the INCUMBENTS CURRENT, then the period of validity of that row wholly contains the row to be inserted, and the entire insertion should not take place. Code Fragment 7.28 Bob was assigned the position of associate director of the Computer Center (partitioned, avoiding sequenced duplicates). INSERT INTO INCUMBENTS_CURRENT VALUES (111223333, 6201945234, CURRENT_DATE) WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS_CURRENT AS I2 WHERE I2.SSN = 111223333 AND I2.PCN = 6201945234) 7.5 TEMPORAL PARTITIONING* 209 Similarly, current deletions move a row from the current store to the history store. Code Fragment 7.29 Bob was red as associate director of the Computer Center (partitioned). INSERT INTO INCUMBENTS_PAST (SSN, PCN, START_DATE, END_DATE) SELECT SSN, PCN, START_DATE, CURRENT_DATE FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND PCN = 999071 DELETE FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND PCN = 999071 This is slightly shorter than the nonpartitioned current deletion (CF-7.8). Similarly, a current update is logically a current delete coupled with a current insert. Sequenced modications over a partitioned table must consider both stores. For sequenced insertions, there are two cases: (1) the period of applicability lies entirely in the past, in which case the row is inserted into the history store, or (2) the period of applicability includes now, in which case the row is inserted into the current store. For sequenced deletions, recall that a partitioned store cannot record future data, so the period of applicability must either end before now or extend to “forever.” In the rst situation, only the history store is modied, as described in Section 7.2.2. The second situation involves changes to the history store and to the current store. Revisiting Figure 7.2 on page 191, all four cases are relevant for the period of validity for rows in both the current and history stores. The insertion, two updates, and the deletion of CF-7.16 apply as is to INCUMBENTS PAST. For the current store, these cases result in a somewhat different set of statements. Code Fragment 7.30 Bob was removed as associate director of the Computer Center for 1997 (partitioned). INSERT INTO INCUMBENTS_PAST SELECT SSN, PCN, DATE 1998-01-01, END_DATE FROM INCUMBENTS_PAST WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE <= DATE 1997-01-01 AND END_DATE > DATE 1998-01-01 continued on page 210 210 CHAPTER SEVEN : MODIFYING STATE TABLES continued from page 209 UPDATE INCUMBENTS_PAST SET END_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1997-01-01 AND END_DATE >= DATE 1997-01-01 UPDATE INCUMBENTS_PAST SET START_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1998-01-01 AND END_DATE >= DATE 1998-01-01 DELETE FROM INCUMBENTS_PAST WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE >= DATE 1997-01-01 AND END_DATE <= DATE 1998-01-01 UPDATE INCUMBENTS_CURRENT SET START_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE <= DATE 1998-01-01 INSERT INTO INCUMBENTS_PAST SELECT SSN, PCN, START_DATE, DATE 1997-01-01 FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1997-01-01 UPDATE INCUMBENTS_CURRENT SET START_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE < DATE 1998-01-01 DELETE FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND PCN = 999071 AND START_DATE >= DATE 1997-01-01 7.5 TEMPORAL PARTITIONING* 211 The situation is similar for sequenced updates. The history store is updated identically to the nonpartitioned validSequenced updates are tedious time state table (copying the ve modication statements from due to the extensive case analysis required for the current CF-7.18). Updating the current store requires some changes to these statements, yielding another six modication statements and history stores separately. (whew!). These are best understood by examining Figure 7.3 and considering what changes to the partitioned store are required in each case. Code Fragment 7.31 Bob was promoted to director of the Computer Center for 1997 (partitioned). INSERT INTO INCUMBENTS_PAST SELECT SSN, PCN, START_DATE, DATE 1997-01-01 FROM INCUMBENTS_PAST WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 INSERT INTO INCUMBENTS_PAST SELECT SSN, PCN, DATE 1998-01-01, END_DATE FROM INCUMBENTS_PAST WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 UPDATE INCUMBENTS_PAST SET PCN = 908739 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS_PAST SET START_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS_PAST SET END_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1998-01-01 continued on page 212 212 CHAPTER SEVEN : MODIFYING STATE TABLES continued from page 211 -- Now handle changes to INCUMBENTS_CURRENT INSERT INTO INCUMBENTS_PAST SELECT SSN, PCN, START_DATE, DATE 1997-01-01 FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 INSERT INTO INCUMBENTS_PAST SELECT SSN, 908739, DATE 1997-01-01, DATE 1998-01-01 FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 AND DATE 1998-01-01 < CURRENT_DATE INSERT INTO INCUMBENTS_PAST SELECT SSN, 908739, START_DATE, DATE 1998-01-01 FROM INCUMBENTS_CURRENT WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND DATE 1998-01-01 < CURRENT_DATE UPDATE INCUMBENTS_PAST SET PCN = 908739 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 AND END_DATE > DATE 1997-01-01 UPDATE INCUMBENTS_CURRENT SET START_DATE = DATE 1998-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1998-01-01 UPDATE INCUMBENTS_CURRENT SET START_DATE = DATE 1997-01-01 WHERE SSN = 111223333 AND START_DATE < DATE 1997-01-01 As with the nonpartitioned store, nonsequenced modications are easy to express in SQL and difcult to express in English because they are so intimately coupled with the implementation. 7.6 7.6 IMPLEMENTATION CONSIDERATIONS 213 IMPLEMENTATION CONSIDERATIONS As before, the code fragments were implemented on several systems. 7.6.1 IBM DB2 Universal Database All of the code fragments compile without error in IBM DB2 UDB. The DUAL table in CF-7.2 can be replaced with a WITH TEMP construct. Code Fragment 7.32 Bob was assigned the position of associate director of the Computer Center, ensuring the primary key, in DB2 UDB. INSERT INTO INCUMBENTS WITH TEMP(SSN, PCN, START_DATE, END_DATE) AS (VALUES (111223333, 999071, CURRENT DATE, 3000-01-01)) SELECT * FROM TEMP AS T WHERE (NOT EXISTS ( SELECT * FROM INCUMBENTS AS I2 WHERE T.SSN = I2.SSN AND T.PCN = I2.PCN AND I2.END_DATE = 3000-01-01)) 7.6.2 Microsoft Access CF-7.6 (ll gaps in the POSITIONS table) cannot be done in Microsoft Access 97 or Access 2000 because these DBMSs do not support the COALESCE operator. 7.6.3 Microsoft SQL Server All of the code fragments compile without error in Microsoft SQL Server. 7.6.4 Oracle8 Server CF-7.6 causes difculties with Oracle8 Server, as it doesn't allow SELECT statements in the target list of an outer SELECT statement. This code fragment can be converted to the following PL/SQL code: 214 CHAPTER SEVEN : MODIFYING STATE TABLES Code Fragment 7.33 Fill gaps in the POSITIONS table for the position of associate director of the Computer Center, in the general case, in Oracle. CURSOR gaps(pcn2 varchar2) IS SELECT END_DATE FROM POSITIONS p2 WHERE p2.PCN = pcn2 AND p2.END_DATE > SYSDATE AND p2.END_DATE < TO_DATE(3000-01-01,YYYY-MM-DD) AND NOT EXISTS ( SELECT * FROM POSITIONS p3 WHERE p3.PCN = pcn2 AND p3.START_DATE <= p2.END_DATE AND p2.END_DATE < p3.END_DATE ); new_start_date DATE; new_end_date DATE; BEGIN OPEN gaps(in_pcn); LOOP BEGIN FETCH gaps INTO new_start_date; EXIT WHEN gaps%NOTFOUND; SELECT NVL(MIN(p2.START_DATE),TO_DATE(3000-01-01,YYYY-MM-DD)) INTO new_end_date FROM POSITIONS p2 WHERE p2.PCN = in_pcn AND p2.START_DATE > new_start_date; INSERT INTO POSITIONS ( pcn, JOB_TITLE_CODE1, START_DATE, END_DATE ) VALUES (in_pcn, NULL, new_start_date, new_end_date ); END; END LOOP; CLOSE gaps; END; The cursor is the WHERE clause of the original INSERT statement. The WHERE clause in the nested select inside the original COALESCE expression is implemented here as a select on the rows returned by the cursor, with COALESCE implemented with NVL. The insert is then performed. 7.7 7.6.5 SUMMARY 215 UniSQL CF-7.6 causes slight difculties with UniSQL, because COALESCE cannot take a SELECT statement as an argument. Also, as UniSQL does not support CURRENT DATE, we use today's date instead. Code Fragment 7.34 Fill gaps in the POSITIONS table for the position of associate director of the Computer Center, in the general case, in UniSQL. INSERT INTO POSITIONS SELECT 999071, NULL, END_DATE, (SELECT COALESCE(MIN(START_DATE), DATE 01/01/3000) FROM POSITIONS AS P2 WHERE P2.PCN = 999071 AND P2.START_DATE > P.START_DATE) FROM POSITIONS AS P2 WHERE P2.PCN = 999071 AND P2.END_DATE > DATE 1/16/1998 AND P2.END_DATE < DATE 01/01/3000 AND NOT EXISTS ( SELECT * FROM POSITIONS AS P3 WHERE P3.PCN = 999071 AND P3.START_DATE <= P2.END_DATE AND P2.END_DATE < P3.END_DATE) 7.6.6 CD-ROM Materials The CD-ROM contains the code fragments in this chapter in IBM DB2 UDB, Microsoft Access 97, Microsoft SQL Server, Sybase SQLServer, Oracle8 Server, and UniSQL. 7.7 SUMMARY We have examined how to convert various nontemporal modications into current and sequenced modications. Insertions are not too troublesome. Additional predicates are required to ensure sequenced uniqueness and referential integrity. Alternatively, gaps can be lled in the referenced table, which is analogous to adding the key values in the nontemporal case. Nontemporal deletions and updates are mapped into a series of SQL statements. Current modications can be viewed as sequenced modications with a period of applicability from “now” to “forever.” The portion of each row's period of validity that is outside the period of applicability must be retained. Often this involves inserting new rows. Deleting a short period from the middle of a row will result 216 CHAPTER SEVEN : MODIFYING STATE TABLES in two remaining rows; updating such a period will result in an initial unchanged row, an updated row, and a nal unchanged row. Keeping all the cases straight requires a sophisticated dance between as many as ve statements for a simple update (CF-7.18). In showing how integrity constraints can be ensured within the modication, we considered for each current modication two cases: the general case, where any modication is allowed on the underlying table, and the restricted case, where only current modications are ever performed on the table. The restricted case is interesting because it mirrors the behavior of a nontemporal table. After a series of current modicaThe modications found in nontemporal applications are all tions, the current state of the temporal table (the rows that are valid at “now”) will be identical to a nontemporal table upon current modications. which the same series of modications had been applied. Many applications initially have no temporal component. The need for retaining the history then arises. To extend such an application, the rst step is to make one or more of the tables temporal, generally by adding a period timestamp (e.g., start date and end date columns). Then the modications, which are all current modications, are converted to manipulate these new columns. This chapter explained this conversion process in detail. Later, such applications are extended to allow storage and changing of future information. Such modications are more general than current modications. When these modications are permitted to the temporal tables, the current modications in the original application must be converted to cover the general case. If the modication mentions other tables, the interaction between the period of validity of the row undergoing modication, the period of applicability of the modication, and the period(s) of validity of the mentioned table(s) must be taken into consideration when translating the modication. Temporal partitioning nesses the problem of storing currently valid data by separating this data from old data, storing the former in a table known as the current store and the latter in a table known as the history store. Some queries and updates are simplied under this arrangement; others are lengthened. 7.8 READINGS Most temporal database research has focused on queries; modication is often handled as an afterthought. Some proposals for temporal query languages have considered extended modication statements: HSQL [84], TQuel [86, 87], and TRM [5]. Implementing modication of temporal tables has received no attention. In fact, Tansel's book [102] has a 170-page part on implementation, with nary a word on modications. 7.8 READINGS 217 Myrach et al. [72] discuss how to ensure keys and referential integrity using the constructs of the TSQL2 temporal query language [91]. A later paper [4] provides various mechanisms for ensuring sequenced referential integrity in an extended relational model. Ahn's work with the author is perhaps the most thorough investigation of temporal partitioning [1]. Clifford et al. propose storing now-relative values (such as CURRENT DATE - INTERVAL 1 DAY) in the database [23]. As discussed in Section 5.7, each transaction containing a modication should reset the mode of temporal assertions to deferred, say, with SET CONSTRAINTS ALL DEFERRED. David Landes argues persuasively that a digital perception of time, encouraged by the stepwise movement of the clock hand in the town's clock tower and the subsequent need for skilled craftsmen who could assemble these clockworks, was one of the major advances that “turned Europe from a weak, peripheral, highly vulnerable outpost of Mediterranean civilization into a hegemonic aggressor. Time measurement was at once a sign of new-found creativity and an agent and catalyst in the use of knowledge for wealth and power” [65, p. 12]. CHAPTER 8 O V E R V I E W A tracking log captures the sequence of mod- the modication occurred) and sometimes an ications that have been applied to a single operation code (insert, delete, update) and a table, the table being tracked. The tracking log transaction identier. Triggers can be used to allows the monitored table to be reconstructed maintain the tracking log, without necessitatas of any time in the past. This feature can be ing changes to the application code. A tracking used to undo inadvertent modications or to log can contain before-images (the row before restore the table to a previous, consistent state. the indicated change occurred), after-images, Of course, the tracking log can also be used in or a combination of both. informal or formal audit procedures. The different organizations of the tracking Different organizations of the tracking log log are coupled with various reconstruction alresult from the varying assumptions and con- gorithms. Achieving fully accurate transaction straints on the monitored table. The schema semantics for the reconstructed table turns out of the tracking log comprises the columns of to be surprisingly difcult; various restrictions the monitored table, along with a timestamp on how the monitored trail is modied can simcolumn (a single datetime specifying when plify the reconstruction algorithm dramatically. Retaining a Tracking Log N igel Corbin, a Welshman who speaks the King's English with a clipped precision underscoring his doctorate in theoretical physics, provides technical support for Schlumberger's GeoQuest division. In April 1996, we talked in Jakarta, at a meeting of F INDER support personnel who had own in from Schlumberger's wide-ung ofces: Perth, Kuala Lumpur, Mexico City. Looking out from GeoQuest's 16th-oor ofces in the “Golden Triangle” of this sprawling Indonesian capital of approximately 10 million people, the eye encounters ofce buildings, ve-star hotels, and foreign embassies in every direction, emphasizing the explosive growth over the past two decades and obscuring the crushing poverty still found in other parts of the city. A year later, the then-unthinkable would occur: Suharto resigned, and a massive economic and social upheaval commenced. Nigel is based on the other side of the world, in Gatwick, near London. Actually, his ofce is at the Gatwick airport, which presented challenges to the building's architect. The windows have 6 inches of double-paned glass, to acoustically isolate the inhabitants from the shrill whine of departing jet planes. An enclosing wire mesh absorbs the microwave emissions from the airport radar, which otherwise would impart a vague warmth on each sweep. There are no architectural solutions for near encounters of planes that occasionally make tight turnarounds for emergency landings due to equipment malfunction, the closest thus far being a miniscule 1 meter. When we met, Nigel had other concerns. One of his clients called him to report that all of the North Sea wells had been relocated to the Pacic Ocean. This was quite disturbing news! Nigel rushed to the customer site and veried that the wells were indeed showing up in the wrong location on the digitized maps generated by F INDER. Upon further investigation, Nigel determined that the wells' coordinates were ne, but that these coordinates were being interpreted using the incorrect units. F INDER includes a PROJECTIONS table, containing the columns PROJECTION ID (the primary key), PROJECTION NAME, PROJECTION TYPE (an integer between 0 and 20), SPHEROID CODE (the U.S. Geologic Survey (USGS) spheroid code, an integer 220 CHAPTER EIGHT : RETAINING A TRACKING LOG between 0 and 18), PROJECTION UOM (the spheroid units, an integer between 0 and 5), and ZONE CODE (the USGS zone code, a number between 0 and 5400). Someone had (perhaps inadvertently) changed one of the codes for the projection used by the North Sea wells, by executing an ill-advised update on this table. Finding the incorrect column value was tedious. While this table is small, containing several tens of rows, it took Nigel the better part of the morning to reconstruct the table's correct contents. With this problem xed, Nigel then considered the more basic issue: what specic changes had been made to this table, and why? One option would be to revise the permissions on this table to disallow updates on the table, thereby ensuring that the table remained consistent. However, this alternative was unacceptable to the client, as there were valid situations in which one or more rows would need to be changed. Nigel decided that a tracking log for this table would be desirable, should the circumstances recur. 8.1 DEFINING THE TRACKING LOG A tracking log species the sequence of modications to a single table, the monitored table. The tracking log records the fact that a modication had been applied, as well as the data involved in the modication. Usually it contains additional information about the change, such as when A tracking log retains the past the modication occurred, or who performed it, or which task states of a table without or transaction effected the change. The tracking log permits the impacting the monitored table. contents of the monitored table to be reconstructed as of any time As differentiated from a in the past. valid-time table, which models A tracking log differs from the valid-time tables discussed in the state of the enterprise over previous chapters. Those tables modeled the state of the entertime, a tracking log captures the prise over time. In contrast, a tracking log captures the state of state of the monitored table the modied table itself over time. itself over time. We rst dene a new table, P Log, which will contain the tracking log for the PROJECTIONS table. Code Fragment 8.1 Create the tracking log table. CREATE TABLE P_Log ( PROJECTION_ID INT, PROJECTION_NAME CHAR(10), PROJECTION_TYPE INT, SPHEROID_CODE INT, PROJECTION_UOM INT, ZONE_CODE INT, When_Changed DATE, PRIMARY KEY (PROJECTION_ID, When_Changed)) 8.1 DEFINING THE TRACKING LOG 221 All but the nal column are from the PROJECTIONS table. The When Changed column indicates the date on which the values in the row were removed or changed in the PROJECTIONS table. Hence, these are the old values; the current values can be found in the monitored table. In fact, the value of the When Changed column can never exceed “now.” That When Changed is of type DATE implies that each specic projection will be updated at most once per day (we will relax this assumption later). Recall from Section 5.3 that the (sequenced) primary key of a valid-time table cannot be composed from its columns; an asserThe schema of a tracking log tion is required. Such is not the case here. The key of the trackcomprises the columns of the ing log is simply the key of the monitored table (PROJECTION monitored table, along with a ID) along with the When Changed column. The reason for this is single timestamp column. Its that the primary key constraint on the monitored table implies key is simply the primary key of a current key constraint on the tracking log. Since only current the monitored table and the modications (in fact, current insertions) are applied to the log, timestamp column. a current key constraint becomes a sequenced key constraint. A tracking log can also contain auxiliary columns, such as Who Changed, that provide additional information on the transaction that is updating the monitored table. However, if triggers are used to maintain the tracking log, those triggers must have access to this auxiliary information. SQL-92's SYSTEM USER is helpful here; other, application-dependent information is harder to make available to the trigger. As an aside, we saw in Chapter 5 that the ZPSOS COMPENSATION HISTORY table included a CHRONOLOGY KEY column, which is effectively a transaction timestamp. That table contained both the current information and the tracking log. The benet of a separate P Log table is that the PROJECTIONS table remains as before, and all the code that uses that table still works as before. F INDER is a large, complex system. If Nigel had to examine all of the code that accessed this table, this additional work would probably have convinced him to abandon adding the tracking log in the rst place. However, the code that modies the PROJECTIONS table is still of concern. We wish to also retain that code as is. This can be done by maintaining the P Log table via triggers, working behind the scenes. We dene two triggers, one each for DELETE and UPDATE, on the monitored table. Code Fragment 8.2 Triggers for maintaining the P Log table. CREATE TRIGGER Delete_PROJECTIONS AFTER DELETE ON PROJECTIONS FOR EACH ROW INSERT INTO P_Log VALUES (OLD.PROJECTION_ID, OLD.PROJECTION_NAME, continued on page 222 222 CHAPTER EIGHT : RETAINING A TRACKING LOG continued from page 221 OLD.PROJECTION_TYPE, OLD.SPHEROID_CODE, OLD.PROJECTION_UOM, OLD.ZONE_CODE, CURRENT_DATE) CREATE TRIGGER Update_PROJECTIONS AFTER UPDATE ON PROJECTIONS FOR EACH ROW INSERT INTO P_Log VALUES (OLD.PROJECTION_ID, OLD.PROJECTION_NAME, OLD.PROJECTION_TYPE, OLD.SPHEROID_CODE, OLD.PROJECTION_UOM, OLD.ZONE_CODE, CURRENT_DATE) In both cases, the values stored in the tracking log table are the old values. In the case of update, the new values may be found in the PROJECTIONS table. The value of the When Changed column is “now.” Again, Triggers allow the tracking log to be maintained automatically, we assume that only one modication is applied each day. Since inserted values can also be found in the monitored table, there is without necessitating changes no need for an INSERT trigger (we also return to this assumption to the application code. later in this chapter). These triggers assume that no other modications are made to the P Log table, other than through the INSERT, DELETE, and UPDATE statements. If triggers were already present on the PROJECTIONS table, and if the DBMS allowed only one trigger per operation per table, then the existing triggers would need to be merged with those dened above. With this organization, Nigel can condently install the tracking log with a simple table denition and two trigger denitions. No existing code is impacted. The tracking log is maintained entirely as a side effect of modications to the monitored table. 8.2 QUERIES Assume that the following transactions have been executed on the PROJECTIONS table (here we show the values of only the table's key column and one additional column). 1. Insert projection 1 with a type of 12 on January 1, 1996. 2. Insert projection 2 with a type of 10 on January 1, 1996. 8.2 QUERIES 223 Table 8.1 The PROJECTIONS table. PROJECTION ID PROJECTION TYPE 1 2 3 12 14 11 Table 8.2 The P Log table. PROJECTION ID PROJECTION TYPE When Changed 5 2 3 2 4 18 10 15 13 17 1996-02-03 1996-03-20 1996-05-28 1996-06-17 1996-07-12 3. 4. 5. 6. 7. 8. 9. 10. Insert projection 3 with a type of 15 on January 1, 1996. Insert projection 4 with a type of 17 on January 1, 1996. Insert projection 5 with a type of 18 on January 1, 1996. Delete projection 5 on February 3, 1996. Update projection 2 to a type of 13 on March 20, 1996. Update projection 3 to a type of 11 on May 28, 1996. Update projection 2 with a type of 14 on June 17, 1996. Delete projection 4 on July 12, 1996. After these transactions have executed, the current contents of the PROJECTIONS table are shown in Table 8.1. The contents of the P Log table are shown in Table 8.2. Note that Table 8.2 will be ordered on When Changed: each trigger adds a new row to the table with a When Changed time greater than all existing values. Note also that the tracking log is append-only; no rows are ever updated or deleted. Finally, observe that the tracking log can contain multiple rows for a particular PROJECTION ID if that value was updated several times. We rst consider extracting prior states, then examine other kinds of queries. 8.2.1 Extracting a Prior State Extracting a prior state involves looking at both the monitored table and the tracking log. The tracking log table allows us to reconstruct the state of the PROJECTIONS table at any day in the past. We wish to reconstruct the table as of April 1, 1996, that is, to see the table as it existed between transactions 7 and 8. Projection 1 was never modied (it does not appear in the tracking log), so the value in 224 CHAPTER EIGHT : RETAINING A TRACKING LOG Circadian Clocks Across the evening sky All the birds are leaving But how can they know It's time for them to go . . . . . . . . . . So come the storms of winter And then the birds in spring again —Sandy Denny, “Who Knows Where the Time Goes” Barbara Kingsolver, in her book High Tide in , realizes that her pet crab is still responding to the tidal cycle of the California coast from where it was taken, several hundred miles to the west. The crab would become active only at certain times, even though there was no longer any environmental stimuli to indicate the tides. Tidal rhythms are common in many animals living in tide-washed coastlines: crabs (locomotion, oxygen Tucson consumption, and color change), sh (swimming), and bivalves (shell gapping). On most coastlines there are two high and two low tides each lunar day, which is the 24 hour and 51 minute average interval between successive moonrises, due to the gravitational and centrifugal forces generated between the moon and the earth. Hence, the average high tide–to–high tide interval is 12.4 hours. It appears that crabs possess not one 12.4-hour biological clock, but rather two biological clocks, each running at twice that interval, tightly coupled 180 degrees out of phase, to ensure a stable interval of 12.4 hours between peaks. One benet of two clocks is that deviations of the tides from a 12.4-hour period can be as great as 90 minutes, whereas deviations from a 24.8-hour period are much smaller: 10 minutes. the monitored table is ne. Projection 2 was modied twice, on March 20 and on June 17, and so the old value stored in the tracking log on June 17 is the desired one. Projection 3 was modied once, on May 28, and so the old value for that date is the desired one. Projection 4 was deleted on July 12 (it is present in the tracking log, but not in the monitored table); we use the old value for that date. Projection 5 was deleted on February 3, and so should not be present in the reconstructed table. The table as of April 1, 1996, is thus as shown in Table 8.3. There are two basic cases. Here, the date for which the state is to be reconstructed is termed the as-of date. Reconstruct a previous state of a monitored table, as of a specied date Each row of a prior state was not deleted or updated after the as-of date, and thus is in the monitored table, or was deleted or updated after the as-of date, and thus is in the tracking log. 8.2 QUERIES 225 Table 8.3 The monitored table as of April 1, 1996. PROJECTION ID PROJECTION TYPE 1 2 3 4 12 13 15 17 Code Fragment 8.3 Reconstruct the PROJECTIONS table as of April 1, 1996. SELECT * FROM PROJECTIONS AS P WHERE NOT EXISTS (SELECT * FROM P_Log AS A WHERE P.PROJECTION_ID = A.PROJECTION_ID AND A.When_Changed > DATE 1996-04-01) UNION SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_Log AS A WHERE When_Changed = (SELECT MIN(When_Changed) FROM P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID AND A2.When_Changed > DATE 1996-04-01) This example illustrates the structure of the reconstruction process. The row from the monitored table is to be retained if there does not exist a change record in the tracking log with a When Changed after the as-of date. Otherwise, the old value is extracted from the change record with a When Changed date that is the rst one to appear after the as-of date. The approach presented thus far in this chapter is adequate for identifying what changes were made to the PROJECTIONS table, and for undoing the changes that were incorrect by rst reconstructing the table as of the date it was last known to be correct. It has the benets of not impacting the existing F INDER code and of adding little to the storage requirements (recall that the PROJECTIONS table is small and that changes to this table are infrequent). Nigel was called back a few months later to correct the same problem. This time it took him only a few minutes to reconstruct the monitored table (by running the above code) and identify the incorrect values. Additionally, he had in hand the date the incorrect change was effected and could use this information to narrow down who made the change. Nigel has used the tracking log approach several times for other tables that users were incorrectly updating. 226 8.2.2 CHAPTER EIGHT : RETAINING A TRACKING LOG Other Queries We now turn to other kinds of queries. Current queries on tracking logs are trivial: just perform them on the monitored table as before. Code Fragment 8.4 List the information on projection 5. SELECT * FROM PROJECTIONS WHERE PROJECTION_ID = 5 Future queries are not possible: we have no way of knowing what the monitored table will look like in the future. Past queries are quite useful on monitored tables; indeed, tables are audited precisely to enable such queries. The above SEQueries on past states of a LECT statement (CF-8.3) extracts a prior state of the monitored monitored table are easiest to table. More extensive queries on this state (say, to prepare a express via a reconstruction report as of the end of the calendar year) are best realized by view. forming a view. Code Fragment 8.5 Reconstruct the PROJECTIONS table as of April 1, 1996, as a view. CREATE VIEW April_PROJECTIONS ( PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE) AS (SELECT . . . ) Here, the SELECT statement in CF-8.3 is used to create a (snapshot) view, which can then be used in queries. Code Fragment 8.6 List the information on projection type 12 as of April 1, 1996. SELECT * FROM April_PROJECTIONS WHERE PROJECTION_TYPE = 12 8.2.3 Converting to a State Table* One way to perform sequenced and nonsequenced queries on a tracking log is to convert it to a transaction-time state table. As with valid-time state tables, we timestamp each row with a closed-open period, represented with two transaction timestamp columns (see Table 8.4). Note that the maximum stop time is “now” (January 16, 1998). Rows that are in the current table (and thus are current now) will have a stop time of “now” in the transaction-time state table. Rows that are not in the current table (and thus were deleted) will have a stop time in the past. 8.2 QUERIES 227 Table 8.4 The tracking log as a transaction-time state table, PROJECTIONS State. PROJECTION ID PROJECTION TYPE Start Date Stop Date 1 5 4 2 3 2 2 3 12 18 17 10 15 13 14 11 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-03-20 1996-06-17 1996-05-28 1998-01-16 1996-02-03 1996-07-12 1996-03-20 1996-05-28 1996-06-17 1998-01-16 1998-01-16 There are four basic cases to consider, differentiated by the timestamp of the resulting row in the state table: 1. The initial row never changed. The state table includes the initial row, valid from January 1, 1996 to the present. 2. The initial row was deleted. The state table includes the initial row, valid from January 1, 1996 to the tracking log entry's When Changed date. This timestamp also results from the case where the initial row was modied at least once, with the earliest row in the audit table contributing a row in the state table valid from January 1, 1996 to the tracking log entry's timestamp. 3. The initial row was modied at least once, with the resulting row drawn from the audited table, valid from the last audit entry's timestamp to the present. 4. Here the initial row was modied several times. Each intermediate value results in a state table row valid from the earlier change date to the later change date. This timestamp also results if the row was deleted. Each case contributes a SELECT statement, with the result being the UNION of these intermediate results, as the cases are disjoint. Code Fragment 8.7 Convert P Log to a transaction-time state table. CREATE VIEW PROJECTIONS_State (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) continued on page 228 228 CHAPTER EIGHT : RETAINING A TRACKING LOG continued from page 227 AS ( -- Case 1 SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, DATE 1996-01-01, CURRENT_DATE FROM PROJECTIONS WHERE NOT EXISTS ( SELECT * FROM P_Log WHERE P_Log.PROJECTION_ID = PROJECTIONS.PROJECTION_ID) UNION -- Case 2 SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, DATE 1996-01-01, When_Changed FROM P_Log AS A1 WHERE NOT EXISTS ( SELECT * FROM P_Log AS A2 WHERE A1.PROJECTION_ID = A2.PROJECTION_ID AND A1.When_Changed > A2.When_Changed) UNION -- Case 3 SELECT A1.PROJECTION_ID, A1.PROJECTION_NAME, A1.PROJECTION_TYPE, A1.SPHEROID_CODE, A1.PROJECTION_UOM, A1.ZONE_CODE, When_Changed, CURRENT_DATE FROM P_Log AS A1, PROJECTIONS WHERE A1.PROJECTION_ID = PROJECTIONS.PROJECTION_ID AND NOT EXISTS ( SELECT * FROM P_Log AS A2 WHERE A1.PROJECTION_ID = A2.PROJECTION_ID AND A1.When_Changed < A2.When_Changed) UNION -- Case 4 SELECT A1.PROJECTION_ID, A1.PROJECTION_NAME, A1.PROJECTION_TYPE, A1.SPHEROID_CODE, A1.PROJECTION_UOM, A1.ZONE_CODE, A0.When_Changed, A1.When_Changed FROM P_Log AS A0, P_Log AS A1 WHERE A0.PROJECTION_ID = A1.PROJECTION_ID AND A0.When_Changed < A1.When_Changed AND NOT EXISTS ( SELECT * FROM P_Log AS M WHERE M.PROJECTION_ID = A1.PROJECTION_ID AND M.When_Changed < A1.When_Changed AND M.When_Changed > A0.When_Changed) ) 8.3 Sequenced and nonsequenced queries on a tracking log are best stated on a view that extracts the states as a transaction-time state table. Code Fragment 8.8 MODIFICATIONS 229 Given the transaction-time state table dened by this view, current, sequenced, and nonsequenced queries can be performed analogously to such queries on valid-time state tables. The semantics of such queries are somewhat different because these tables utilize transaction time. Rather than being of the form “Give the history of . . .,” transaction-time sequenced queries are of the form “When was it recorded that . . .” When was it recorded that a projection had a type of 17? SELECT PROJECTION_ID, PROJECTION_TYPE, Start_Date, Stop_Date FROM PROJECTIONS_State WHERE PROJECTION_TYPE = 17 This query returns the following table: PROJECTION ID PROJECTION TYPE Start Date Stop Date 4 17 1996-01-01 1996-07-12 This transaction sequenced selection and projection query should be compared with the similar valid-time sequenced queries CF-6.6 and CF-6.7. Other examples of sequenced and nonsequenced queries are given in Section 9.3. 8.3 MODIFICATIONS Current modications are trivial: these are modications on the monitored table, with the triggers behind the scene ensuring that the tracking log is kept consistent. Code Fragment 8.9 Insert a projection with an ID of 6. INSERT INTO PROJECTIONS (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE) VALUES (6, New Projection, 22, 14, 93, 4) Code Fragment 8.10 Delete projection 2. DELETE FROM PROJECTIONS WHERE PROJECTION_ID = 2 230 CHAPTER EIGHT : RETAINING A TRACKING LOG Code Fragment 8.11 Change the type of projection 1 to 43. UPDATE PROJECTIONS SET PROJECTION_TYPE = 43 WHERE PROJECTION_ID = 1 Sequenced and nonsequenced modications are not allowed on tracking logs because such modications destroy the semanSequenced and nonsequenced tics of a tracking log in two senses. If a past state were modied, modications are not allowed we no longer would be able to reconstruct the state as it was on tracking logs. stored at that time, thereby removing the prime motivation for a tracking log. If a state with a stop date after “now” were inserted, then a future state could not later be reconstructed. 8.4 PERMITTING INSERTIONS The above code makes several assumptions, which we now address. The rst assumption is that the table was originally constituted with insertions, and thereafter the only changes were updates and deletions. Any insertions that do occur will be assumed (in the reconstruction algorithm) to have been executed when the table was dened. Say that an insertion of a new projection, number 6, was made on June 29, 1996. CF-8.3 would include this projection in the state reconstructed as of April 1, 1996, via the rst SELECT statement. A second assumption is that insertions are not allowed after a deletion. To remove the rst assumption, we need to include insertions to the tracking log, so that they will be dated correctly. This is done via a trigger on INSERT. Code Fragment 8.12 Insert trigger for maintaining the P Log table. CREATE TRIGGER Insert_PROJECTIONS AFTER INSERT ON PROJECTIONS FOR EACH ROW INSERT INTO P_Log VALUES (NEW.PROJECTION_ID, NEW.PROJECTION_NAME, NEW.PROJECTION_TYPE, NEW.SPHEROID_CODE, NEW.PROJECTION_UOM, NEW.ZONE_CODE, CURRENT_DATE) Having the insertions in the tracking log increases the size of the tracking log considerably. In the rst approach, projections were in P Log only if the projection was updated or deleted. The tracking log table might be much smaller than 8.4 PERMITTING INSERTIONS 231 The Sothic Cycle Early calendars were lunar, perhaps because the lunar cycle, at slightly less than 30 days, is more easily observed than the solar cycle, at about 365.25 days. The Egyptian calendar contained 12 months of 30 days each. However, the annual ooding of the Nile required reconciliation with the solar year, so ve intercalated days were included. The lack of a leap day meant that their civil lunar New Year retrogressed by 1/4 day each year with respect to the religious solar New Year (dened as when the Dog Star, named Sothis by the Greeks, rose with the sun). The two New Years coincide once every 1,460 years, termed the Sothic cycle. It is known that in 139 A . D ., the two New Years did coincide, so, working backward, historians have concluded that the Egyptian calendar originated in 4241 B . C . E . (This is being written in 1998, during the 399th year of the fth Sothic cycle.) Table 8.5 Including insertions in the P Log table. PROJECTION ID PROJECTION TYPE When Changed 1 2 3 4 5 5 2 3 2 4 12 10 15 17 18 18 10 15 13 17 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-02-03 1996-03-20 1996-05-28 1996-06-17 1996-07-12 the monitored table if the monitored table exhibited low volatility. In this new approach, every projection in PROJECTIONS is also in P Log, as illustrated by Table 8.5. The tracking log is now always larger than the monitored table. However, this additional information allows us to reconstruct the monitored table correctly even in the presence of later insertions. To reconstruct the PROJECTIONS table at a previous time t , there are ve cases to consider, shown in Figure 8.1. In this gThe time sequence of an object ure, the sequence of operations for a single projection is shown records the evolution over time as a progression along time. This progression consists of an inof that object. sertion, followed by zero or more updates, followed optionally by a deletion. Such a sequence is called the time sequence of the projection. The ve cases indicate possible as-of times. Case 1 occurs when the as-of time t is before the initial insertion. The projection should not appear in the reconstructed table. In Case 2, t is between the time of insertion and the rst update. Either the 232 CHAPTER EIGHT : RETAINING A TRACKING LOG INSERT (1) UPDATE (2) UPDATE (3) DELETE (4) (5) Figure 8.1 Cases for tracking log reconstruction. rst value of the tracking log (from the INSERT trigger) or the second value (from the UPDATE trigger) should be used in the reconstructed table; the two values are identical. In Case 3, t occurs between two updates; the value from the tracking log corresponding to the second update should be used. In Case 4, t occurs between the last update and the tuple being deleted; the value in the tracking log inserted by the DELETE trigger should be used here. In Cases 2 through 5, the value stored in PROJECTIONS may also be used. In Case 5, t occurs after the deletion. In Cases 4 and 5, the as-of time is after the last time in the tracking log. We differentiate these cases by the presence of the projection in the monitored table. If the projection is not in PROJECTIONS, and the timestamp of the last tracking log match is older than the as-of time (Case 5), then that projection was deleted and should not appear in the reconstructed value. Otherwise (Case 4), the value in PROJECTIONS should be used. In the following code fragment, we merge Cases 2 through 4 in the rst SELECT. We locate the rst entry in the tracking If arbitrary insertions are log after the as-of time t (the NOT EXISTS and the middle predallowed, the reconstruction icate ensure that this entry is the rst) and use its values for the algorithm becomes more columns. The EXISTS ensures that this is not Case 1. The second complex. SELECT is Case 4, where no DELETE or UPDATE followed the as-of time. The result is the same as before, shown in Table 8.3. Code Fragment 8.13 Reconstruction algorithm 2, again, as of April 1, 1996. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_Log AS A WHERE NOT EXISTS ( SELECT * FROM P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID AND DATE 1996-04-01 < A2.When_Changed AND A2.When_Changed < A.When_Changed) AND DATE 1996-04-01 < A.When_Changed AND EXISTS ( SELECT * 8.5 BACKLOGS 233 FROM P_Log AS A3 WHERE A.PROJECTION_ID = A3.PROJECTION_ID AND A3.When_Changed <= DATE 1996-04-01) UNION SELECT * FROM PROJECTIONS AS P WHERE DATE 1996-04-01 > (SELECT MAX(When_Changed) FROM P_Log AS A WHERE P.PROJECTION_ID = A.PROJECTION_ID) The code to create a transaction-time state table is also complicated by this change. 8.5 BACKLOGS While the trigger in CF-8.12 allows insertions to the PROJECTIONS table other than at the very beginning, it still does not allow insertions after a deletion. This is because a deletion followed later by an insertion of the same projection is indistinguishable in the tracking log from two sequential updates. To differentiate a deletion from an update, we add a column to P Log that indicates which operation was done. Such a tracking log is called a backlog . A backlog is a tracking log with the modication operation (insert, delete, update) explicitly identied. ALTER TABLE P_Log ADD COLUMN Operation CHAR(1) The triggers must be changed to also store the Operation code, I, D, and U. Table 8.6 shows an example of the P Log table, with some insertions after deletions. This differs from the list of transactions in Section 8.2 in that the two latest insertions, which were not allowed before, are included here. As before, we show only a few of the columns in the backlog. There are three basic cases to consider in the reconstruction algorithm. 1. If the as-of time t occurs before the rst insertion of a projection's time sequence, the projection is not included. 2. If t occurs after the last operation of a projection, the projection is included only if the operation is not a deletion, using the current value in the PROJECTIONS table. 3. Otherwise, t occurs between two operations, and Table 8.7 must be consulted to determine the appropriate action: to use the value from the rst operation or to use the value stored from the second operation. The entries marked “illegal” cannot occur. For example, it is impossible for a projection to be reinserted 234 CHAPTER EIGHT : RETAINING A TRACKING LOG Table 8.6 The P Log backlog. PROJECTION ID PROJECTION TYPE When Changed Operation 1 2 3 4 5 5 2 5 3 2 4 4 12 10 15 17 18 18 10 19 15 13 17 18 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-02-03 1996-03-20 1996-04-09 1996-05-28 1996-06-17 1996-07-12 1996-08-30 I I I I I D U I U U D I Table 8.7 Reconstruction action. I rst (oldest before t ) I U D illegal illegal nothing second (youngest after t ) U D rst or second second illegal rst or second second illegal because PROJECTION ID is the key for the monitored table. It is also impossible for a deletion to follow a deletion because there is no projection to remove. This analysis indicates that two SELECT statements are required, the rst for Case 2 and the second for the options in Table 8.7. In this table, an illegal entry simply cannot occur, and so needs not be accommodated in the reconstruction algorithm. Code Fragment 8.14 Reconstruction algorithm 3. SELECT * FROM PROJECTIONS AS P WHERE DATE 1996-04-01 > (SELECT MAX(When_Changed) FROM P_Log AS A WHERE P.PROJECTION_ID = A.PROJECTION_ID) UNION SELECT A2.PROJECTION_ID, A2.PROJECTION_NAME, A2.PROJECTION_TYPE, A2.SPHEROID_CODE, A2.PROJECTION_UOM, A2.ZONE_CODE FROM P_Log AS A, P_Log AS A2 WHERE A.When_Changed < A2.When_Changed 8.6 USING AFTER-IMAGES CONSISTENTLY 235 AND A.PROJECTION_ID = A2.PROJECTION_ID AND NOT EXISTS (SELECT * FROM P_Log AS A3 WHERE A.PROJECTION_ID = A3.PROJECTION_ID AND A.When_Changed < A3.When_Changed AND A3.When_Changed < A2.When_Changed) AND A.When_Changed < DATE 1996-04-01 AND DATE 1996-04-01 < A2.When_Changed AND A.Operation <> D A tracking log can contain before-images, after-images, or both, with differing implications for reconstruction. 8.6 This code is complex because a combination of before-images, where the previous values of the row are stored, and after-images, where the new values are stored, appear in P Log. In particular, before-images are stored by the UPDATE and DELETE triggers, and after-images are stored by the INSERT trigger. USING AFTER-IMAGES CONSISTENTLY The reconstruction algorithm can be simplied considerably if the DELETE and UPDATE triggers use after-images consistently. The former needs not store any values because the after-image is not dened for deletions. The INSERT trigger may be retained from CF-8.12, as it already records the after-image. Code Fragment 8.15 Triggers for maintaining the P Log table, version 2. CREATE TRIGGER Delete_PROJECTIONS AFTER DELETE ON PROJECTIONS FOR EACH ROW INSERT INTO P_Log VALUES (OLD.PROJECTION_ID, NULL, NULL, NULL, NULL, CURRENT_DATE, D) CREATE TRIGGER Update_PROJECTIONS AFTER UPDATE ON PROJECTIONS FOR EACH ROW INSERT INTO P_Log VALUES (NEW.PROJECTION_ID, NEW.PROJECTION_NAME, NEW.PROJECTION_TYPE, NEW.SPHEROID_CODE, NEW.PROJECTION_UOM, NEW.ZONE_CODE, CURRENT_DATE, U) 236 CHAPTER EIGHT : RETAINING A TRACKING LOG Table 8.8 Backlog with after-images. PROJECTION ID PROJECTION TYPE When Changed Operation 1 2 3 4 5 5 2 5 3 2 4 4 12 10 15 17 18 NULL 13 19 11 14 NULL 18 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-02-03 1996-03-20 1996-04-09 1996-05-28 1996-06-17 1996-07-12 1996-08-30 I I I I I D U I U U D I Table 8.9 Reconstruction action. I rst I U D illegal illegal nothing second U rst rst illegal D rst rst illegal For the same transactions discussed previously, the backlog shown in Table 8.8 results. In comparison with Table 8.6, note that both have the same number of rows. In fact, the only difference is the value of the PROJECTION TYPE column (the new values are indicated in italics). The previous representation exhibited redundancy in that consecutive I-U pairs in a time sequence have identical values for that column; the entries for projection 2 on January 1 and March 20 provide an example. The same holds for consecutive I-D pairs, such as the entries for projection 5 on January 1 and February 3. Consistently using after-images enables a shorter reconstruction algorithm. Let us examine the action table for after-images Using after-images consistently (Table 8.9). Note that if the Operation is I or U, the same action simplies the reconstruction occurs. Also note that if there is only one operation before the algorithm considerably. as-of time, the same action occurs here also. Hence, there is no need to consult the PROJECTIONS table, and the reconstruction algorithm becomes a single SELECT statement. 8.6 Code Fragment 8.16 USING AFTER-IMAGES CONSISTENTLY 237 Reconstruction algorithm with after-images. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_Log AS A WHERE A.When_Changed =(SELECT MAX(A2.When_Changed) FROM P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID AND A2.When_Changed < DATE 1996-04-01) AND A.Operation <> D Using only after-images also changes the transaction-time state view. Convert a backlog containing after-images to a transaction-time state table Each row of the state table starts with an I or U operation and ends with a U or D operation, or starts with an I or U operation and is not subsequently modied, in which case its stop time is “now.” Code Fragment 8.17 Convert the backlog to a transaction-time state table, using afterimages. CREATE VIEW PROJECTIONS_state ( PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, START_DATE, STOP_DATE) AS (SELECT A.PROJECTION_ID, A.PROJECTION_NAME, A.PROJECTION_TYPE, A.SPHEROID_CODE, A.PROJECTION_UOM, A.ZONE_CODE, A.When_Changed, A2.When_Changed FROM P_Log AS A, P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID AND A.When_Changed < A2.When_Changed AND A.Operation <> D AND NOT EXISTS ( SELECT * FROM P_Log AS A3 WHERE A.PROJECTION_ID = A3.PROJECTION_ID AND A.When_Changed < A3.When_Changed AND A3.When_Changed < A2.When_Changed) continued on page 238 238 CHAPTER EIGHT : RETAINING A TRACKING LOG continued from page 237 UNION SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, When_Changed, CURRENT_DATE FROM P_Log AS A WHERE A.Operation <> D AND NOT EXISTS ( SELECT * FROM P_Log AS A3 WHERE A.PROJECTION_ID = A3.PROJECTION_ID AND A.When_Changed < A3.When_Changed) ) We make sure each pair of operations in the rst SELECT is consecutive by disallowing an intermediate operation. This code fragment should be compared with CF-8.7, which is over three times longer. The comparison emphasizes the value of consistent use of after-images in the tracking log. As mentioned earlier, once the transaction-time state table is available, sequenced and nonsequenced queries can be performed analogously to such queries on valid-time state tables, as discussed in detail in Chapter 6. As an example, consider the following query: When was it recorded that a projection had the same USGS zone code as the projection with ID 13447? The rst part, “when was it recorded,” indicates that we are concerned with transaction time. It also implies that if a particular time is reSequenced and nonsequenced turned, the specied relationship should hold during that time. queries are best expressed on a This indicates a sequenced query, here in transaction time. transaction-time state table The fact that two projections are mentioned indicates a (self-) view, rather than on the join on the transaction-time state table. CF-6.12 provides the underlying tracking log. structure for a sequenced join, which we can use here. Using after-images consistently also greatly simplies the conversion of the tracking log to a transaction-time state table. Code Fragment 8.18 List the projections recorded as having the same USGS zone code as the projection with ID 13447. SELECT S1.PROJECTION_NAME, CASE WHEN S1.START_DATE > S2.START_DATE THEN S1.START_DATE ELSE S2.START_DATE END, CASE WHEN S1.STOP_DATE > S2.STOP_DATE THEN S2.STOP_DATE ELSE S1.STOP_DATE END, FROM PROJECTIONS_state AS S1, PROJECTIONS_state AS S2 WHERE S1.ZONE_CODE = S1.ZONE_CODE AND S2.PROJECTION_ID = 13447 AND S1.PROJECTION_ID <> 13447 AND (CASE WHEN S1.START_DATE > S2.START_DATE 8.6 USING AFTER-IMAGES CONSISTENTLY 239 THEN S1.START_DATE ELSE S2.START_DATE END) < (CASE WHEN S1.STOP_DATE > S2.STOP_DATE THEN S2.STOP_DATE ELSE S1.STOP_DATE END) The resulting query isn't too bad. However, computing this result on the underlying tracking log would have been extremely complex. When after-images are used consistently, P Log contains all of PROJECTIONS, which is not true of the prior approaches. It includes this additional information without adding any rows; instead, redundancy is eliminated to provide this information. This allows the current version to be computed even more easily. Code Fragment 8.19 Reconstructing the current version. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_Log AS A WHERE A.When_Changed =(SELECT MAX(A2.When_Changed) FROM P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID) AND A.Operation <> D If after-images are used in the tracking log, then the monitored table itself is superuous. Code Fragment 8.20 In fact, the PROJECTIONS table is simply a cached version of the reconstruction as of “now.” We could dene it as a view, thereby achieving a space savings, as the current information would not be in both the monitored table and the backlog, at the expense of more expensive retrieval of that information. Dening PROJECTIONS as a view on P Log. CREATE VIEW PROJECTIONS ( PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE) AS (SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_Log AS A WHERE A.When_Changed =(SELECT MAX(A2.When_Changed) FROM P_Log AS A2 WHERE A.PROJECTION_ID = A2.PROJECTION_ID) AND A.Operation <> D ) If the PROJECTIONS table is dened as a view, then the user is responsible for updating the backlog directly, as current DBMSs do not permit triggers to be dened on a view. 240 8.7 CHAPTER EIGHT : RETAINING A TRACKING LOG TRANSACTION SEMANTICS* All of the above approaches make three assumptions: 1. No two changes to the same projection occur on a single day, even in different transactions. This assumption derives from the When Changed column being a DATE. 2. Every transaction commits by the end of the day; that is, a transaction does not span two days. Otherwise the reconstruction algorithm may return a partially completed state—a state that will never be visible to the application, as we will see shortly. 3. Every transaction makes at most one modication to each projection. This assumption is a consequence of PROJECTION ID and When Changed forming the primary key for P Log. Violating assumption 1 or 3 will cause the INSERT statement in the trigger to fail, which will abort the entire transaction. In fact, Simple approaches to assumption 1 implies no concurrency in the modications to maintaining the tracking log the PROJECTIONS table, which in many situations is untenable. impose rather harsh constraints Violating assumption 2 can cause the reconstruction algorithm on the application. to yield an incorrect result, which is also generally untenable. One obvious attempt to remove these assumptions is to redene the When Changed column to be a TIMESTAMP, which has a default precision of microsecond. However, this just changes assumption 1 to one in which no two changes to the same projection can occur on a single microsecond, which, given today's transaction processing rates, is a reasonable one. The concern then arises as to whether the trigger ensures that the When Changed value is consistent with the serialization order of the transactions that are changing the PROJECTIONS table. To put this another way, was the table reconstructed at a specied time actually visible to transactions executing at that time? Let us examine two transactions, T1 and T2 . We assume two-phase row-level locking as our concurrency control mechanism. Transaction T1 starts on July 1 at 4 P. M . It updates projection 1 at 6 P. M . (18:00) and again at 8 P. M . (Transactions generally complete in a much shorter period of time; here we spread out the time to make this example easier to discuss.) Each update inserts a row into the backlog; that row is write-locked. Transaction T2 updates projection 2 at 7 P. M . and commits at 9 P. M . T1 updates projection 3 at 1 A . M . the following day and commits at 2 A . M . Note that T1 updates projection 1 twice and also spans a day, thereby violating all three assumptions. 8.7 TRANSACTION SEMANTICS* 241 Table 8.10 A sample backlog. PROJECTION ID PROJECTION TYPE When Changed Operation 1 2 1 3 10 12 14 13 1996-07-01 18:00 1996-07-01 19:00 1996-07-01 20:00 1996-07-02 01:00 U U U U T1 T2 T1 T1 Table 8.11 State of the PROJECTIONS table before 9 P. M . PROJECTION ID PROJECTION TYPE 1 2 3 5 7 9 Table 8.12 State of the PROJECTIONS table between 9 P. M . and 2 A . M . PROJECTION ID PROJECTION TYPE 1 2 3 5 12 9 This series of updates will generate the backlog shown in Table 8.10 (here we show the transaction associated with each row, though this information will not be stored in the backlog). The reconstruction algorithm yields the state of the monitored table at any point in time. Due to concurrent transactions, such as the two above, what we desire is a state that is consistent with the serialization order of the transactions that executed on that table. Assume that the projection type for projection 1 was initially 5; for projection 2, 7; and for projection 3, 9. At any time before 9 P. M ., the state of the PROJECTIONS table is as shown in Table 8.11, reecting that no (committed) transactions have updated the table. Recall that transaction T2 committed at 9 P. M . and T1 at 2 A . M . So between those two times, the state of the PROJECTIONS table was as shown in Table 8.12, reecting the changes made by T2 . After 2 A . M . on July 2, the state of the monitored table has the values shown in Table 8.13, reecting the changes made by both T2 and T1 . 242 CHAPTER EIGHT : RETAINING A TRACKING LOG Table 8.13 State of the PROJECTIONS table after 2 A . M . PROJECTION ID PROJECTION TYPE 1 2 3 14 12 13 Table 8.14 Reconstructed state as of 6:30 P. M . PROJECTION ID PROJECTION TYPE 1 2 3 10 7 9 The reconstruction algorithm will yield precisely the rst state for as-of times before 6 P. M . on July 1 and the third state for times after 2 A . M . on July 2. More interesting is what it does for intermediate as-of times when applied after 2 A . M ., July 2. Applying the algorithm with an as-of time of 6:30 P. M ., using the backlog shown in Table 8.10, yields Table 8.14. This differs from the state before 6 P. M . in the type of projection 1, which was changed by transaction T1 . Note, however, that T1 had not committed by 6:30 P. M . Hence, no other transaction would have seen this state, because it is not consistent with any serialization order. We see that reconstruction yields a state containing information from active transactions. As an aside, what happens if transaction T1 later aborted, rather than committing? It turns out that we are OK in such situations because all the rows of the backlog inserted by that transaction are automatically removed upon abort, and hence will not be used by the reconstruction algorithm. In the case above, we are running the reconstruction algorithm after July 2, and so we know that T1 had committed because its updates are in the backlog. Returning to 6:30 P. M ., what would a concurrent transaction (T3 ) see? Transaction T3 will not have access to projection 1 beThe reconstruction algorithm cause that row will be write-locked by T1 at 6:30 P. M . And we may yield states inconsistent know that T2 did not read projection 1 because had it tried, it with serializability. would have blocked on that same lock and would have resumed only at 2 A . M . the next morning, when T1 committed. What if transaction T3 had attempted to read projection 1 using a dirty read isolation level, rather than the default serialization isolation level? In that case, the write lock on that row is ignored, and T3 would have seen the projection type as 10. 8.8 REFINEMENTS* 243 The Vertical Blanking Interval That ubiquitous sign of technical ineptitude, the blinking “12:00” on the videocassette recorder, has recently been the source of technological innovation, as VCRs learn how to get the time directly from the video feed. A television frame (30 frames a second) is composed of two elds of 262.5 horizontal scan lines each. The rst 21 lines of each eld, collectively called the vertical blanking interval (VBI), are hidden (they are the black band you see when your vertical tracking isn't working). The rst 9 are used for repositioning the scan, but the remaining 12 lines are available for data transport. Line 21 itself is reserved for closed captioning. PBS stations in the United States use extended data ser- vices codes within line 21 to send the current date and time. Some of the newer VCRs scan all frequencies to nd the PBS channel, then set their clock automatically from line 21 of the VBI. They also refresh their internal clock, as often as once an hour, from this source, to correct for drift in their internal clock and to make daylight saving time adjustments. This technology renders the VCR the most accurate clock available for home use. Incidentally, the other 11 lines are being considered for VBI data broadcasting; these lines provide an aggregate of about 150 Kbps per channel streaming into every home. So, to be precise, the reconstruction algorithm yields a state that would be visible to a transaction at the specied time using a dirty read isolation level. This state, though, will contain only changes made by transactions that eventually committed. What if there are still active transactions? Since the backlog itself is being read by the reconstruction algorithm using the (default) serialization isolation level, the algorithm must place a read lock on the entire backlog, and hence there can be no write locks in place, which implies that there can be no active transactions that have modied the monitored table. Any subsequent transaction that wished to modify the monitored table will attempt to write-lock the backlog, and thus will have to await the completion of the reconstruction algorithm of the other transaction. The effect is to serialize the reconstruction transaction with all other transactions, including other reconstruction transactions. 8.8 REFINEMENTS* If we wish the reconstruction algorithm to not retrieve dirty data, then we must ensure that such data is not written to the tracking log. The triggers can be modied to delete a previous value, for the projection in question, before inserting the current value. To do so, the trigger needs to know if the value in the tracking log was put there by this transaction, or if it is the committed value by a previous transaction. The former value should be removed, but the latter value must be retained. We add 244 CHAPTER EIGHT : RETAINING A TRACKING LOG a transaction identier to the tracking log to make this distinction. Alternatively, we can augment the reconstruction algorithm to ignore dirty data by using only the last record of each projection, which requires ordering the records inserted by a transaction. The When Changed value serves this purpose if it is of a sufciently ne precision. The modications performed by a transaction should be included in the reconstructed state only for times after the commit time of the transaction. Because the commit time is not stored in the tracking log, the reconstruction algorithm must approximate this time; a reasonable guess is the Achieving fully accurate time of the last modication in the tracking log. We can imtransaction semantics for the prove this somewhat by having the application insert a record reconstructed table is difcult. into the tracking log immediately before committing. Note that this requires scanning the application code to identify COMMITs of transactions that modify the PROJECTIONS table, a task not necessitated by any of the other approaches in this chapter. This commit time is also an estimate, in that the commit process may itself take some time, and the actual commit record may be written to the DBMS log (thereby effecting the actual commit) quite a while after the time recorded in P Log. Reconstructing the exact state, utilizing only the transactions that have actually committed by the specied time, is in general not possible because the DBMS does not render the actual commit time accessible. 8.9 IMPLEMENTATION CONSIDERATIONS Microsoft Access 97 and Access 2000 do not support table-based triggers. 8.9.1 IBM DB2 Universal Database IBM DB2 UDB triggers differ in some syntactic details from the SQL-92 triggers discussed in this chapter. DB2 UDB requires a referencing clause to create correlation names for the old and new values in the referenced table, for example, REFERENCING OLD AS O. DB2 also requires that MODE DB2SQL be specied. Finally, when there is more than one action specied for a trigger, these actions must be delimited with BEGIN ATOMIC and END. When there is exactly one action in the trigger, these delimiting clauses are optional. Finally, CURRENT DATE is two words in DB2 UDB (it is one word, with an embedded underscore, in SQL-92). CF-8.2 can be expressed in DB2 UDB as follows (with the optional ATOMIC clause specied for clarity): Code Fragment 8.21 Triggers for maintaining the P Log table in DB2 UDB, assuming no insertions. CREATE TRIGGER Delete_PROJECTIONS AFTER DELETE ON PROJECTIONS 8.9 IMPLEMENTATION CONSIDERATIONS 245 REFERENCING OLD AS O FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO P_Log VALUES (O.PROJECTION_ID, O.PROJECTION_NAME, O.PROJECTION_TYPE, O.SPHEROID_CODE, O.PROJECTION_UOM, O.ZONE_CODE, CURRENT DATE); END CREATE TRIGGER Update_PROJECTIONS AFTER UPDATE ON PROJECTIONS REFERENCING OLD AS O FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO P_Log VALUES (O.PROJECTION_ID, O.PROJECTION_NAME, O.PROJECTION_TYPE, O.SPHEROID_CODE, O.PROJECTION_UOM, O.ZONE_CODE, CURRENT DATE); END 8.9.2 Microsoft SQL Server The syntax of the CREATE TRIGGER statement supported by Microsoft SQL Server differs from SQL-92. The implicit OLD and NEW correlation names are not available; instead, SQL Server provides two special tables, inserted, containing the rows that were inserted, and deleted, containing the rows that were deleted, by the statement under consideration. “Now” is implemented in SQL Server via GETDATE(). CF-8.2 can be expressed in SQL Server as follows: Code Fragment 8.22 Triggers for maintaining the P Log table in Microsoft SQL Server, assuming no insertions. CREATE TRIGGER Delete_PROJECTIONS ON PROJECTIONS FOR DELETE AS INSERT P_Log SELECT *, GETDATE() FROM deleted continued on page 246 246 CHAPTER EIGHT : RETAINING A TRACKING LOG continued from page 245 CREATE TRIGGER Update_PROJECTIONS ON PROJECTIONS FOR UPDATE AS INSERT P_Log SELECT *, GETDATE() FROM deleted The other code fragments can be similarly implemented in Microsoft SQL Server. 8.9.3 Sybase SQLServer Sybase SQLServer was one of the rst DBMSs to support triggers. The syntax of the CREATE TRIGGER statement supported by Sybase SQLServer differs from SQL92. The implicit OLD and NEW correlation names are not available; instead, Sybase provides two special tables, inserted, containing the rows that were inserted, and deleted, containing the rows that were deleted, by the statement under consideration. “Now” is implemented in Sybase via GETDATE(). CF-8.2 can be expressed in Sybase as follows: Code Fragment 8.23 Triggers for maintaining the P Log table in Sybase SQLServer, assuming no insertions. CREATE TRIGGER Delete_PROJECTIONS ON PROJECTIONS FOR DELETE AS INSERT P_Log SELECT *, GETDATE() FROM deleted CREATE TRIGGER Update_PROJECTIONS ON PROJECTIONS FOR UPDATE AS INSERT P_Log SELECT *, GETDATE() FROM deleted The other code fragments can be similarly implemented in Sybase SQLServer, with the exceptions of CF-8.7 and CF-8.17, as Sybase does not allow a view to be over a UNION. 8.9.4 Oracle8 Server All the code fragments work ne under Oracle8 Server. 8.9 8.9.5 IMPLEMENTATION CONSIDERATIONS 247 UniSQL UniSQL supports triggers, but does not allow expressions such as CURRENTDATE within triggers. However, it does allow triggers to call methods on rows. To store a value of “now” in the tracking log, we'll use two triggers. The rst, dened on the monitored table, is the normal one, with the minor change of storing a placeholder date (DATE 01/01/1800) as the timestamp. The second is an insert trigger, dened on the tracking log, which calls a method to replace this value with the current date. Code Fragment 8.24 Insert UniSQL trigger on the tracking log. EXEC SQLX ALTER CLASS P_Log ADD METHOD set_date() FUNCTION set_date FILE ./trans.o; CREATE TRIGGER Insert_P_Log AFTER INSERT ON P_Log EXECUTE CALL set_date(); The set date function uses the db put operation to replace the date with the current date. Code Fragment 8.25 set date C function. void set_date(DB_OBJECT *obj) f EXEC SQLX BEGIN DECLARE SECTION; DB_VALUE d; struct timeval time_sec; struct tm *cur_time; EXEC SQLX END DECLARE SECTION; gettimeofday(&time_sec, NULL); cur_time = localtime(&time_sec.tv_sec); g 8.9.6 db_make_date(&d, cur_time->tm_mon+1, cur_time->tm_mday, cur_time->tm_year+1900); db_put(obj, "When_Changed",&d); EXEC SQLX COMMIT WORK; CD-ROM Materials All of the code discussed in this chapter has been implemented in IBM DB2 UDB, Microsoft SQL Server 7.0, Sybase SQLServer, Oracle8 Server, and UniSQL, and is provided on the CD-ROM, along with a test harness and Makefile. 248 CHAPTER EIGHT : RETAINING A TRACKING LOG Table 8.15 Tracking log organizations and their imposed constraints. All insertions performed initially Before-images Before- + after-images After-images Backlog 8.10 p p p p constraints on updates None allowed after deletions No constraints p p p p SUMMARY A tracking log contains the history of modications to the underlying monitored table, allowing previous states of that table to be reconstructed. A tracking log is maintained separately from the monitored table. For the PROJECTIONS table, a tracking log is preferable, as the rest of the application need not be modied. Different organizations of the tracking log result from the varying assumptions and constraints on the monitored table. We considered a variety of situations:    All insertions are performed initially. Only deletions and updates need be stored in the tracking log. Insertions are allowed at any time other than after a deletion. In this case, insertions must also be stored in the tracking log. The tracking log will be at least as long as the underlying table, even with no updates or deletions. Insertions are allowed at any time. In such cases a backlog, in which the operation type (INSERT, DELETE, UPDATE) is explicitly recorded, is indicated. Two organizations were discussed, one which stored a combination of before- and after-images, and one which stored only after-images, the latter exhibiting a concomitant simplication of the reconstruction algorithm. Table 8.15 summarizes the tracking log organizations (listed down the left) and the constraints imposed on when insertions are allowed to the monitored table (listed across the top). A check mark means that Different organizations of the the indicated organization will work when the indicated contracking log result from various straint is satised. initial assumptions and The tracking log structure depends strongly on the applicaconstraints on the monitored tion. In the case of the problem with inadvertent changes to table. the PROJECTIONS table, a very simple structure was adequate. Should the application need to make arbitrary modications to 8.10 SUMMARY 249 the monitored table, then a backlog is appropriate. If intermediate, dirty data is undesirable in the reconstructed states, then either more involved triggers or a more involved reconstruction algorithm is required. You must be careful to distinguish the information content of a tracking log and of a valid-time table. A conventional table Tracking logs support models the current state of a portion of the enterprise. A validtransaction time, which is time table models the time-varying state of a portion of the enorthogonal to valid time. terprise. A tracking log is an example of a transaction-time table. Such a table records the state not of the modeled reality, but of the monitored table over time. This distinction is important both in the information we can extract from the table and the kinds of updates permitted. Consider two tables, the valid-time table Employee from Chapter 5 and the transaction-time table P Log from this chapter. Requesting the state on April 1, 1996, of the valid-time table will return the employees on that date, as best known. This information is independent of when the Employee table was actually created. In fact, this table could have been created yesterday, then populated with historical information. On the other hand, requesting the state on April 1, 1996, of the transaction-time table will return the contents of that table as it was stored on disk on that date. If the table was actually populated yesterday, then its state back on April 1 would be empty. Information about the past or future can be added or changed in valid-time tables. If we nd that information about April 1, 1996, was in error (say, an employee was omitted), we can make that correction; later queries will return that employee. On the other hand, we cannot change what was stored previously on the disk, and so cannot update past states of a transaction-time table. Similarly, we do not know what will be stored on disk in the future, and so cannot update future states of that table. Hence, transaction time is dened only in the past, unlike valid time, which can extend into the future. All we can do is append a new state to the table. For this reason, all the triggers that maintain P Log effect insertions. A transaction-time table is append-only. Changes to the monitored table, whether insertions, deletions, or updates, are in actuality insertions into the tracking log. This means that we can add a tracking log to a conventional table, as was described in this chapter, or to a valid-time table, resulting in a bitemporal table, to be discussed in Chapter 10. A transaction-time table has an important property not shared with valid-time tables: queries on past states will return the same result when evaluated at any time in the future. Consider CF-8.3 on page 225, “reconstruct the PROJECTIONS table as of April 1, 1996.” Whether we execute this query on April 2, 1996, December 31, 1996, July 7, 1998, or September 22, 2009, the resulting states will all be identical. The resulting state will be a copy of the PROJECTIONS table that was present as magnetic patterns on the disk on April 1, 1996. 250 CHAPTER EIGHT : RETAINING A TRACKING LOG We also dened views of the PROJECTIONS table; CF-8.5 on page 226 is the reconstructed table as of April 1, 1996 as a view. It makes no difference whether this view is materialized as a stored table or remains as a virtual table because the contents of the view will not change, regardless of the modications applied to either PROJECTIONS or P Log. The triggers dened in this chapter to maintain the tracking log ensure that only the current state is modied; prior states must be left intact and unchanged. For this same reason, changes to the future of a transactiontime table are not allowed. There is no way to accurately predict The reconstructed state of a what the magnetic patterns of the disk will be at some point in transaction-time table as of a the future. point in the past will never Such is not the case with valid-time tables. We are free to rechange, independent of when vise the stored history in a valid-time table as new information that reconstruction query or becomes available. Sequenced and nonsequenced modications view is evaluated. The state at a can change the past and the future. A view of the enterprise point in time of a valid-time on April 1, 1996, can change as information about that date is table can change, as new received and our knowledge is rened. The valid-time table reinformation is received and ects our understanding of the history of the enterprise as best incorporated into the table. known. Current queries on a tracking log are much easier on monitored tables than on valid-time state tables: just perform the query on the monitored table, which already records only the current state. Current modications (the only kind allowed on such tables) are equally simple: just apply it to the table, and the triggers will make sure the tracking log is maintained. Legacy applications need not be modied at all when maintaining a tracking log is initiated on the table. Extracting a prior state involves looking both at the monitored table and the tracking log in some tracking log organizations; if a backlog is maintained, the monitored table need not be consulted. Sequenced and nonsequenced queries are best realized by rst dening a view that extracts a transaction-time state table from the tracking log. Sequenced and nonsequenced modications are not permitted on a tracking log, as they would invalidate the semantics of transaction time and would corrupt later reconstructions. 8.11 READINGS Serialization order of concurrent transactions is discussed in many textbooks; [6, 36] are seminal works on this topic. Transaction time was rst covered in detail by Ahn and the author [89, 90] and was later included in the glossary [48]. Tracking logs 8.11 READINGS 251 have been studied by [8]. Backlog tables have been suggested by several authors [51, 52, 61]. Chamberlin shows how to maintain a list of changes, though not the actual values of the changes, eliminating an opportunity to reconstruct past states via DB2 triggers [22, pp. 358–359]. Leung and Pirahesh show how to access a backlog in which only the changed columns, as well as the primary key, were stored; the columns retaining their old values were represented with NULLs, which incur less storage overhead [66]. A timeslice is obtained by collecting, for each primary key value, the most recent value for each column, using the recursive query facilities of DB2. This is a classic time-forspace trade-off. Fraser's Time: the Familiar Stranger [34] is a superb survey of an expanse of topics related to time. Palmer provides a highly readable account of detecting two clocks in ddler crabs, as well as summarizing other biological clocks [78]. [31] is a technical guide for those who wish to provide encoding equipment and/or decoding equipment to produce material with encoded data embedded in line 21 of the vertical blanking interval of the NTSC video signal. The encoded data includes extended data services, such as date and time information. CHAPTER 9 O V E R V I E W A transaction-time state table associates with Different organizations for state tables selec- each row the period of time that row was tively minimize space overhead, modication present in the monitored table, thereby allow- time, degree of legacy code change required, ing the state of the monitored table at any and query complexity. Sometimes triggers can previous point in time to be reconstructed. A be used to maintain the state table. state table is more amenable to sequenced and nonsequenced queries than is a tracking log. If a state table becomes too large, the DBA can vacuum it in a disciplined fashion. Transaction-Time State Tables T he previous chapter addressed Nigel's problem of spurious changes in the PROJECTIONS table by dening an associated tracking log that captures these changes for later perusal. Several organizations of the tracking log were examined: recording before-images, recording after-images, recording both beforeand after-images, and recording the actual modication operations (termed a “backlog”). These variants all utilized a single transaction timestamp, When Changed. To realize some queries, in particular sequenced queries, we recommended that the tracking log be converted into a transaction-time state table, with period timestamping. In this chapter, we adopt exactly the opposite approach. We maintain the transaction-time state table directly, with the monitored (snapshot) table available either as a view or as a regular table. If space is at a premium, maintaining an instant-stamped tracking log (specifically, the after-image organization) with triggers is the way to go. On the other hand, if sequenced queries or sequenced integrity constraints are important, then the period-stamped approach described here should be considered. We revisit the issues of the last chapter using this period-stamped organization. This discussion will parallel that chapter, as well as the valid-time state table chapters (Chapters 5–7). While many of the concepts are the same between the two types of state tables, valid-time and transaction-time, it is important to keep in mind the critical difference: valid-time tables model changes in reality, while transactiontime tables model changes in the database. The two kinds of time are orthogonal, and as we will see later, can be combined into one glorious structure, the bitemporal table. 254 9.1 CHAPTER NINE : TRANSACTION-TIME STATE TABLES DEFINITION Conceptually, a transaction-time state table represents the sequence of snapshot states constituting the states of the monitored table over time. This sequence is represented by timestamping rows with a period. The period begins at the time in which the row was inserted into the monitored table, either directly with an INSERT statement or as a side effect of an UPDATE statement, and ends when the row was deleted from the monitored table, again, either directly via a DELETE statement or as a side effect of an UPDATE statement. This period is termed the period of presence of the row, as it species when that row was in the monitored table. We rst dene a new table, P TT, the transaction-time state table mirroring the PROJECTIONS table. Code Fragment 9.1 Create the transaction-time state table. CREATE TABLE P_TT ( PROJECTION_ID INT, PROJECTION_NAME CHAR(10), PROJECTION_TYPE INT, SPHEROID_CODE INT, PROJECTION_UOM INT, ZONE_CODE INT, Start_Date DATE, Stop_Date DATE, PRIMARY KEY (PROJECTION_ID, Stop_Date)) All but the nal two columns are from the PROJECTIONS table. The Start Date and Stop Date in concert denote the period of presence. Recall from Section 5.3 that the (sequenced) primary key The schema of a of a valid-time table cannot be composed from its columns; transaction-time state table an assertion is required. Such is not the case here. The key of comprises the columns of the monitored table, along with two the transaction-time state table is simply the key of the monitored table (PROJECTION ID) along with the Stop Date column. timestamp columns denoting This works because the primary key constraint on the monithe period of presence. Its key is tored table implies a current key constraint on its associated simply the primary key of the transaction-time state table. Since only current modications monitored table and the start are applied to the state table, a current key constraint implies timestamp column. a sequenced key constraint. 9.2 9.2 MAINTENANCE 255 MAINTENANCE There are two ways to maintain a transaction-time state table: indirectly, as a side effect of triggers dened on the monitored table, and directly, by transforming modications on the monitored table into modications on the state table. The benet of the former approach is that no code need be changed when the state table is dened; legacy applications function as before. 9.2.1 Indirectly via Triggers In this rst approach, the application need not be concerned with maintaining the state table; this will be done behind the scenes via three triggers. In the following, we represent “until changed” with “forever,” in this case DATE 9999-12-31. Code Fragment 9.2 Triggers for maintaining the P TT table. CREATE TRIGGER INSERT_P AFTER INSERT ON PROJECTIONS FOR EACH ROW INSERT INTO P_TT(PROJECTION_NAME, PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) VALUES (NEW.PROJECTION_NAME, NEW.PROJECTION_ID, NEW.PROJECTION_NAME, NEW.PROJECTION_TYPE, NEW.SPHEROID_CODE, NEW.PROJECTION_UOM, NEW.ZONE_CODE, CURRENT_DATE, DATE 9999-12-31) CREATE TRIGGER DELETE_P AFTER DELETE ON PROJECTIONS FOR EACH ROW UPDATE P_TT SET Stop_Date = CURRENT_DATE WHERE P_TT.PROJECTION_ID = OLD.PROJECTION_ID AND P_TT.Stop_Date = DATE 9999-12-31 CREATE TRIGGER UPDATE_P AFTER UPDATE ON PROJECTIONS FOR EACH ROW BEGIN ATOMIC UPDATE P_TT SET Stop_Date = CURRENT_DATE WHERE P_TT.PROJECTION_ID = OLD.PROJECTION_ID AND P_TT.Stop_Date = DATE 9999-12-31; continued on page 256 256 CHAPTER NINE : TRANSACTION-TIME STATE TABLES continued from page 255 INSERT INTO P_TT(PROJECTION_NAME, PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) VALUES (NEW.PROJECTION_NAME, NEW.PROJECTION_ID, NEW.PROJECTION_NAME, NEW.PROJECTION_TYPE, NEW.SPHEROID_CODE, NEW.PROJECTION_UOM, NEW.ZONE_CODE, CURRENT_DATE, DATE 9999-12-31) END After the transactions listed in Section 8.2.1, the state table (in this chapter, mention of a state table will imply a transaction-time state table) will contain the rows shown in Table 9.1. As before, we only show two columns, PROJECTION ID and PROJECTION TYPE, as well as the timestamp columns. It is useful to compare Table 9.1 with the state table converted from the tracking log, Table 8.4. The only difference is Triggers on the monitored table the value of the Stop Date column. In the previous table, for can be used to maintain a some rows the value is 1998-01-16 (the date the conversion was transaction-time state table. run, “now”), whereas here the value for those rows is 9999-1231, or “forever.” While “now” is in fact more accurate, in that only the past and the current state can be stored in a transaction-time state table (since we cannot predict the future), we use “forever” in this chapter only because constantly updating the Stop Date value to “now” is impractical. The state table is somewhat redundant, in two senses. It contains all of the monitored table, as rows with a Stop Date of “forever.” And many of the other stop dates are not strictly necessary, as they are paired with identical Start Date values; projections 2 and 3 are examples. The Stop Date value of 1996-03-20 for the rst row of projection 2 matches the Start Date value of the following row of projection 2; indeed, both of these rows were impacted by a single transaction, an UPDATE that Table 9.1 A transaction-time state table, P TT. PROJECTION ID PROJECTION TYPE Start Date Stop Date 1 2 3 4 5 2 3 2 12 10 15 17 18 13 11 14 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-03-20 1996-05-28 1996-06-17 9999-12-31 1996-03-20 1996-05-28 1996-07-12 1996-02-03 1996-06-17 9999-12-31 9999-12-31 9.2 MAINTENANCE 257 changed the type of projection 2 from 10 to 13. This shows that the tracking log organizations, which use only one timestamp column, are more space efcient than the period-stamped state table organization. However, the state table approach is much easier to query, especially for sequenced queries. 9.2.2 Directly via Rewritten Modications A transaction-time state table may also be maintained directly. Code Fragment 9.3 The second approach is to replace the monitored table with the state table, then dene the monitored table as a view on the state table, with the associated space savings over the regular monitored table of the previous section. Reconstruct the PROJECTIONS table as of now, as a view. CREATE VIEW PROJECTIONS (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE) AS (SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_TT WHERE Stop_Date = DATE 9999-12-31) Applications composed only of queries on the PROJECTIONS table will work ne with this view, oblivious to the fact that the evolution of that table is being retained. Applications that modify the PROJECTIONS table must be changed to instead modify the state table. Chapter 7 discussed 12 (!) categories of modications on valid-time state tables: INSERT, DELETE, and UPDATE coupled Pendulum with current, sequenced, and nonsequenced semantics, along with current The foliot was weighted to slow its oscillation, with modications in the restricted case (only the weights movable so that the clock could be current modications ever allowed). The adjusted. Unfortunately, the friction of the clock's situation with transaction-time state tables mechanism and its exact mechanical arrangement is much simpler, as there are only current kept its accuracy to only about 15 minutes a day. modications. We cannot modify the past, What was needed was a periodic device whose freas we cannot change the bits that were quency was dependent only on the device itself stored on disks in the past. Similarly, we and not on the details of its manufacture. cannot modify the future, as we cannot acThe Dutch scientist Christian Huygens was the curately predict what will be stored on the rst to apply the pendulum, whose frequency is disk in the future. We can only modify the dependent only on its length, to regulate a clock. current state. So, we are left with only three Huygens's clock of 1656 was accurate to 10 seconds kinds of modications to consider: cura day, a vast improvement over the foliot clock. rent INSERT, current DELETE, and current 258 CHAPTER NINE : TRANSACTION-TIME STATE TABLES UPDATE. The resulting code is very similar to that given for current modications to valid-time state tables in Section 7.1. An INSERT on a transaction-time state table requires only appending the Start Date and Stop Date values, as “now” (CURRENT DATE) and “forever” (DATE 9999-1231), respectively. Code Fragment 9.4 Insert a projection with an ID of 6. INSERT INTO P_TT (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) VALUES (6, New Projection, 22, 14, 93, 4, CURRENT_DATE, DATE 9999-12-31) The fourth and sixth lines of this fragment were added to capture the change behavior. A DELETE is mapped into an UPDATE, changing the Stop Date of the deleted row(s) to “now.” Code Fragment 9.5 Delete projection 2. UPDATE P_TT SET Stop_Date = CURRENT_DATE WHERE PROJECTION_ID = 2 AND Stop_Date = DATE 9999-12-31 An UPDATE is logically a deletion followed by an insertion, and so is implemented with an UPDATE and an INSERT. However, the INSERT must come rst. Code Fragment 9.6 Change the type of projection 1 to 43. INSERT INTO P_TT (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) SELECT PROJECTION_ID, PROJECTION_NAME, 43, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, CURRENT_DATE, DATE 9999-12-31 FROM P_TT WHERE PROJECTION_ID = 1 AND Stop_Date = DATE 9999-12-31 UPDATE P_TT SET Stop_Date = CURRENT_DATE WHERE PROJECTION_ID = 1 AND PROJECTION_TYPE <> 43 AND Stop_Date = DATE 9999-12-31 9.3 QUERIES 259 Here we rst ensure that there is a row to update, then insert the new value (via the INSERT), and terminate the old value at Maintaining the state table via direct modications obviates the “now” (via the UPDATE). The PROJECTION TYPE <> 43 predicate in the UPDATE is required to avoid changing the row just inneed for a materialized monitored table, decreasing the serted. We emphasize that in this approach P TT is a replacement space overhead for capturing for the PROJECTIONS table. We maintain the P TT table directly changes over time. through rewritten modication statements, rather than indirectly through triggers dened on the monitored table. 9.3 QUERIES As previously mentioned, the advantage of a transaction-time state table over a tracking log (with its single timestamp) is its ease in querying. Reconstruction queries on state tables are termed time-slice queries. The current state view (CF-9.3) was one example. Of course, it is possible to reconstruct the state of the monitored table at any point in the past. Code Fragment 9.7 Reconstruct the PROJECTIONS table as of April 1, 1996. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_TT WHERE Start_Date <= DATE 1996-04-01 AND DATE 1996-04-01 < Stop_Date This is shorter than any of the reconstruction algorithms given for the tracking log organizations (compare with CF-8.3, CF-8.13, CF-8.14, and CF-8.16). This code also seems to work for dates in the future (try reReconstruction is easy to express placing 1996 with 2009), but in fact we have no idea what rows the PROJECTIONS table will contain in 2009. Reconstructions on a state table, though only should only be done on the current or past dates; using fustates in the past or present ture dates is meaningless. (This doesn't apply to valid-time state should be requested. tables, where future time-slices may be quite meaningful.) Current queries are even easier: just apply to the monitored table or view. State tables really shine when sequenced queries are desired. The strategies for such queries on valid-time state tables apply in their entirety on transactiontime state tables, with two important provisions. A sequenced query on a validtime state table means “give the history of”; a sequenced query on a transactiontime state table means “when was it recorded that” or perhaps “give the change history for.” 260 CHAPTER NINE : TRANSACTION-TIME STATE TABLES The second difference is that while a sequenced query on a valid-time state table returns another valid-time state table, Sequenced queries over transaction-time state tables are a sequenced query on a transaction-time state table does not return another transaction-time state table. Recall once again expressed identically to such that a transaction-time state table species the magnetic patqueries over valid-time state tables. However, their semantics terns recorded on the disk at times in the past. The result of a sequenced query itself was emphatically not stored on the disk is in terms of “when was it in the past; it has just been calculated now. It does indicate recorded that.” what was recorded, but it itself was not in existence until the query was performed. To emphasize this distinction, we will use the column names Recorded Start and Recorded Stop for these query results. With those critical distinctions in mind, we now try out some sequenced queries. As before, selections (the WHERE clause) and projections (the SELECT clause) are easy to render as sequenced (compare with CF-6.7). Code Fragment 9.8 When was it recorded that a projection had a type of 17? SELECT PROJECTION_ID, PROJECTION_TYPE, Start_Date AS Recorded_Start, Stop_Date AS Recorded_Stop FROM P_TT WHERE PROJECTION_TYPE = 17 Selections (the WHERE clause) are unchanged in sequenced queries; projections (the SELECT clause) require adding the timestamp columns. UNION is also easy to convert (compare with CF-6.10). Code Fragment 9.9 Give the change history for projections having a type of 12 or 18. SELECT PROJECTION_ID, Start_Date AS Recorded_Start, Stop_Date AS Recorded_Stop FROM P_TT WHERE PROJECTION_TYPE = 12 UNION SELECT PROJECTION_ID, Start_Date, Stop_Date FROM P_TT WHERE PROJECTION_TYPE = 18 This will tell us when such projections were added or removed, or when the type was changed to or from 12 or 18. Joins are more challenging. Here we use first instant and last instant PSM functions (CF-6.13). Compare the following query with CF-6.14. Code Fragment 9.10 When was it recorded that two projections had the same type? SELECT P1.PROJECTION_ID, P2.PROJECTION_ID, P1.PROJECTION_TYPE, last_instant(P1.Start_Date, P2.Start_Date) AS Recorded_Start, 9.3 QUERIES 261 first_instant(P1.Stop_Date, P2.Stop_Date) AS Recorded_Stop FROM P_TT AS P1, P_TT AS P2 WHERE P1.PROJECTION_ID <> P2.PROJECTION_ID AND P1.PROJECTION_TYPE = P2.PROJECTION_TYPE AND last_instant(P1.Start_Date, P2.Start_Date) < first_instant(P1.Stop_Date, P2.Stop_Date) Auditing queries are often nonsequenced queries. Once an error is found, queries examining the changes made to the monitored table attempt to determine how and why the error was made. Changes appear in the state table as two periods that meet. Code Fragment 9.11 When was the type of a projection erroneously changed to be identical to that of an existing projection? SELECT P1.PROJECTION_ID, P2.PROJECTION_ID, P1.PROJECTION_TYPE AS Identical_TYPE, P3.PROJECTION_TYPE AS Prior_TYPE, P2.Start_Date AS When_Changed FROM P_TT AS P1, P_TT AS P2, P_TT AS P3 WHERE P1.PROJECTION_ID <> P2.PROJECTION_ID AND P2.PROJECTION_ID = P3.PROJECTION_ID AND P1.PROJECTION_TYPE = P2.PROJECTION_TYPE AND P2.PROJECTION_TYPE <> P3.PROJECTION_TYPE AND P3.Stop_Date = P2.Start_Date Here, P1 is the existing projection; P3 has the old type, which was changed erroneously to P2. This query is arduous when attempted on a tracking log. While the old or the new type is readily available (depending on whether before- or after-images are recorded in the tracking log), determining the type of a projection existing at the same time is difcult with instant-stamped tables. Another kind of nonsequenced query is the conversion to a tracking log. Beforeimages and after-images can be easily extracted from a state table. Code Fragment 9.12 Extract before-images from a transaction-time state table. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Stop_Date AS When_Changed FROM P_TT WHERE Stop_Date <> DATE 9999-12-31 Code Fragment 9.13 Extract after-images from a transaction-time state table. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date AS When_Changed FROM P_TT 262 CHAPTER NINE : TRANSACTION-TIME STATE TABLES Converting a state table to a backlog is a little more ambitious, as we have to distinguish insertions, deletions, and updates. However, doing so emphasizes that the information content of tracking logs (possibly along with the monitored table), backlogs, and transaction-time state tables is identical. Code Fragment 9.14 Extract a backlog from a transaction-time state table. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date AS When_Changed, I AS Operation FROM P_TT AS P1 WHERE NOT EXISTS ( SELECT * FROM P_TT AS P2 WHERE P1.PROJECTION_ID = P2.PROJECTION_ID AND P2.Stop_Date = P1.Start_Date) UNION SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Stop_Date AS When_Changed, D AS Operation FROM P_TT AS P1 WHERE P1.Stop_Date <> DATE 9999-12-31 AND NOT EXISTS ( SELECT * FROM P_TT AS P2 WHERE P1.PROJECTION_ID = P2.PROJECTION_ID AND P1.Stop_Date = P2.Start_Date) UNION SELECT P1.PROJECTION_ID, P1.PROJECTION_NAME, P1.PROJECTION_TYPE, P1.SPHEROID_CODE, P1.PROJECTION_UOM, P1.ZONE_CODE, P2.Start_Date AS When_Changed, U AS Operation FROM P_TT AS P1, P_TT AS P2 WHERE P1.PROJECTION_ID = P2.PROJECTION_ID AND P1.Stop_Date = P2.Start_Date Tracking logs, backlogs, and transaction-time state tables have identical information content. 9.4 Here we do a case analysis. INSERTs are indicated by the absence of an immediately preceding state with the same key value, DELETEs by the absence of an immediately following state, and UPDATEs by the presence of an immediately preceding state. TEMPORAL PARTITIONING* As we mentioned, having a Stop Date of “forever” is awkward, as we cannot accurately predict the future. As discussed in Section 7.5 in the context of valid time, 9.4 TEMPORAL PARTITIONING* 263 a temporally partitioned organization nesses this awkwardness, while also achieving a slight space savings, at the expense of requiring more effort to express some queries. This organization uses two (or more) tables to represent a single state table. 9.4.1 Current and Archival Stores To illustrate, we use two tables, P TT PAST, consisting of the rows that have been corrected, and P TT CURRENT, consisting of the rows that haven't been corrected, that is, whose period of presence includes “now.” Since all rows of P TT CURRENT have a Stop Date of “now,” we'll simply omit that column. Code Fragment 9.15 Create a temporally partitioned transaction-time state table. CREATE TABLE P_TT_PAST (PROJECTION_ID INT, PROJECTION_NAME CHAR(10), PROJECTION_TYPE INT, . . ., Start_Date DATE, Stop_Date DATE, PRIMARY KEY (PROJECTION_ID, Start_Date)) CREATE TABLE P_TT_CURRENT (PROJECTION_ID INT, PROJECTION_NAME CHAR(10), PROJECTION_TYPE INT, . . ., Start_Date DATE DEFAULT CURRENT_DATE, PRIMARY KEY (PROJECTION_ID)) There are three differences between the two tables. The rst is that P TT CURRENT does not have a Stop Date column. Its implicit stop date is “now.” The second is that P TT CURRENT has a default value of “now” for the Start Date; we will see the utility of this shortly. The nal difference is that the primary key of P TT CURRENT is that of the original monitored table. We term P TT PAST the archival store: it contains rows that have been corrected, and “store” is used rather than “table” to differentiate the representation (the “store”) from the logical structure (the state table). P TT CURRENT is likewise termed the current store. Another way to think about this is that P TT CURRENT is the monitored table, PROJECTIONS, with an additional Start Date column. This enables us to dene PROJECTIONS as a view and also justies P TT CURRENT having the same primary key. 264 CHAPTER NINE : TRANSACTION-TIME STATE TABLES Code Fragment 9.16 Reconstruct the PROJECTIONS table as of now, as a view on a temporally partitioned table. CREATE VIEW PROJECTIONS (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE) AS (SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_TT_CURRENT) A transaction-time state table may be represented with two tables, a current and an archival store. Code Fragment 9.17 Comparing this code fragment with CF-9.3, we notice that here every row is selected; in that earlier view denition, we had to explicitly test the Stop Date. The best way to maintain this temporally partitioned state table is via triggers on the current store. Triggers for maintaining the P TT table. CREATE TRIGGER DELETE_P BEFORE DELETE ON P_TT_CURRENT FOR EACH ROW INSERT INTO P_TT_PAST(PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, CURRENT_DATE FROM P_TT_CURRENT AS P WHERE P.PROJECTION_ID = OLD.PROJECTION_ID CREATE TRIGGER UPDATE_P BEGIN ATOMIC BEFORE UPDATE ON P_TT_CURRENT FOR EACH ROW INSERT INTO P_TT_PAST(PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, CURRENT_DATE FROM P_TT_CURRENT AS C WHERE C.PROJECTION_ID = OLD.PROJECTION_ID UPDATE P_TT_CURRENT SET Start_Date = CURRENT_DATE WHERE P_TT_CURRENT.PROJECTION_ID = OLD.PROJECTION_ID END 9.4 TEMPORAL PARTITIONING* 265 Table 9.2 The P TT PAST table. PROJECTION ID PROJECTION TYPE Start Date Stop Date 2 3 4 5 2 10 15 17 18 13 1996-01-01 1996-01-01 1996-01-01 1996-01-01 1996-03-20 1996-03-20 1996-05-28 1996-07-12 1996-02-03 1996-06-17 Table 9.3 The P TT CURRENT table. PROJECTION ID PROJECTION TYPE Start Date 1 3 2 12 11 14 1996-01-01 1996-05-28 1996-06-17 Note that there is no trigger for INSERT. An insertion just affects the current store. However, for a deletion or update, we capture The two-table representation the before-image in the archival store, with a period of presrequires a few replacements in ence from the date the row was originally inserted (or updated) the legacy code. to “now.” Finally, P TT CURRENT.Start Date of the updated row needs to be changed to “now”; this requires an after-trigger. Dening the triggers on the current store requires that the following replacements be made to the legacy code:    INSERT INTO PROJECTIONS replaced with INSERT INTO P TT PAST DELETE FROM PROJECTIONS replaced with DELETE FROM P TT PAST UPDATE PROJECTIONS replaced with UPDATE P TT PAST Within the modication statement, and within SELECT statements, references to PROJECTIONS can remain; these will now refer instead to the view dened on P TT CURRENT. These triggers will produce the archival and current stores shown in Tables 9.2 and 9.3, which should be compared with Table 9.1. There were eight rows in that previous table, partitioned here into ve corrected rows and three current rows. 9.4.2 Queries We now turn to queries. Queries on the current state can be applied to the PROJECTIONS view as before. Past states can be reconstructed, using the archival store. 266 CHAPTER NINE : TRANSACTION-TIME STATE TABLES Code Fragment 9.18 Reconstruct the PROJECTIONS table as of April 1, 1996. SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_TT_PAST WHERE Start_Date <= DATE 1996-04-01 AND DATE 1996-04-01 < Stop_Date UNION SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE FROM P_TT_CURRENT WHERE Start_Date <= DATE 1996-04-01 This is an extension of CF-9.7. An important difference is that future states cannot be reconstructed from the archival store, as the Stop Date is always before “now.” This makes the archival store slightly safer to use. Sequenced queries are a little more difcult because the inBoth the monitored table and formation is spread across two tables. The easiest approach is to the transaction-time state table dene another view, P TT, which is the original state table being can be dened as views on the implemented by the two stores. two stores. Code Fragment 9.19 Dene the state table as a view. CREATE VIEW P_TT (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) AS (SELECT * FROM P_TT_PAST UNION SELECT PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, CURRENT_DATE AS Stop_Date FROM P_TT_CURRENT) Having the state table available as a view, we can then query it exactly as discussed in Section 9.3, using it for both sequenced and nonsequenced queries. 9.4.3 Utilizing the Primary Key One objection to the partitioned organization just presented is that it requires the legacy application to be modied. Granted, the modication is slight—just replace the mention of the PROJECTIONS table in the rst line of modication statements— but any change to a complex application should not be approached lightly. In a tripartitioned table, the The PROJECTIONS table was dened as a view on the current current store consists of just the store, just projecting out the Start Date column. Instead, we primary key and the start date. can dene three tables: the original monitored table, the archival 9.4 TEMPORAL PARTITIONING* 267 store, and a horizontally truncated current store, containing only the primary key of the monitored table and the start time, when that row was inserted into the monitored table. The current store and the archival store can be maintained via triggers on the monitored table, thereby obviating any changes to legacy code. Code Fragment 9.20 Dene a truncated current store. CREATE TABLE P_TT_CURRENT ( PROJECTION_ID INT Start_Date DATE, PRIMARY KEY (PROJECTION_ID)) The triggers are now dened on the monitored table itself. Code Fragment 9.21 Triggers for maintaining a tripartitioned state table. CREATE TRIGGER INSERT_P AFTER INSERT ON PROJECTIONS FOR EACH ROW INSERT INTO P_TT_CURRENT(PROJECTION_ID, Start_Date) VALUES (NEW.PROJECTION_ID, CURRENT_DATE) CREATE TRIGGER DELETE_P BEFORE DELETE ON PROJECTIONS FOR EACH ROW BEGIN ATOMIC INSERT INTO P_TT_PAST(PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) SELECT OLD.PROJECTION_ID, OLD.PROJECTION_NAME, OLD.PROJECTION_TYPE, OLD.SPHEROID_CODE, OLD.PROJECTION_UOM, OLD.ZONE_CODE, Start_Date, CURRENT_DATE FROM P_TT_CURRENT AS PC WHERE PC.PROJECTION_ID = OLD.PROJECTION_ID; DELETE FROM P_TT_CURRENT WHERE PROJECTION_ID = OLD.PROJECTION_ID; END CREATE TRIGGER UPDATE_P AFTER UPDATE ON PROJECTIONS FOR EACH ROW BEGIN ATOMIC INSERT INTO P_TT_PAST(PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) continued on page 268 268 CHAPTER NINE : TRANSACTION-TIME STATE TABLES continued from page 267 SELECT OLD.PROJECTION_ID, OLD.PROJECTION_NAME, OLD.PROJECTION_TYPE, OLD.SPHEROID_CODE, OLD.PROJECTION_UOM, OLD.ZONE_CODE, Start_Date, CURRENT_DATE FROM P_TT_CURRENT AS PC WHERE PC.PROJECTION_ID = OLD.PROJECTION_ID; UPDATE P_TT_CURRENT SET Start_Date = CURRENT_DATE WHERE PROJECTION_ID = NEW.PROJECTION_ID END Here we have the P TT CURRENT table mirror the changes to the monitored table, with before-images retained in the archive store. Current queries are expressed against the monitored table, which is now materialized, rather than being dened as a view as A view reconstitutes the state in some of the other organizations. Such queries will generally table from the three underlying be faster when evaluated against a table than when evaluated tables. against a view of a larger underlying table. For sequenced and nonsequenced queries, we dene a transaction-time state view over the three constituent tables. Code Fragment 9.22 Dene the state table as a view. CREATE VIEW P_TT (PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, Stop_Date) AS (SELECT * FROM P_TT_PAST UNION SELECT PROJECTIONS.PROJECTION_ID, PROJECTION_NAME, PROJECTION_TYPE, SPHEROID_CODE, PROJECTION_UOM, ZONE_CODE, Start_Date, CURRENT_DATE AS Stop_Date FROM PROJECTIONS, P_TT_CURRENT AS C WHERE PROJECTIONS.PROJECTION_ID = C.PROJECTION_ID) 9.5 VACUUMING* The current store consists of the monitored table plus possibly an additional column, indicating when the row entered the table. As such it will contain the same number of rows as the original monitored table. The archival store contains old rows of the monitored table that have since been corrected; the two additional 9.5 VACUUMING* 269 columns denote the period of presence of these rows. The archival store is useful for auditing the changes that have been applied to the monitored table, particularly when the changes themselves were incorrect or malicious. In comparison with a table associated with no temporal support, the database administrator needs to be aware of the implications of adding transaction-time support to that table. First, either the monitored table will be replaced with the current store with an additional DATE column, or there will be an additional table dened with the primary key and the DATE column. Either approach incurs a slight space penalty. Second, the archival store is created. Initially this table is empty, so the immediate cost is one of execution time for deletions and updates, which trigger insertions into the archival store. Depending on the volatility of the monitored table, the archival store will grow slowly or quickly; in any case, the growth will be monotonic. Every deletion or update of a row of the monitored table will insert a row into the archival store. For highly volatile tables, the archival store can become quite large. In one sense, this is desirable because that store is capturing the time-varying behavior of the monitored table, permitting later analysis, which would be difcult to impossible without the archival store. However, eventually the space required by the archival store may become excessive. Transactions on the monitored table get progressively slower as insertions into the archival store take longer; queries on the virtual transaction-time state table also bog down due to the sheer size of the archival store. At some point the DBA may want to vacuum the archival store to remove less desired rows, thereby improving the space and The archival store can be time efciency of the state table, with the drawback of reducing reduced in size by purging the querying capability of the state table. information on invalid entities. There are several kinds of vacuuming operations. Two major classes are entity vacuuming and temporal vacuuming , distinguished by what is removed. In the former, entities that are judged to be less interesting are removed from the archival store. In the latter, information is removed based on it having been logically deleted at some specied instant in the past. The further back this instant is, the less information discarded. As an example, we can purge all projections that are no longer currently valid. Code Fragment 9.23 Entity vacuum the archival store. DELETE FROM P_TT_PAST WHERE NOT EXISTS ( SELECT * FROM P_TT_CURRENT AS C WHERE P_TT_PAST.PROJECTION_ID = C.PROJECTION_ID) 270 CHAPTER NINE : TRANSACTION-TIME STATE TABLES This works with either partitioned store organization described in Section 9.4. The danger here is that a projection might have been erroneously deleted only yesterday, yet we have just vacuumed away all evidence of that projection. Once a transaction-time table has been vacuumed, subsequent queries should be interpreted with that in mind. The query of CF-9.8 needs to be rephrased: “When was it recorded that a currently present projection had a type of 17?” Vacuuming is a dangerous operation because it violates the underlying semantics of the transaction-time state table. The Although vacuuming a state table allows all prior states of the monitored table to be transaction-time table helps reconstructed. After the state table has been vacuumed, it is no contend with the unchecked longer possible to fully reconstruct some past states. For entity growth of the table, it violates vacuuming, the past states will not contain the entities that have the underlying semantics of the been vacuumed. table, revising the meaning of On page 250, we argued that a view reconstructing a past state subsequent queries. of a transaction-time table was inviolate; it will return the same rows independent of when the view was evaluated. Such is not the case in the presence of vacuuming. Before CF-9.23 was run by the DBA to entity vacuum the archival store, projection 1 was in the April 1, 1996, reconstructed state. After the archival store was vacuumed, projection 1 mysteriously disappeared from that state. Although this is probably what the DBA intended, users of the transaction-time table need to be aware that such vacuuming has occurred, and that the information in the transaction-time table is incomplete. Entity vacuuming is one way to reduce the size of the archival store. Alternatively, we can temporally vacuum the archival store, removing all information older than, say, two years. Many countries have laws that require that certain records be retained only for a xed length of time. Business policies may also pose similar requirements. Such situations indicate temporal vacuuming. Code Fragment 9.24 Temporally vacuum the archival store of data older than two years. DELETE FROM P_TT_PAST WHERE (CURRENT_DATE - Stop_Date DAY) > INTERVAL 731 DAY Again, after temporally vacuuming the archival store, queries need to be reinterpreted. The query of CF-9.8 needs to be rephrased: “When was it recorded over the past two years that a projection had a type of 17?” In most settings, a combination makes sense: delete those entities having only old information, which is a more conservative stance than either entity vacuuming or temporal vacuuming alone. Code Fragment 9.25 Temporally vacuum old unused entities from the archival store. DELETE FROM P_TT_PAST WHERE (CURRENT_DATE - Stop_Date DAY) > INTERVAL 731 DAY 9.5 VACUUMING* 271 AND NOT EXISTS ( SELECT * FROM P_TT_CURRENT AS C WHERE PROJECTION_ID = C.PROJECTION_ID) Sometimes additional criteria may be appropriate; these tests can be added to the WHERE clause. Code Fragment 9.26 Temporally vacuum old unused entities from the archival store that had a USGS spheroid code of 2. DELETE FROM P_TT_PAST WHERE (CURRENT_DATE - Stop_Date DAY) > INTERVAL 731 DAY AND NOT EXISTS ( SELECT * FROM P_TT_CURRENT AS C WHERE PROJECTION_ID = C.PROJECTION_ID) AND SPHEROID_CODE = 2 The DBA may wish to vacuum the archival store based on a combination of criteria. Code Fragment 9.27 The DBA can adjust the vacuuming criteria, trading off the realized space savings with the reduction in querying ability. A record should be kept, probably in a separate vacuuming log, of the cleaning that has taken place. Log the vacuuming operations. CREATE TABLE Vacuum_Log ( Table_Name CHAR(40) NOT NULL, When_Vacuumed DATE NOT NULL, Who CHAR(40) NOT NULL, Entity_Vacuuming CHAR(1) NOT NULL, Vacuum_Interval INTERVAL, Vacuum_Criteria CHAR(256) PRIMARY KEY (Table_Name, When_Vacuumed)) In this table, the Entity Vacuuming column indicates whether old entities were purged, and the Vacuum Interval indicates whether temporal The vacuum log, which indicates vacuuming took place, with a NULL value indicating not. Other criteria used in the vacuuming, such as a USGS spheroid code of the meaning of queries on the 2, can be indicated as a prose comment in Vacuum Criteria. state table, should be This log should be updated each time a state table is vacumaintained automatically. umed. For this reason, it is best to dene stored procedures that vacuum a table, given criteria such as whether to do entity vacuuming and the vacuuming interval, while also ensuring that the Vacuuming specications should vacuuming is logged appropriately. be monotonic to avoid Vacuuming needs to be done in a way that makes sense to time-dependent assumptions. users. While complex predicates can be specied in the WHERE 272 CHAPTER NINE : TRANSACTION-TIME STATE TABLES clause of the DELETE statement effecting the vacuuming, the vacuuming criteria should be carefully chosen. One desirable property of a vacuuming specication is that it be monotonic—once it is satised, it will continue to be satised, so that repeated application does not violate the specication. Consider the following request: Code Fragment 9.28 Temporally vacuum the archival store between one and two years old. DELETE FROM P_TT_PAST WHERE (CURRENT_DATE - Stop_Date DAY) > INTERVAL 365 DAY AND (CURRENT_DATE - Stop_Date DAY) < INTERVAL 730 DAY This deletion will repeatedly be applied, to keep the size of the archival store in check. The problem is that data that is 15 months old, and hence is subject to deletion, will eventually become two years old and should then be retained. However, that data is gone; it cannot be later reconstituted. In contrast, the vacuuming specication of CF-9.24, “data older than two years,” is monotonic: once data satises this predicate, it will always satisfy the predicate. Similarly, the vacuuming specications of CF-9.25 and CF-9.26 are also monotonic. We note in passing that a nonmonotonic vacuuming specication is an instance of a time-dependent assumption (see page 66), to be avoided if at all possible. 9.6 IMPLEMENTATION CONSIDERATIONS The code fragments were implemented in Microsoft SQL Server. 9.6.1 Microsoft SQL Server Other than the proviso mentioned in Section 8.9.2 concerning using the inserted and deleted tables rather than the OLD and NEW correlation names, all the code fragments worked as stated on Microsoft SQL Server 6.5 and 7.0. 9.6.2 CD-ROM Materials All of the code discussed in this chapter has been implemented in Microsoft SQL Server and is provided on the CD-ROM. 9.7 9.7 SUMMARY 273 SUMMARY A transaction-time state table maintains a history of the changes that have been applied to a monitored table by associating with each row a period of presence, indicating when that row was present in the monitored table. Several organizations for such state tables were considered:     As a period-stamped table augmenting the monitored table (CF-9.1), with triggers dened on the monitored table (CF-9.2). Here there is some duplication, as rows of the monitored table will also be present in the state table. This approach does not require any changes to legacy code. As a single period-stamped table, with the monitored table dened as a view on the state table, as discussed in the previous chapter. Modications must be rephrased to apply to the state table; queries can still reference the view. As a current and an archival store (CF-9.15), with the monitored table dened as a view on the current store (CF-9.16). The rst line of modication statements must be changed to refer to the current store; triggers on this store automatically maintain the archival store. The current store is narrower, as the superuous stop date is not stored. Sequenced and nonsequenced queries are applied to a view reconstituting the state table. As a tripartitioned store: an archival store as before, a current store containing only the key and the start date (CF-9.20), and the monitored table, with triggers on the monitored table maintaining both stores (CF-9.21). This organization requires no changes to the legacy code and materializes the monitored table for efcient current queries. Transaction-time state tables have the same information content as the tracking logs considered in the previous chapter. We demonstrated this with views that extracted the before-images, after-images, and rows of a backlog. The previous chapter provided views that went the other direction, to a state table from a tracking log. A tracking log can be considered to be a temporally partitioned transaction-time table in which the archival store is timestamped with an instant, rather than a period. 274 CHAPTER NINE : TRANSACTION-TIME STATE TABLES To choose between the organizations that support transaction time presented in the last two chapters, the following factors should be considered:        Are all insertions performed when the table is rst created, or can entities come and go? Can an entity be deleted and later inserted? How critical is the space overhead? How critical is modication performance? How volatile is the monitored table? Which is most prevalent, current, sequenced, or nonsequenced queries? Is the legacy code available? If so, how hard is it to modify? As a rough guide to selecting the manner in which transaction-time support is implemented, the following is suggested:        Use a tracking log only if sequenced and nonsequenced queries are rare. Use before-images only if all insertions are performed when the table is created. Use after-images only if no insertions follow deletions. Use a backlog only if sequenced and nonsequenced queries are rare and if afterimages are not indicated. Use a single or bipartitioned transaction-time state table if legacy code can be changed and space is tight. Use a state table along with the monitored table if changes to legacy code are not permitted and space isn't too tight. Use a tripartitioned state table if the legacy code cannot be changed and space is tight. Vacuuming can be used to ameliorate the space overhead of maintaining all previous states of the monitored table. The DBA can congure the extent and timing of the purge process via vacuuming specications; the DBA should ensure that these specications are monotonic. 9.8 9.8 READINGS 275 READINGS Jacob Ben-Zvi originated the concept of a partitioned store in his Ph.D. dissertation [5]. Several others subsequently studied partitioned stores in the context of valid-time, transaction-time, and bitemporal tables [1, 26, 60, 67, 68]. Christian S. Jensen and Leo Mark have developed a comprehensive theory concerning vacuuming that includes the kinds of vacuuming discussed in this chapter [50]. Their approach goes further and considers the impact on query semantics and query evaluation, and discusses how to perform the vacuuming operation. Jensen later applied these concepts to a language extension to TSQL2 to support rudimentary vacuuming [47] and later still extended his theory of vacuuming [85]. These facilities have yet to be proposed for SQL3. CHAPTER 10 O V E R V I E W A bitemporal table is a glorious structure. It Bitemporal tables, in capturing both valid simultaneously records the history of the en- time and transaction time, require care in mainterprise, while also capturing the sequence of taining. Modications must not disturb prechanges to the record of that history. Bitempo- viously recorded information; they must be ral tables permit queries on the history as best append-only. As such, modications generally known (over valid time, with a transaction time require longer sequences of more complex SQL of “now”), queries on the change history of a statements. stored data item (over transaction time, with Bitemporal tables admit a wide variety of a xed valid time), and queries on the interac- temporal queries and integrity constraints. tion of valid time and transaction time (for ex- They also admit a variety of representational ample, nding that information stored retroac- schemes, which speed up some common tively, after the fact). It is this range of queries queries at the expense of some rarer queries. that makes bitemporal tables so versatile and useful. Bitemporal Tables I nformation is the key asset of many companies. Nykredit, a major Danish mortgage bank, is a good example. In 1989, the Danish legislature changed the Mortgage Credit Act to allow mortgage providers to market loans directly to customers and through real estate agents; before such loans had to be funneled indirectly through banks, with the mortgage providers separated from the consumer by these middlemen. This change in the law had a dramatic impact on the loan market, with the number of mortgage credit suppliers in Denmark doubling since the law's amendment. This new environment represented both an opportunity to Nykredit to enter into direct marketing, as well as a challenge to fend off its now-burgeoning competitors. One of the challenges was achieving high data quality on the customers and their loans, while expanding the traditional focus to also include customer support. Managers needed access to up-to-date data to set benchmarks and identify problems in various areas of the business. The sheer volume of the data, nine million loans to eight million customers concerning seven million properties, demands that eliminating errors in the data must be highly efcient. Jens Gadgaard is a seasoned senior architect at Nykredit Data, Nykredit's in-house information technology provider, located in bucolic Aalborg. Aalborg is in Jutland, to the north on the mainland, right on the Lim Fjord and only a few miles from the North Sea coast. The company ofces occupy a modern building several kilometers outside of the city proper, fronted by a beautiful pond and surrounded by farmland; I've seen sheep and rabbits contentedly grazing on adjacent elds and lawns. Next door is Aalborg University, with its newly inaugurated Nykredit Center for Database Research. Jens has long pushed for better management of temporal data; the Center and the internal structure of property ownership tables reect this emphasis. As Jens explains it, a customer service person reports an error to the IT personnel; errors are also discovered by batch jobs producing quarterly reports. The more information the IT personnel have access to, the better able they are to analyze and 278 CHAPTER TEN : BITEMPORAL TABLES property_number customer_number customer name 1 n property_ ownership address property_type property estimated_value Figure 10.1 The property ownership relationship. correct these errors. For this reason, Jens mandated that changes to critical tables be tracked. This implies that the tables have transaction-time support. As these tables also model changes in reality, they require valid-time support. The result is termed a bitemporal table, reecting these two aspects of underlying temporal support. With such tables, IT personnel can rst determine when the erroneous data was stored (a transaction time), roll back the table to that point, and look at the valid-time history. They can then determine what the correct valid-time history should be. At that point, they can tell the customer service person what needs to be changed, or if the error was in the processing of a user transaction, they may update the database manually. Because transaction-time support is included, these changes would be logged as well, enabling someone later to see what happened when the change itself was in error. Although bitemporal tables can be challenging to implement, their support for both valid time and transaction time permits a sophisticated analysis of the evolution of the table, with all the data directly at hand. The alternatives of going back through paper records to reconstruct the sequence of changes that were made, or attempting to extract that sequence from backup tapes or other secondary data sources, are simply not practical in such a dramatically changing environment. Nykredit must be doing something right. Despite the arrival of additional competitors, Nykredit was able to increase its market share to become the largest mortgage bank in Denmark by 1997 and is currently Europe's fth largest provider of real estate loans. 10.1 DEFINITION One of the central tables of the Nykredit database is the property ownership table, which we will abbreviate as Prop Owner. This table species the relationship between the customer and property entities, as shown in Figure 10.1 as an entity-relationship diagram. 10.1 DEFINITION 279 The customer entity has a key of customer number; the property entity has a key of property number. (What kind of key, current, sequenced, or nonsequenced?, you may ask. The entity-relationship diagram does not say. We address this critical question only after we decide which aspects of time we wish to capture here.) The customer and property entities have additional attributes. The property ownership relationship is a one-to-many relationship between customers and properties: a customer can own many properties, but a property is owned by exactly one customer. This relationship is itself associated with other attributes, not shown here. In mapping this conceptual entity-relationship schema to a logical, relational schema, the customer entity induces a Customer table, with primary key customer number, and the property entity induces a Property table, with primary key property number. For the property ownership relationship, we have two alternatives, given that this relationship is a one-to-many relationship. One alternative is to extend the Property table with a customer number foreign key, as well as the relationship's attributes. However, since the relationship is not total/mandatory (a property can exist without being owned by a customer present in the Nykredit database), that implies that all of the property ownership attributes must be nullable, including the customer number. The second alternative, which is more attractive in this case, is to create a separate table, the Prop Owner table, with foreign keys customer number and property number. None of these columns need be nullable. It turns out that the Customer and Property tables are temporal tables, but we will defer consideration of that aspect. For the Prop Owner table, Jens wanted to capture both the history in reality of the owner(s) of a property over time, as well as the sequence of database states, capturing the transactions applied to this table. This requirement, originating from a need for high A bitemporal state table data quality, meant that both valid time and transaction time contains four timestamp were relevant for this table. columns, two specifying the A bitemporal state table captures valid-time states via a peperiod of validity and two riod timestamp, here as two instant timestamps, VT Begin and specifying the period of VT End, and transaction-time states also via a period timestamp, presence. here as TT Start and TT Stop. Along with the foreign keys, the table is comprised of six columns. Code Fragment 10.1 Create the Prop Owner table. CREATE TABLE Prop_Owner ( customer_number INT, property_number INT, VT_Begin DATE, VT_End DATE, TT_Start TIMESTAMP, TT_Stop TIMESTAMP) 280 CHAPTER TEN : BITEMPORAL TABLES We give the valid timestamps a granularity of day (as a property cannot change owners multiple times in a single day), and the transaction timestamps a granularity of microsecond (to differentiate transactions). We also specify the Customer and Property tables as bitemporal tables. CREATE TABLE Customer ( name CHAR, VT_Begin DATE, VT_End DATE, TT_Start TIMESTAMP, TT_Stop TIMESTAMP) CREATE TABLE Property ( property_number INT, address CHAR, property_type INT, estimated_value INT, VT_Begin DATE, VT_End DATE, TT_Start TIMESTAMP, TT_Stop TIMESTAMP) Since the property ownership relationship is one-to-many, the primary key of the Prop Owner table should consist of only the many side, that is, the property foreign key: property number. As has been emphasized many times, the sequenced semantics is generally the natural choice; what is desired here is to specify property number to be a primary key sequenced in both valid time and transaction time. The state of the table at any day in valid time, as stored at any instant in transaction time, should include at most one row in the table for any particular property, meaning that property has one owner at that valid time, as recorded at that transaction time. So, how do we convert a property number PRIMARY KEY constraint to be sequenced in both valid time and transaction time? Since only current modications are permitted on tables with transaction-time support, including the TT Start column is sufcient (see the explanations on pages 178 and 221). However, arbitrary modications (including sequenced and nonsequenced) are generally permitted on tables with valid-time support; that is true here specically as well. As we saw in Section 5.3 on page 117, it is not sufcient to use either the begin date, the end date, or a combination of the two; instead, an assertion is needed. Leaving the valid timestamps out of the primary key doesn't work either, because the foreign keys plus the transaction start time does not differentiate multiple entries inserted by a single transaction specifying different valid times. Hence, a PRIMARY KEY constraint simply doesn't work in this case. 10.1 DEFINITION 281 Components of Every Clock Every periodic clock, save sundials and clepsydrae, has ve primary components. The rst is a device that will be periodic, termed a resonator. The twisting and untwisting of a string, the back-and-forth of a pendulum, and the vibrating of a crystal are all resonators. The second component is a means of supplying energy to the resonator, so that it doesn't wind down. The escapement provides energy from a falling weight to the twisting of the string and the swinging of a pendulum; a small battery provides energy to a crystal. The energy supply together with the resonator is called an oscillator. The third component is a counting device, such as an escapement or solid-state circuit. The fourth is a transmission, getting the count to the fth component, which is a display, such as the clock's hands. To specify that the property number column constitutes a transaction-time sequenced, valid-time sequenced primary key, we need an assertion. We will apply this assertion at the current transaction Stating that a key on a time; that only current modications are permitted in transbitemporal table is valid-time sequenced requires an assertion. action time will ensure that it holds over all transaction-time states. This is a slight modication of CF-5.14 on page 124. Code Fragment 10.2 property number is a (valid-time sequenced, transaction-time sequenced) primary key for Prop Owner. CREATE ASSERTION P_O_seq_primary_key CHECK (NOT EXISTS (SELECT * FROM Prop_Owner AS P1 WHERE property_number IS NULL OR 1 < (SELECT COUNT(customer_number) FROM Prop_Owner AS P2 WHERE P1.property_number = P2.property_number AND P1.VT_Begin < P2.VT_End AND P2.VT_Begin < P1.VT_End AND P1.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31)) ) While we're at it, we also include a nonsequenced valid-time assertion: that there are no gaps in the valid-time history. Specically, once a property is acquired by a customer, it remains associated with an owner (or sequence of owners) over its existence. As before, we use current transaction time. This is a slight modication of CF-5.22 on page 129. 282 CHAPTER TEN : BITEMPORAL TABLES Code Fragment 10.3 Prop Owner.property number denes a contiguous valid-time history. CREATE ASSERTION P_O_Contiguous_History CHECK (NOT EXISTS (SELECT * FROM Prop_Owner AS P, Prop_Owner AS P2 WHERE P.VT_End < P2.VT_Begin AND P.property_number = P2.property_number AND P.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31 AND NOT EXISTS ( SELECT * FROM Prop_Owner AS P3 WHERE P3.property_number = P.property_number AND (((P3.VT_Begin <= P.VT_End) AND (P.VT_End < P3.VT_End)) OR ((P3.VT_Begin < P2.VT_Begin) AND (P2.VT_Begin <= P3.VT_End))) AND P3.TT_Stop = DATE 9999-12-31)) ) The change made here was to apply the assertion at the current transaction time, which, due to the append-only nature of transaction time, renders it a sequenced transaction-time constraint. 10.2 MODIFICATIONS In Chapter 7 we saw that valid-time state tables admit nine kinds of modications: current, sequenced, and nonsequenced versions of INSERT, DELETE, and UPDATE. Chapter 9 showed that transaction-time state tables are much simpler: only current versions of INSERT, DELETE, and UPDATE are relevant. So, what is the situation with bitemporal tables? It turns out that here again only nine kinds of modications apply, all current in transaction time: valid-time current, validtime sequenced, and valid-time nonsequenced versions of INSERT, DELETE, and UPDATE. Translating modications on bitemporal tables into SQL parallels the translation on valid-time tables given in Chapter 7. In fact, we advocate a two-stage transformation. The rst stage applies those transformations given for valid-time tables. Only then will we consider transaction time, applying a second set of transformations to render a nal sequence of SQL statements that respect the coupled semantics of valid time and transaction time. The mappings themselves are straightforward, albeit somewhat tedious. 10.2 MODIFICATIONS 283 Let's follow the history, over both valid time and transaction time, of a at in Aalborg, at Skovvej 30 for the month of January 1998. This history is quite interesting for illustrating the translation for various kinds of modications. 10.2.1 Current Modications We rst consider current insertion, then current updates, and end with current deletions. Insertions On the 10th of January, this at was purchased by Eva Nielsen. We record this information as a current valid-time, current transaction-time insertion. Code Fragment 10.4 Eva Nielsen buys the at at Skovvej 30 in Aalborg on January 10, 1998. INSERT INTO Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) VALUES (145, 7797, CURRENT_DATE, DATE 9999-12-31, CURRENT_TIMESTAMP, DATE 9999-12-31) This information is valid starting now and was inserted now. We will see that the transaction-time extent of all modications is “now” to “until changed,” which we encode as “forever.” The interplay between valid time and transaction time can be confusing, so it is useful to have a visualization of the information content of a bitemporal table. Figure 10.2 shows the bitemporal time diagram, or simply time diagram, corresponding to the above insertion. In this gure, the horizontal axis tracks transaction time and the vertical axis tracks valid time. Information about a row, or Current insertions require only about multiple rows associated with a primary key value, is dethat the valid and transaction picted as two-dimensional polygonal regions in the diagram. Artimestamps be appropriately rows extending rightward denote “until changed” in transaction specied. time; arrows extending upward denote “forever” in valid time. Here we have but one region, associated with Eva Nielsen, that starts at time 10 (January 10, 1998) in transaction time and extends to “until changed,” and that begins also at time 10 in valid time and extends to “forever.” The arrow pointing upward extends to the largest valid-time value (“forever”); the arrow pointing to the right extends to “now,” that is, it advances day by day to the right (a transaction time in the future is meaningless). 284 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.2 A bitemporal time diagram corresponding to Eva purchasing the at, performed on January 10. Updates On the 15th Peter Olsen buys this at; this legal transaction transfers ownership from Eva to him. The nontemporal expression of this modication is a simple UPDATE. Code Fragment 10.5 Peter Olsen buys the at on January 15, 1998. UPDATE Prop_Owner SET customer_number = 827 WHERE property_number = 7797 Figure 10.3 illustrates how this update impacts the time diagram. The valid-time extent of a current modication is always “now” to “forever,” so from time 15 on, the property is owned by Peter; at the rest of the time, from time 10 to 15, the property was owned by Eva. Both regions extend to the right to “until changed.” This time diagram captures two facts: Eva owning the at and Peter owning the at, each associated with a bitemporal region. This gure captures the evolving information content of the Prop Owner table quite effectively. Consider a transaction time-slice, which returns the valid-time history at a given transaction time. Such a time-slice can be visualized as a vertical line intersecting the x-axis at the given time. At transaction time 5 (January 5), the table has no record of the at being owned by anyone. At transaction time 12, the table records that the at was owned by Eva from January 10 to “forever.” If we 10.2 MODIFICATIONS 285 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.3 A current update: Peter buys the at, performed on January 15. time-traveled back to January 12 and asked for the history of the at, that would be the response. We thought then that Eva owns the at, and that is what the Prop Owner table recorded then. At transaction time 17 the table records that the at was owned by Eva from January 10 to 15, at which time ownership transferred to Peter, who now owns it to “forever.” And that is the history as best known (denoted by the right-pointing arrows); it is what we think is true about the valid-time history. The current update must effect the change in the Prop Owner table from Figure 10.2 to Figure 10.3, via SQL statements that manipulate the explicit columns as well as the timestamp columns. While CF-10.5 consists of but 3 lines, the translation into SQL-92 is involved, ultimately requiring over 30 lines of SQL! However, the translation is mechanical, so with some patience, all will be clear. CF-7.11 on page 186 translated a valid-time current update For modications on bitemporal into three SQL statements, the rst to insert new information valid from “now” until the row ended, the second to terminate tables, the rst stage contends the current row at “now,” and the third to update any rows that with valid time, resulting in a start in the future with the new values. I urge you to revisit that series of SQL statements. code fragment, read the associated commentary, and ensure that you understand it well because the bitemporal version will build on it. In addition to contending with valid time, we also must ensure that the transaction-time extent of the modication is from “now” to “until changed.” One important property of tables with transaction-time support is that they are appendonly (cf. Section 8.10). As such tables capture the state of the stored table over time, 286 CHAPTER TEN : BITEMPORAL TABLES once we have recorded that the state was such and such at a particular time, we can't go back and change that later because we can't change the bits stored on the disk at that prior time. The changes always accumulate in the table with transaction-time support (the one exception is when the table is vacuumed, which as we emphasized on page 270 violates the semantics of the table). The practical ramication is that we never physically delete a row from such a table; the only physical modications allowed Only two kinds of modications are to insert rows into the table and to change the transactionare permitted on bitemporal stop time of a row from “until changed” to “now,” thereby logstate tables: insertions with a ically deleting the row. All nine types of modications allowed transaction time of “now” to on bitemporal tables must be implemented as a combination of “forever,” and updates that set INSERTs with a transaction time of “now” to “until changed” the transaction-stop time to (which is represented with “forever”) and UPDATEs that set the “now.” transaction-stop time to “now.” Any other modication to a bitemporal table will violate its semantics. As mentioned, we utilize a two-stage procedure for translating a temporal modication on a bitemporal table into a series of SQL statements. The rst stage pretends that the table is a valid-time table and uses the mappings elaborated in Chapter 7 for handling modications of such tables. In the second stage, we identify the statements that violate the semantics of transaction time, which basically are all DELETEs and UPDATEs, and further map these statements into combinations of UPDATEs on the transaction-stop time and INSERTs. Finally, we must add a predicate for each correlation name in the statement that selects the most recent transaction-time version; this can be done by simply checking that the transaction-stop time is “until changed.” A modication on a bitemporal table A nontemporal modication is mapped into a modication on a bitemporal table in two stages: The rst transformation assumes that the table only has valid-time support. The second transformation then converts updates and deletions into stylized INSERT and UPDATE statements. A WHERE predicate is added for each correlation name selecting the row(s) current in transaction time. For our rst modication, a current insertion, shown in CF-10.4, we didn't need to invoke this second transformation stage, but most of the other temporal modications will require both stages. 10.2 MODIFICATIONS 287 We now examine the three statements of CF-7.11 on page 186, which effects a current update on a valid-time state table. The rst stage maps the update of CF-10.5 into the following three statements, which parallel the three statements of CF-7.11. Code Fragment 10.6 Peter Olsen buys the at on January 15, 1998, a current update (partial solution, considering only valid time). INSERT INTO Prop_Owner SELECT 827, property_number, CURRENT_DATE, VT_End FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin <= CURRENT_DATE AND VT_End > CURRENT_DATE UPDATE Prop_Owner SET VT_End = CURRENT_DATE WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE UPDATE Prop_Owner SET customer_number = 827 WHERE property_number = 7797 AND VT_Begin > CURRENT_DATE The rst statement in this fragment is an insertion, which is ne, as it upholds the semantics of transaction time. The second statement, which terminates the valid time of the current row at “now,” is an update of a column other than the transaction-stop time. So it must be subsequently mapped (as we'll show shortly) into two SQL statements, one to logically delete the entire row, by setting the transaction-stop time to “now,” and one to insert the row, with a new valid-time stop time of “now.” The third statement, to update any rows that start in the future with new values, must also be subsequently mapped into two SQL statements, an UPDATE and an INSERT. So the second and third statements of CF-10.6 must each be expanded into two statements, yielding a total of ve SQL statements expressing the sequenced version of CF-7.11. There is a further complication in the interplay of two time dimensions, valid time and transaction time. When we were concerned only with valid time, we contended with valid-time periods, lengthening and shortening these periods by altering their beginning and ending instants. Two time dimensions generalize periods to regions in the time diagram, which are considerably more involved than simple one-dimensional periods. Quite intricate shapes can result from a series of bitemporal modications, as we shall see. 288 CHAPTER TEN : BITEMPORAL TABLES In terms of the time diagram, a row with two valid-time instants, VT Begin and VT A pendulum must be hung vertically, making it End, and two transaction-time instants, TT ne for grandfather clocks but impractical for wrist Start and TT Stop, encodes a rectangle in watches. Huygens also had the insight that a spring bitemporal space. Hence, the region in Fighas the same characteristics as a pendulum, but ure 10.2, being a single rectangle, requires is unaffected by its spatial orientation. His spiral but one row to encode—the row inserted spring has been rened into the hairspring that regin CF-10.4. The region associated with Eva ulates the motion of the balance wheel in today's in Figure 10.3 requires two rectangles; the mechanical watches. region associated with Peter needs but one (see Figure 10.4). Due to the semantics of transaction time, regions are often split with vertical lines in time diagrams. The implication is that in this case two new rows will have to be inserted, and the existing row modied, to effect this temporal modication. (This is the visual analog of the requirement, stated earlier, that an UPDATE of a table with transaction-time support must be mapped into an UPDATE only of the transaction-stop time to “now,” and an INSERT with a transaction-start time of “now.”) Returning to the three statements needed to realize a current deletion of a validtime table, we note that the third statement, to update any rows that start in the future, is not strictly required here, as there are no rows concerning this at that start in the future. However, for generality, because your application may indeed Hairspring 30 Valid time 25 20 3 2 15 Peter 1 10 5 5 10 15 20 25 Transaction time 30 Figure 10.4 Splitting a polygonal region into rectangles. 10.2 MODIFICATIONS 289 30 25 Valid time ? Peter 20 15 10 5 5 10 15 20 25 Transaction time 30 Figure 10.5 A current update of a future row. have (valid-time) future rows, we include this statement in our discussion here. Say there was a future row, valid from 20 to 25, with a transaction-stop time of “until changed” (see Figure 10.5). Here the at was owned during these ve days (from January 20 to January 24; recall that we're using an open-ended period) by someone else. A current update, “Peter Olsen buys the at,” has a valid-time extent of “now” to “forever”; this extent includes all of January. So we must logically delete the old row and insert a new row, indicating associating that valid time with Peter. The third statement thus maps into two SQL statements, an INSERT and an UPDATE. In summary, the rst stage maps CF-10.5 to CF-10.6, resulting in three SQL statements. The second stage retains the INSERT statement, but maps each of the two UPDATE statements into an INSERT-UPDATE pair. Five SQL statements result, shown as CF-10.7. You should verify that these statements do not violate the transaction-time semantics: all INSERTs have transaction-time extent of “now” to “until changed,” and all UPDATEs change only the transaction-stop time from “until changed” to “now,” with no other kinds of modications allowed. Code Fragment 10.7 Peter Olsen buys the at on January 15, 1998, a current update. INSERT INTO Prop_Owner SELECT 827, property_number, CURRENT_DATE, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner continued on page 290 290 CHAPTER TEN : BITEMPORAL TABLES continued from page 289 WHERE AND AND AND property_number = 7797 VT_Begin <= CURRENT_DATE VT_End > CURRENT_DATE TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, CURRENT_DATE, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT 827, property_number, VT_Begin, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 The rst UPDATE must occur after the rst two INSERTs; the last UPDATE must occur after the last INSERT. The resulting Prop Owner table (shown in Table 10.1) contains three rows, corresponding to the three rectangles in Figure 10.4. A careful matching of the dates in this table to the time diagram will aid in understanding how a bitemporal state table encodes the regions found in the time diagram. 10.2 MODIFICATIONS 291 Table 10.1 Result of the current insertion. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 9999-12-31 1998-01-15 9999-12-31 1998-01-10 1998-01-15 1998-01-15 1998-01-15 9999-12-31 9999-12-31 Deletions We perform a current deletion on January 20 against Table 10.1. Specically, we nd out that Peter has sold the property to someone else, with the mortgage handled by another mortgage company. From Nykredit's point of view, the property no longer exists as of (a valid time of) January 20. Peter Olsen sells the at on January 20, 1998. Code Fragment 10.8 DELETE FROM Prop_Owner WHERE property_number = 7797 Figure 10.6 shows the resulting time diagram. If we now request the valid-time history as best known, we will learn that Eva owned the at from January 10 to January 15, and Peter owned the at from January 15 to January 20. Note that all prior states are retained. We can still time-travel back to January 18 and request 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.6 A current deletion: Peter sells the at, performed on January 20. 292 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 2 1 15 10 5 5 10 15 20 25 Transaction time 30 Figure 10.7 A current deletion: splitting into rectangles. the valid-time history, which will state that on that day we thought that Peter still owned the at. In Figure 10.3, Peter's region was a rectangle. The current deletion has chopped off the top-right corner, so that the region is now L-shaped. The row associated with Peter in Figure 10.3 denotes a single rectangle. That rectangle must be converted into the two rectangles shown in Figure 10.7. We do so by terminating the existing row (by setting its transaction-stop time to “now”) and by inserting the portion still present, with a valid-end time of “now.” As before, we proceed in two stages. The rst stage pretends that the table is a valid-time state table, mapping the temporal modication to SQL. As in CF-7.8 on page 184, two statements are required. Code Fragment 10.9 Peter Olsen sells the at on January 20, 1998, a current deletion (partial version, considering only valid time). UPDATE Prop_Owner SET VT_End = CURRENT_DATE WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE DELETE FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin >= CURRENT_DATE 10.2 MODIFICATIONS 293 In the rst statement, applied to rows that started in the past and end in the future, the valid-time end date is set to “now.” Deletions on bitemporal tables The second deletes those rows that start now or in the future. follow these same two stages: The second stage further maps those statements that viorst consider valid time, then late the transaction-time semantics into particular forms of UPtransaction time. DATEs and INSERTs. The rst statement (an UPDATE) is mapped into two, an INSERT and an UPDATE; the second (a DELETE) is mapped into an UPDATE. We also add a predicate for each correlation name that checks for the current transaction-time version. Again, you should be convinced that these statements do not violate the semantics of transaction time. Code Fragment 10.10 Peter Olsen sells the at on January 20, 1998, a current deletion. INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, CURRENT_DATE, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin < CURRENT_DATE AND VT_End > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin >= CURRENT_DATE AND TT_Stop = DATE 9999-12-31 We can simplify this by combining the two UPDATEs into one. Code Fragment 10.11 Peter Olsen sells the at on January 20, 1998, a current deletion, simplied version. INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, CURRENT_DATE, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner continued on page 294 294 CHAPTER TEN : BITEMPORAL TABLES Table 10.2 Result of the current deletion. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-15 9999-12-31 1998-01-20 9999-12-31 continued from page 293 WHERE AND AND AND property_number = 7797 VT_Begin < CURRENT_DATE VT_End > CURRENT_DATE TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_End > CURRENT_DATE AND TT_Stop = DATE 9999-12-31 The UPDATE handles both current and future rows. The resulting table (Table 10.2) contains four rows. The third row was terminated at “now,” with the fourth row newly inserted. The modied rows and columns are highlighted with an italic font. In current modications, valid time and transaction time are coupled: the valid time at which the modication takes effect is “now.” Similarly, the transaction time at which the modication is recorded is “now.” Sequenced modications decouple the valid time from the transaction time, allowing the former to be supplied by the user. 10.2.2 Sequenced Modications As we saw in Chapter 7, sequenced modications generalize current modications to apply over a specied period of applicability. For bitemporal tables, the modication is sequenced only on valid time; the modication is always a current modication on transaction time, from “now” to “until changed.” As before, we apply a two-stage transformation, rst considering only the validtime component of the bitemporal table, then further transforming the SQL statements so that they do not violate the semantics of transaction time. The result will be a series of stylized UPDATE and INSERT statements. 10.2 MODIFICATIONS 295 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.8 A sequenced insertion performed on January 23: Eva actually purchased the at on January 3. Insertions Continuing with the Prop Owner table as depicted in Figure 10.6, we consider a sequenced insertion. On January 23, we nd out that Eva had purchased the at not on January 10, but on January 3, a week earlier. So we insert those additional days, to obtain the time diagram shown in Figure 10.8. This insertion is termed a retroactive modication, as the period of applicability (here, January 3 through 10) is before the modication date (here, January 23). Sequenced (and nonsequenced) modications can also be postactive, an example being a promotion that will occur in the future (in valid time). (A valid-end time of “forever” is generally not considered a postactive modication; only the validstart time is considered.) A sequenced modication might even be simultaneously retroactive, postactive, and current, when its period of applicability starts in the past and extends into the future (e.g., a xed-term assignment that started in the past and ends at a designated date in the future). There are two ways to effect the insertion illustrated in Figure 10.8. The easiest is to use a single SQL INSERT statement. Code Fragment 10.12 Eva actually purchased the at on January 3, performed on January 23. INSERT INTO Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) VALUES (145, 7797, DATE 1998-01-03, DATE 1998-01-10, CURRENT_TIMESTAMP, DATE 9999-12-31) 296 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.9 One splitting into rectangles. Table 10.3 Result of the sequenced insertion. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-15 9999-12-31 1998-01-20 9999-12-31 9999-12-31 The period of applicability for the insertion appears as the values of the VT Begin and VT End columns. The region associated One approach to a sequenced with Eva's ownership consists of the three rectangles shown in insertion is to simply insert the Figure 10.9, and the rst, second, and fth rows in Table 10.3. new period of validity, without A second approach is to always split with vertical lines, as regard to how it interacts with shown in Figure 10.10. This is termed transaction-time splitting the period of validity of the because the regions are split into bands of transaction time. (The existing rows. rst approach is then termed valid-time splitting .) In transactiontime splitting, we terminate the current row and insert a new row, with a new period of validity being the union of the original period of validity and the period of applicability, that is, from time 5 to time 15. For this new period, there are four cases, shown in Figure 10.11. In all four cases, the original period of 10.2 MODIFICATIONS 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.10 An alternate splitting into rectangles. Case 1 PV PA Result: Case 2 PV PA Result: Case 3 PV PA Result: Case 4 PV PA Result: PV of row unchanged Figure 10.11 Sequenced insertion cases. 297 298 CHAPTER TEN : BITEMPORAL TABLES validity (PV) overlaps the period of applicability of the insertion (PA). In Case 1, PV starts before PA, with the new period of validity starting from the start of PV to the end of PA. This case applies to the Eva row in this example. In Case 2, the PV starts after PA. In Case 3, the PV is contained in PA, and the new PV is PA. In Case 4, the PA is contained in PV, and the PV need not be changed. In the following SQL code, we use a CASE statement to compute the new period of validity. Rows are affected if their PV overlaps the PA but does not contain the PA. Such rows are logically deleted by setting the transaction-stop time to “now,” then inserted with the new PV. If there are no rows whose PV overlaps the PA, the insertion is performed as before. Code Fragment 10.13 Eva actually purchased the at on January 3, with transactiontime splitting. -- Do normal insert if there are no overlapping rows that -- do not contain the period of applicability INSERT INTO Prop_Owner SELECT 145, 7797, DATE 1998-01-03, DATE 1998-01-10, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM DUAL WHERE NOT EXISTS (SELECT * FROM Prop_Owner WHERE customer_number = 145 AND property_number = 7797 AND DATE 1998-01-03 < VT_End AND VT_Begin < DATE 1998-01-10 AND NOT (VT_Begin < DATE 1998-01-03 AND DATE 1998-01-10 < VT_End) AND TT_Stop = DATE 9999-12-31) -- If there is an overlap, extend it, unless PA is contained in PV INSERT INTO Prop_Owner SELECT customer_number, property_number, CASE WHEN DATE 1998-01-03 < VT_Begin THEN DATE 1998-01-03 ELSE VT_Begin END, CASE WHEN DATE 1998-01-10 < VT_End THEN VT_End ELSE DATE 1998-01-10 END, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE customer_number = 145 AND property_number = 7797 AND DATE 1998-01-03 < VT_End AND VT_Begin < DATE 1998-01-10 AND NOT (VT_Begin < DATE 1998-01-03 10.2 MODIFICATIONS 299 AND DATE 1998-01-10 < VT_End) AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE customer_number = 145 AND property_number = 7797 AND DATE 1998-01-03 < VT_End AND VT_Begin < DATE 1998-01-10 AND NOT (VT_Begin < DATE 1998-01-03 AND DATE 1998-01-10 < VT_End) AND TT_Stop = DATE 9999-12-31 (Note the use of a DUAL table, as discussed on page 138.) The three statements can be in any order, as they are disjoint. This approach minimizes the representation, that is, the number of rows in the Prop Owner table (though in this particular example, there is no difference). As shown in Table 10.4, this table still has ve rows (cf. Table 10.3), but here the second row was logically deleted. The drawback of this optimized approach is substantial complexity and execution cost for the temporal insertion. For the remainder of the modications, we will not attempt to minimize the representation, but note here that doing so is always an option to be considered. A second approach to a sequenced insertion on a bitemporal table computes a new period of validity. Deletions We learn on January 26 that Eva bought the at not on January 10, as initially thought, nor on January 3, as later corrected, but on January 5. This requires a sequenced version of the following deletion: Table 10.4 Result of a second approach to the sequenced insertion. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-15 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-15 1998-01-23 1998-01-20 9999-12-31 9999-12-31 300 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 30 Transaction time Figure 10.12 A sequenced deletion performed on January 26: Eva actually purchased the at on January 5. Code Fragment 10.14 Eva actually purchased the at on January 5 (nontemporal version). DELETE FROM Prop_Owner WHERE property_number = 7977 We specify a period of applicability of January 3 through 5, with the result shown in the time diagram in Figure 10.12. We need to terminate the current row and insert a new row, with a smaller period of validity. As in the valid-time sequenced deletion of CF-7.16 on page 191, there are four cases, depicted in Figure 7.2. The valid-time sequenced deletion was transformed into four SQL statements. Valid-time sequenced deletion Insert the old values from the end of the period of applicability to the end of the period of validity of the original row. Update the end date to end at the beginning of the period of applicability. Update the start date to begin at the end of the period of applicability. Delete entirely rows that are covered by the period of applicability. 10.2 MODIFICATIONS 301 When transaction time is considered (recall that all modications are current in transaction time), updates turn into a combination of terminating the row with a transaction-stop time of “now” and inSequenced deletions on serting a row with a transaction-start time of “now” and with valid-time tables require some the new valid-time date. This concerns both the second and the four SQL statements; when third statements. Logically deleting a row turns into an UPDATE, mapped to bitemporal tables, a when transaction time is considered. total of six statements are In summary, we took CF-7.16, applied it to the Prop Owner required. table, being careful to utilize a period of applicability of [199801-02 - 1998-01-05), then applied the second stage of the transformation, to obtain six SQL statements, all consistent with transaction-time semantics. We admit that in this particular situation, the rst two statements sufce to effect the deletion. However, our previous explanation and provided code cover all situations. Code Fragment 10.15 Eva actually purchased the at on January 5. INSERT INTO Prop_Owner SELECT customer_number, property_number, DATE 1998-01-05, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin < DATE 1998-01-02 AND VT_End > DATE 1998-01-05 AND TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, DATE 1998-01-02, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin < DATE 1998-01-02 AND VT_End > DATE 1998-01-02 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin < DATE 1998-01-02 AND VT_End > DATE 1998-01-02 AND TT_Stop = DATE 9999-12-31 continued on page 302 302 CHAPTER TEN : BITEMPORAL TABLES Table 10.5 Result of the sequenced deletion. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 7797 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-15 9999-12-31 1998-01-20 9999-12-31 1998-01-26 9999-12-31 continued from page 301 INSERT INTO Prop_Owner SELECT customer_number, property_number, DATE 1998-01-05, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin < DATE 1998-01-05 AND VT_End >= DATE 1998-01-05 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin < DATE 1998-01-05 AND VT_End >= DATE 1998-01-05 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND VT_Begin >= DATE 1998-01-02 AND VT_End <= DATE 1998-01-05 AND TT_Stop = DATE 9999-12-31 Starting from Table 10.3, the sequenced deletion of CF-10.15 results in Table 10.5. Updates We learn on January 28 that Peter bought the at on January 12, not January 15 as previously thought. This requires a sequenced version of the following update. 10.2 MODIFICATIONS 303 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.13 A sequenced update performed on January 28: Peter actually purchased the at on January 12. Code Fragment 10.16 Peter actually purchased the at on January 12 (nontemporal version). UPDATE Prop_Owner SET customer_number = 145 WHERE property_number = 7797 AND customer_number <> 145 Table 10.6 Result of the sequenced update. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 145 827 7797 7797 7797 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 1998-01-12 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-20 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-28 1998-01-15 1998-01-28 1998-01-20 1998-01-28 1998-01-26 1998-01-28 9999-12-31 9999-12-31 304 CHAPTER TEN : BITEMPORAL TABLES This update requires a period of applicability of January 12 through 15, setting the customer number to 145, which results in the time diagram in Figure 10.13. Effectively, the ownership must be transferred from Eva to Peter for those three days, resulting in Table 10.6. The two-stage transformation, rst valid time and then transaction time, applies here as well. We modify CF-7.18 on page 194 to apply to Prop Owner and to utilize a period of applicability of [1998-01-12 - 1998-01-15), then contend with transaction time in the second stage. INSERTs remain; UPDATEs are mapped to a pair of INSERT and UPDATE. Code Fragment 10.17 Peter actually purchased the at on January 12. INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, DATE 1998-01-12, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-12 AND VT_End > DATE 1998-01-12 AND TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT customer_number, property_number, DATE 1998-01-15, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-15 AND VT_End > DATE 1998-01-15 AND TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT 145, property_number, VT_Begin, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-15 AND VT_End > DATE 1998-01-12 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 199801-15 AND VT_End > DATE 1998-01-12 AND TT_Stop = DATE 9999-12-31 10.2 MODIFICATIONS 305 INSERT INTO Prop_Owner SELECT customer_number, property_number, DATE 1998-01-12, VT_End, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-12 AND VT_End > DATE 1998-01-12 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-12 AND VT_End > DATE 1998-01-12 AND TT_Stop = DATE 9999-12-31 INSERT INTO Prop_Owner SELECT customer_number, property_number, VT_Begin, DATE 1998-01-15, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM Prop_Owner WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-15 AND VT_End > DATE 1998-01-15 AND TT_Stop = DATE 9999-12-31 UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE property_number = 7797 AND customer_number <> 145 AND VT_Begin < DATE 1998-01-15 AND VT_End > DATE 1998-01-15 AND TT_Stop = DATE 9999-12-31 Sequenced updates require applying the same two-stage transformation process, resulting in some eight SQL statements to implement a single sequenced update. 10.2.3 While this series of statements is quite intimidating, the two stages employed—that of mapping from the initial sequenced update to the rst set of ve statements, taking the validtime component into consideration, as discussed in Chapter 7, then mapping into the eight statements shown here, taking the transaction-time component into consideration—are largely mechanical and more tedious than conceptually challenging. Nonsequenced Modications We saw before that no mapping was required for nonsequenced modications on valid-time state tables; such statements treat the (valid) timestamps identically to the other columns. When considering the transaction timestamps, we just perform the second-stage mapping discussed above. 306 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.14 A nonsequenced deletion performed on January 30: Delete all records of exactly one-week duration. As an example, consider the modication “Delete all records with a valid-time duration of exactly one week.” This modication is clearly (valid-time) nonsequenced: (1) it depends heavily on the representation, looking for rows with a particular kind of valid timestamp, (2) it does not apply on a per Nonsequenced modications are instant basis, and (3) it mentions “records,” that is, the recorded information, rather than “reality.” The result of this deletion, initially complex to write, but evaluated on the 30th, is shown in Figure 10.14. require no subsequent DELETEs are mapped in the second stage into an UPDATE transformations. on the transaction-stop time, so one statement sufces for nonsequenced deletions on bitemporal tables. Code Fragment 10.18 Delete all records with a valid-time duration of exactly one week. UPDATE Prop_Owner SET TT_Stop = CURRENT_TIMESTAMP WHERE (VT_End - VT_Begin DAY) = INTERVAL 7 DAY AND TT_Stop = DATE 9999-12-31 The result is Table 10.7. Now that we have a populated bitemporal table, we can discuss bitemporal queries. 10.3 QUERIES 307 Table 10.7 After a nonsequenced deletion. 10.3 customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 145 827 7797 7797 7797 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 1998-01-12 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-20 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-28 1998-01-15 1998-01-28 1998-01-20 1998-01-28 1998-01-26 1998-01-28 1998-01-30 9999-12-31 QUERIES We rst consider a restricted class of queries, time-slice queries, then move on to the full spectrum of possible bitemporal queries. 10.3.1 Time-Slice Queries A common query or view over the valid-time state table of Chapter 6 was to capture the state of the enterprise at some point in the past (or future). This query was termed a valid-time time-slice. For the tracking log of Chapter 8, we sought to reconstruct the state of the monitored table as of a date in the past; that query was termed a transaction time-slice. As a bitemporal table captures valid and transaction time, both time-slice variants are appropriate on such tables. Time-slices are useful also in understanding the information A transaction time-slice query content of a bitemporal table. A transaction time-slice of a bitemcorresponds to a vertical slice in poral table takes as input a transaction-time instant and results the time diagram. in a valid-time state table that was present in the database at that specied time. Code Fragment 10.19 Give the history of owners of the at at Skovvej 30 in Aalborg as of January 1, 1998. SELECT customer_number, VT_Begin, VT_End FROM Prop_Owner WHERE property_number = 7797 AND TT_Start <= DATE 1998-01-01 AND DATE 1998-01-01 < TT_Stop Applying this time-slice to Table 10.7, whose time diagram appears in Figure 10.14, results in an empty table, as no history was yet known about that property. 308 CHAPTER TEN : BITEMPORAL TABLES Taking a transaction time-slice as of January 14 results in a history with one entry: customer number VT Begin VT End 145 1998-01-10 9999-12-31 On January 14, we thought that Eva was the current owner of that property. We now know that Peter purchased the property on January 12, and that Eva never owned the property at all on January 14, but that is 20-20 hindsight. The information we had on January 14 indicated that Eva bought the property on the 10th, and still owns it. The time-slice as of January 18 tells a different story: customer number VT Begin VT End 145 827 1998-01-10 1998-01-15 1998-01-15 9999-12-31 On January 18 we thought that Eva had purchased the at on January 10 and sold it to Peter, who now owns it. A transaction time-slice can be visualized on the time diagram as a vertical line situated at the specied date. This line gives the validtime history of the enterprise that was stored in the table on that date. Figure 10.15 illustrates this transaction time-slice. Continuing, we take a transaction time-slice as of January 29: customer number VT Begin VT End 145 827 1998-01-05 1998-01-12 1998-01-12 1998-01-20 On January 29, we thought that Eva had purchased the at on January 5 and sold it to Peter on January 12, who sold the property to someone else on January 20. Finally, taking the current transaction time-slice, Code Fragment 10.20 Give the history of owners of the at at Skovvej 30 in Aalborg as best known. SELECT customer_number, VT_Begin, VT_End FROM Prop_Owner WHERE property_number = 7797 AND TT_Stop = DATE 9999-12-31 yields the following result: 10.3 customer number VT Begin VT End 827 1998-01-12 1998-01-20 QUERIES 309 Only Peter ever had ownership of the property, since all records with a valid-time duration of exactly one week were deleted. Peter's ownership was for all of eight days, January 12 to January 20. We can also cut the pie (or, more accurately, the time diagram) horizontally. A valid time-slice of a bitemporal table takes A valid time-slice query corresponds to a horizontal slice as input a valid-time instant and results in a transaction-time in the time diagram, resulting in state table capturing when information concerning that specied valid time was recorded in the database. A valid time-slice is a transaction-time state table. expressed in SQL similarly to the transaction time-slice. When was information about the owners of the at at Skovvej 30 in Aalborg on January 4, 1998, recorded in the Prop Owner table? Code Fragment 10.21 SELECT customer_number, TT_Start, TT_Stop FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin <= DATE 1998-01-04 AND DATE 1998-01-04 < VT_End 30 Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 30 tt = 18 Transaction time Figure 10.15 A transaction time-slice as of January 18. CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 310 25 20 Peter 15 Eva vt = 13 10 5 5 10 15 20 25 Transaction time 30 Figure 10.16 A valid time-slice on January 13. Table 10.8 The valid time-slice on January 13. customer number TT Start TT Stop 145 145 827 1998-01-10 1998-01-15 1998-01-28 1998-01-15 1998-01-28 9999-12-31 Applying this time-slice to Table 10.7, whose time diagram appears in Figure 10.14, results in one row, customer number TT Start TT Stop 145 1998-01-23 1998-01-26 indicating that this information—that the property was owned by Eva on January 4—was inserted into the table on January 26 and subsequently deleted, as it was found to be incorrect, on January 26. The valid time-slice on January 13 is more interesting. Such a time-slice can be visualized as the horizontal line shown in Figure 10.16. This time-slice results in Table 10.8. While the horizontal line in Figure 10.16 intersects two regions, three rows result from the time-slice. This has to do with the way that the regions in the time diagram are sliced up into rectangles, each associated with a row in the Prop Owner table. 10.3 QUERIES 311 30 Valid time 25 1 20 15 3 Peter 4 Eva vt = 13 8 2 10 5 6 7 5 5 10 15 20 25 Transaction time 30 Figure 10.17 The underlying rectangles encoding the bitemporal regions. Examine the rectangles in the time diagram in Figure 10.17, which indicates the rectangle associated with each of the eight rows of Table 10.7. This gure makes it clear why the time-slice on January 13 returned three rows: rows 1, 2, and 8. A bitemporal time-slice takes as input two instants, a valid-time and a transaction-time instant, and results in a snapshot state A bitemporal time-slice query of the information regarding the enterprise at that valid time, extracts a single point from a as recorded in the database at that transaction time. This query, time diagram, resulting in a CF-10.22, is illustrated in Figure 10.18. The result is the facts snapshot table. located at the intersection of the two lines, in this case, Eva. customer number 145 Code Fragment 10.22 Give the owner of the at at Skovvej 30 in Aalborg on January 13 as stored in the Prop Owner table on January 18. SELECT customer_number FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin <= DATE 1998-01-13 AND DATE 1998-01-13 < VT_End AND TT_Start <= DATE 1998-01-18 AND DATE 1998-01-18 < TT_Stop 312 CHAPTER TEN : BITEMPORAL TABLES 30 Valid time 25 20 Peter 15 Eva vt = 13 10 5 5 10 15 20 25 30 tt = 18 Transaction time Figure 10.18 A bitemporal time-slice on a valid time of January 13 and as of a transaction time of January 18. The current bitemporal time-slice uses “now” for both input instants. Code Fragment 10.23 Give the owner of the at at Skovvej 30 in Aalborg today as best known. SELECT customer_number FROM Prop_Owner WHERE property_number = 7797 AND VT_Begin <= CURRENT_DATE AND CURRENT_DATE < VT_End AND TT_Stop = DATE 9999-12-31 10.3.2 The Spectrum of Bitemporal Queries Chapter 6 discussed the three major kinds of queries on valid-time state tables: current (“valid now”), sequenced (“history of”), and nonsequenced (“at some time”). Chapter 8 showed that there were three analogous kinds of queries on transactiontime state tables: current (“as best known”), sequenced (“when was it recorded”), and nonsequenced (e.g., “when was . . . erroneously changed”). As a bitemporal table includes both valid-time and transaction-time support, and as these two types of time are orthogonal, it turns out that all nine combinations are possible on such tables. 10.3 QUERIES 313 30 Peter Valid time 25 20 Peter 15 Eva 10 5 5 10 15 20 25 Transaction time 30 Figure 10.19 A sequenced insertion, performed on January 31, 1998: Peter bought another at on January 15. To illustrate, we will take a nontemporal query and provide all the variations of that query. Before doing that, we add one more row to the Prop Owner table. Code Fragment 10.24 Peter Olsen bought another at, at Bygaden 4 in Aalborg on January 15, 1998; this was recorded on January 31, 1998. INSERT INTO Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) VALUES (827, 3621, DATE 1998-01-15, DATE 9999-12-31, CURRENT_TIMESTAMP, DATE 9999-12-31) Overlaying this information on the time diagram, shown in Figure 10.19, we see that for ve days Peter owned two properties, at Bygaden and Skovvej; he sold the Skovvej property on January 20, but retains the Bygaden property. We start with a nontemporal query, a simple equijoin, pretending that the Prop Owner table is a snapshot table. Code Fragment 10.25 What properties are owned by the customer who owns property 7797? SELECT P2.property_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number 314 CHAPTER TEN : BITEMPORAL TABLES Table 10.9 The bitemporal state illustrated in Figure 10.19. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 145 827 827 7797 7797 7797 7797 7797 7797 7797 7797 3621 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 1998-01-12 1998-01-15 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-20 9999-12-31 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-28 1998-01-31 1998-01-15 1998-01-28 1998-01-20 1998-01-28 1998-01-26 1998-01-28 1998-01-30 9999-12-31 9999-12-31 We now enumerate the nine kinds of bitemporal queries that are analogous to this nontemporal query, applying each on the state illustrated in Figure 10.19 and given in tabular form in Table 10.9. Case 1 Valid-time current and transaction-time current Code Fragment 10.26 What properties are owned by the customer who owns property 7797, as best known? SELECT P2.property_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P1.VT_End AND P1.TT_Stop = DATE 9999-12-31 AND P2.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P2.VT_End AND P2.TT_Stop = DATE 9999-12-31 Current in valid time is implemented by requiring that the period of validity overlap “now”; current in transaction time is implemented by requiring a transactionstop time of “until changed.” The result, a snapshot table, is in this case the empty table because now, as best known, no one owns property 7797. (Peter owned it for some nine days in January, but doesn't own it now.) 10.3 Case 2 QUERIES 315 Valid-time sequenced and transaction-time current Code Fragment 10.27 What properties are or were owned by the customer who owned at the same time property 7797, as best known? SELECT P2.property_number, CASE WHEN DATE P1.VT_Begin < P2.VT_Begin THEN P2.VT_Begin ELSE P1.VT_Begin END AS VT_Begin, CASE WHEN DATE P1.VT_End < P2.VT_End THEN P1.VT_End ELSE P2.VT_End END AS VT_End, FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin < P2.VT_End AND P2.VT_Begin < P1.VT_End AND P1.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31 Sequenced in valid time is implemented by selecting the overlap of the periods of validity, when the underlying rows were both valid (compare with CF-6.12 on page 152). The result, a valid-time state table, is the following: property number VT Begin VT End 3621 1998-01-15 1998-01-20 For those ve days in January, Peter owned both properties. Case 3 Valid-time nonsequenced and transaction-time current Code Fragment 10.28 What properties were owned by the customer who owned at any time property 7797, as best known? SELECT P2.property_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31 Nonsequenced in valid time is implemented by ignoring the valid timestamps. The result, a snapshot table, is the following: property number 3621 316 CHAPTER TEN : BITEMPORAL TABLES Peter owned both properties. While in this case there was a time when Peter owned both properties simultaneously, the query does not require that. Even if Peter had bought the second property on a valid time of January 31, that property would still be returned by this query. Case 4 Valid-time current and transaction-time sequenced Code Fragment 10.29 What properties did we think are owned by the customer who owns property 7797? SELECT P2.property_number, CASE WHEN DATE P1.TT_Start < P2.TT_Start THEN P2.TT_Start ELSE P1.TT_Start END AS Recorded_Start, CASE WHEN DATE P1.TT_Stop < P2.TT_Stop THEN P1.TT_Stop ELSE P2.TT_Stop END AS Recorded_Stop FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P1.VT_End AND P2.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P2.VT_End AND P1.TT_Start < P2.TT_Stop AND P2.TT_Start < P1.TT_Stop Sequenced in transaction time is implemented identically to sequenced in valid time: by selecting the overlap of the periods of presence, when the underlying rows were both present. As emphasized on page 260, the result of a transaction-time sequenced query is not a transaction-time state table. While the result does indicate what was recorded in the Prop Owner table, it itself was not in existence until the query was performed. We thus use Recorded Start and Recorded Stop column names to highlight this distinction. The result, a snapshot table with two additional timestamp columns, is the empty table because there was no time in which we thought that Peter currently owns both properties. Case 5 Valid-time sequenced and transaction-time sequenced Code Fragment 10.30 When did we think that some property, at some time, was owned by the customer who owned at the same time property 7797? SELECT P2.property_number, CASE WHEN DATE P1.VT_Begin < P2.VT_Begin THEN P2.VT_Begin ELSE P1.VT_Begin END AS VT_Begin, CASE WHEN DATE P1.VT_End < P2.VT_End THEN P1.VT_End ELSE P2.VT_End END AS VT_End, 10.3 QUERIES 317 30 Valid time 25 20 15 10 5 5 10 15 20 25 Transaction time 30 Figure 10.20 A query sequenced in both valid time and transaction time, computing the intersection of two rectangles. CASE WHEN DATE P1.TT_Start < P2.TT_Start THEN P2.TT_Start ELSE P1.TT_Start END AS Recorded_Start, CASE WHEN DATE P1.TT_Stop < P2.TT_Stop THEN P1.TT_Stop ELSE P2.TT_Stop END AS Recorded_Stop FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin < P2.VT_End AND P2.VT_Begin < P1.VT_End AND P1.TT_Start < P2.TT_Stop AND P2.TT_Start < P1.TT_Stop Here we have sequenced in both valid time and transaction time. This is the most involved of all the queries, but the parallel between valid time and transaction time should be apparent in the above query. We must compute the overlap of the underlying rectangles, with the result being a valid-time state table with additional Recorded timestamp columns. Figure 10.20 shows the two rectangles that are involved (the last row of Table 10.7 and the row inserted by CF-10.24), and the overlap that is computed. One row results: property number VT Begin VT End Recorded Start Recorded Stop 3621 1998-01-15 1998-01-20 1998-01-31 9999-12-31 318 CHAPTER TEN : BITEMPORAL TABLES For those ve days in January, Peter owned both properties. That information was recorded on January 31 and is still thought to be true (a transaction-stop time of “until changed”). Case 6 Valid-time nonsequenced and transaction-time sequenced Code Fragment 10.31 When did we think that some property, at some time, was owned by the customer who owned at any time property 7797? SELECT P2.property_number, CASE WHEN DATE P1.TT_Start < P2.TT_Start THEN P2.TT_Start ELSE P1.TT_Start END AS Recorded_Start, CASE WHEN DATE P1.TT_Stop < P2.TT_Stop THEN P1.TT_Stop ELSE P2.TT_Stop END AS Recorded_Stop FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.TT_Start < P2.TT_Stop AND P2.TT_Start < P1.TT_Stop As before, nonsequenced in valid time is implemented by ignoring the valid timestamps. The result, a snapshot table with additional timestamp columns, is the following: property number Recorded Start Recorded Stop 3621 1998-01-31 9999-12-31 From January 31 on, we thought that Peter had owned those two properties, perhaps not simultaneously. Case 7 Valid-time current and transaction-time nonsequenced Code Fragment 10.32 When was it recorded that a property is owned by the customer who owns property 7797? SELECT P2.property_number, P2.TT_Start AS Recorded_Start FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P1.VT_End AND P2.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P2.VT_End AND P1.TT_Start <= P2.TT_Start AND P2.TT_Start < P1.TT_Stop 10.3 QUERIES 319 Nonsequenced in transaction time is implemented by not testing for full overlap in transaction time (sequenced) and by not testing the transaction-stop time for “until changed” (current). The result, a snapshot table, is empty because we never thought that Peter currently owns two properties. Case 8 Valid-time sequenced and transaction-time nonsequenced Code Fragment 10.33 When was it recorded that a property is or was owned by the customer who owned at the same time property 7797? SELECT P2.property_number, CASE WHEN DATE P1.VT_Begin < P2.VT_Begin THEN P2.VT_Begin ELSE P1.VT_Begin END AS VT_Begin, CASE WHEN DATE P1.VT_End < P2.VT_End THEN P1.VT_End ELSE P2.VT_End END AS VT_End, P2.TT_Start AS Recorded_Start FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin < P2.VT_End AND P2.VT_Begin < P1.VT_End AND P1.TT_Start <= P2.TT_Start AND P2.TT_Start < P1.TT_Stop This query is similar to valid-time sequenced/transaction-time current (CF-10.27), with a different predicate for transaction time. The result, a valid-time state table with an additional timestamp column, is the following: property number VT Begin VT End Recorded Start 3621 1998-01-15 1998-01-20 1998-01-31 For those ve days in January, Peter owned both properties; this information was recorded on January 31. Case 9 Valid-time nonsequenced and transaction-time nonsequenced Code Fragment 10.34 When was it recorded that a property was owned by the customer who owned at some time property 7797? SELECT P2.property_number, P2.TT_Start AS Recorded_Start FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.TT_Start <= P2.TT_Start AND P2.TT_Start < P1.TT_Stop 320 CHAPTER TEN : BITEMPORAL TABLES Note how short the FROM list and WHERE clause are. The result, a snapshot table with an additional timestamp column, is the following: property number Recorded Start 3621 1998-01-31 The two main points of this exercise are that all combinations do make sense, and all can be composed by considering valid time and transaction time separately.    For current queries, just add a predicate to the WHERE clause restricting overlap with “now”; for transaction time, this is easiest done by requiring the transaction-stop time to be “until changed.” For sequenced queries, the target list computes a new timestamp by taking the overlap of the two underlying timestamps (for the temporal join considered here); the WHERE clause must ensure that the overlap exists. Other kinds of sequenced queries require different approaches, as discussed in Section 6.3. For nonsequenced queries, nothing in the WHERE clause is needed. Depending on the query, the target list may or may not need to include one or both of the timestamps. Current in valid time translates in English to “at now”; sequenced translates to “at the same time”; and nonsequenced translates to “at any time.” Current in transaction time translates to “as best All combinations of current, known”; sequenced translates to “when did we think”; and nonsequenced, and nonsequenced sequenced translates to “when was it recorded” or “when was it over valid time and transaction corrected.” time are possible and sensible. Of these nine types of queries, a few are more prevalent. The most common is the current/current queries, “now, as best Current/current queries are known.” These queries correspond to queries on the nontemcommon and can be easily poral version of the table. (The following queries also utilize stated in SQL via currency the Customer and Property tables, corresponding to the cuspredicates. tomer and property entities of the entity-relationship diagram in Figure 10.1; we assume that these two tables are also bitemporal.) Code Fragment 10.35 What is the estimated value of the property at Bygaden 4? SELECT estimated_value FROM Property AS P WHERE P.address = Bygaden 4 AND P.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P.VT_End AND P.TT_Stop = DATE 9999-12-31 10.3 QUERIES 321 Minutes, Seconds, and Jifes We've seen (page 22) that the night was partitioned into 12 hours corresponding to the 12 signs of the zodiac, and then the day was similarly ascribed to 12 hours, and hence an hour was eventually dened as 1/24 of a day. But why are there 60 minutes in an hour and 60 seconds in a minute? King Alfonso X (the Wise) of Castille in the 13th century gathered together Arabic, Jewish, and Christian scholars to publish scientic works, including the Alphonsine Tables, which were arguably the most important astonomical charts of the late Middle Ages. These tables consistently use the sex- agesimal division, in which hours (and days, and degrees of arcs) are divided into minutes, seconds, and “terciae.” We can detect the etymology of “minute” from Latin minutus, or small, and “second” from Latin secundus. A sixtieth of a second should then be properly called a tercia, but instead Unix programmers have dubbed this unit a “jiffy,” based on the fact that in the United States and Canada, computer clocks in the 1970s were incremented by 60-cycle power; in most other countries there are 50 jifes to a second, due to their 50-cycle power. Current/current queries return a snapshot result. The last two lines of the WHERE clause select the current state in both valid time and transaction time. Code Fragment 10.36 Who owns the property at Bygaden 4? SELECT name FROM Prop_Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property_number = PO.property_number AND C.customer_number = PO.customer_number AND PO.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < PO.VT_End AND PO.TT_Stop = DATE 9999-12-31 AND C.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < C.VT_End AND C.TT_Stop = DATE 9999-12-31 AND P.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P.VT_End AND P.TT_Stop = DATE 9999-12-31 Although this is a three-way join between bitemporal tables, the fact that it is a current/current query means that only the Sequenced/current queries allow you to probe the history as WHERE clause is affected. Perhaps the next most common kind of query is a sequenced/ best known. current query, “history, as best known.” These queries ignore transaction time and return a valid-time state table. Sequenced/current queries over one table are simple to specify. 322 CHAPTER TEN : BITEMPORAL TABLES Code Fragment 10.37 How has the estimated value of the property at Bygaden 4 varied over time? SELECT estimated_value, VT_Begin, VT_End FROM Property AS P WHERE P.address = Bygaden 4 AND P.TT_Stop = DATE 9999-12-31 Sequenced joins require more work. Code Fragment 10.38 Who has owned the property at Bygaden 4? SELECT name, GREATEST(PO.VT_Begin, C.VT_Begin, P.VT_Begin), LEAST(PO.VT_End, C.VT_End, P.VT_End) FROM Prop_Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property_number = PO.property_number AND C.customer_number = PO.customer_number AND GREATEST(PO.VT_Begin, C.VT_Begin, P.VT_Begin) < LEAST(PO.VT_End, C.VT_End, P.VT_End) AND PO.TT_Stop = DATE 9999-12-31 AND C.TT_Stop = DATE 9999-12-31 AND P.TT_Stop = DATE 9999-12-31 Here we use Oracle's GREATEST and LEAST functions to compute the intersection of the periods of validity of the three underlying rows. A (somewhat complex) CASE expression could be substituted for each. Transaction time is supported in the Prop Owner table to track the changes and to correct errors. A common query searches for the transaction that stored the current information in valid time. This is a current/nonsequenced query. Current/nonsequenced queries concern incorrectly stored information about now. Code Fragment 10.39 When was the estimated value for the property at Bygaden 4 stored? SELECT estimated_value, TT_Start AS Recorded_Start FROM Property WHERE address = Bygaden 4 AND VT_Begin <= CURRENT_DATE AND CURRENT_DATE < VT_End This query will return a snapshot table giving one or more estimated values, along with the date of the transaction recording that value. Sequenced/nonsequenced queries allow you to determine when invalid information about the history was recorded. 10.4 Code Fragment 10.40 INTEGRITY CONSTRAINTS 323 Who has owned the property at Bygaden 4, and when was this information recorded? SELECT name, GREATEST(PO.VT_Begin, C.VT_Begin, P.VT_Begin) AS VT_Begin, LEAST(PO.VT_End, C.VT_End, P.VT_End) AS VT_End, PO.TT_Start AS PO_Recorded, C.TT_Start AS C_Recorded, P.TT_Start AS P_Recorded_Start FROM Prop_Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property_number = PO.property_number AND C.customer_number = PO.customer_number AND GREATEST(PO.VT_Begin, C.VT_Begin, P.VT_Begin) < LEAST(PO.VT_End, C.VT_End, P.VT_End) AND GREATEST(PO.TT_Start, C.TT_Start, P.TT_Start) < LEAST(PO.TT_Stop, C.TT_Stop, P.TT_Stop) This returns a valid-time state table, with three additional columns stating when that information was recorded in the underlying tables. Subsequent queries could then isolate the identied problem. Finally, nonsequenced/nonsequenced queries can probe the interaction between valid time and transaction time, identifying, for example, retroactive changes (where the change concerned the past) and postactive changes (where the change concerned the future). Nonsequenced/nonsequenced queries tease out the interaction between valid time and transaction time. Code Fragment 10.41 List all retroactive changes made to the Prop Owner table. SELECT customer_number, property_number, VT_Begin, VT_End, TT_Start AS Recorded_Start FROM Prop_Owner WHERE VT_Begin < TT_Start This returns the valid-time state table in Table 10.10, indicating that many of the modications were retroactive. 10.4 INTEGRITY CONSTRAINTS An integrity constraint can be implemented by rst writing a SELECT statement, then embedding it in a CHECK constraint. There is a strong connection between queries and integrity constraints (here, we are considering general integrity constraints, not just the particular ones, such as uniqueness and key constraints, accorded specic language constructs in SQL). An integrity constraint of the form “it must be the case that . . .” can be transformed into a query of the form “select those rows such that . . . is false”; this query can then be inserted into a check constraint of the form CHECK NOT EXISTS. 324 CHAPTER TEN : BITEMPORAL TABLES Implementing an integrity constraint State the constraint as a SELECT that returns offending rows. Create a CHECK constraint that requires that those rows not exist. As a (nontemporal) example, consider the integrity constraint “a customer who owns property 7797 shall own no other property.” (Admittedly, this is a rather unusual integrity constraint, but it will be clear momentarily why we use this particular constraint.) We rst transform this into a query. Code Fragment 10.42 Select those customers who own property 7797 and another property. SELECT P2.customer_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number We then insert this into a NOT EXISTS. Code Fragment 10.43 A customer who owns property 7797 shall own no other property. CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT P2.customer_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number)) Table 10.10 All retroactive changes made to the Prop Owner table. customer number property number VT Begin VT End Recorded Start 145 827 145 145 145 827 827 7797 7797 7797 7797 7797 7797 3621 1998-01-10 1998-01-15 1998-01-03 1998-01-05 1998-01-05 1998-01-12 1998-01-15 1998-01-15 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-20 9999-12-31 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-28 1998-01-31 10.4 INTEGRITY CONSTRAINTS 325 What does this have to do with bitemporal tables? Well, just as there are many kinds of bitemporal queries (nine, to be exact), there are many kinds of bitemporal integrity constraints. We give three to illustrate the correspondence. The rst is a current/current constraint. Code Fragment 10.44 A customer who owns property 7797 shall own no other property. CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT P2.property_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P1.VT_End AND P1.TT_Stop = DATE 9999-12-31 AND P2.VT_Begin <= CURRENT_DATE AND CURRENT_DATE < P2.VT_End AND P2.TT_Stop = DATE 9999-12-31 )) You may have noticed that all but the rst and last lines were copied directly from CF-10.26. The above constraint doesn't accommodate the past. Often we wish the constraint to hold over all valid time. This can be accomplished with a sequenced/ current constraint. Code Fragment 10.45 A customer who owned property 7797 shall concurrently own no other property. CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT * FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.VT_Begin < P2.VT_End AND P2.VT_Begin < P1.VT_End AND P1.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31 )) This is just CF-10.27, with the target list replaced with *, as the NOT EXISTS could care less whether there is one column or many in the row returned by the subquery. To check for ownership of another property, at some possibly different time, we use a nonsequenced/current constraint. 326 CHAPTER TEN : BITEMPORAL TABLES Code Fragment 10.46 A customer who owned property 7797 shall own no other property, even at a different time. CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT P2.property_number FROM Prop_Owner AS P1, Prop_Owner AS P2 WHERE P1.property_number = 7797 AND P2.property_number <> P1.property_number AND P1.customer_number = P2.customer_number AND P1.TT_Stop = DATE 9999-12-31 AND P2.TT_Stop = DATE 9999-12-31)) This is just CF-10.28, placed in a NOT EXISTS. Integrity constraints are generally applied after modication statements, or at the end of transactions containing modication statements. As such, current in transaction time, as in the above constraints, is appropriate. The rows modied by the transaction will all have a transaction-stop There are six variants time of “until changed.” There are nine variants correspondcorresponding to each ing to each nontemporal integrity constraint, paralleling the sitnontemporal integrity uation with queries. However, transaction-time sequenced inconstraint. tegrity constraints should be specied as current in transaction time, reducing the number of usable bitemporal integrity constraints to six: current/current, sequenced/current, nonsequenced/current, current/ nonsequenced, sequenced/nonsequenced, and nonsequenced/nonsequenced. We now turn to a particularly important constraint, that of referential integrity, and focus on Prop Owner.customer number as a sequenced/current foreign key to the Customer table. The brute-force approach, which always works, is to use the approach above to get a nontemporal constraint, then use the process discussed in Section 10.3.2 to obtain the appropriate bitemporal constraint. For referential integrity, we rst construct the following (nontemporal) constraint: Code Fragment 10.47 The customer number in Prop Owner is a foreign key referencing the Customer table (nontemporal version). CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT * FROM Prop_Owner WHERE customer_number NOT IN (SELECT customer_number FROM Customer)) ) We now need to map this into a sequenced/current constraint, which is done by mapping the SELECT into a sequenced/current query. As noted on page 155, the NOT IN is actually relational difference and can be expressed using that construct. 10.4 Code Fragment 10.48 INTEGRITY CONSTRAINTS 327 The customer number in Prop Owner is a foreign key referencing the Customer table, using EXCEPT (nontemporal version). CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT customer_number FROM Prop_Owner EXCEPT SELECT customer_number FROM Customer) ) A sequenced/current foreign key constraint can be expressed as an embedded sequenced/  current query.    We can then map this into a sequenced/current query using the approach illustrated in CF-6.18 on page 155. To do so, we made the following changes to that code fragment: Replaced INCUMBENTS with Prop Owner for I1 and with Customer for the other correlation names, I2, I3, and I4.  Removed the mentions of specic PCNs. Replaced SSN with customer number. Replaced each of the target lists with *. Added the transaction currency check to the WHERE clauses for all correlation names. Code Fragment 10.49 The customer number in Prop Owner is a foreign key referencing the Customer table (valid-time sequenced/transaction-time current version). CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT I1.customer_number FROM Prop_Owner AS I1, Customer AS I3 WHERE I1.customer_number = I3.customer_number AND I1.TT_Stop = DATE 9999-12-31 AND I3.TT_Stop = DATE 9999-12-31 AND NOT EXISTS (SELECT * FROM Customer AS I4 WHERE I4.customer_number = I1.customer_number AND I4.TT_Stop = DATE 9999-12-31 AND I1.VT_Begin < I4.VT_End AND I4.VT_Begin < I3.VT_Begin) UNION SELECT I1.customer_number FROM Prop_Owner AS I1, Customer AS I2 WHERE I1.customer_number = I2.customer_number continued on page 328 328 CHAPTER TEN : BITEMPORAL TABLES continued from page 327 ) AND I1.TT_Stop = DATE 9999-12-31 AND I2.TT_Stop = DATE 9999-12-31 AND NOT EXISTS (SELECT * FROM Customer AS I4 WHERE I4.customer_number = I1.customer_number AND I4.TT_Stop = DATE 9999-12-31 AND I2.VT_End < I4.VT_End AND I4.VT_Begin < I1.VT_End) UNION SELECT I1.customer_number FROM Prop_Owner AS I1, Customer AS I2, Customer AS I3 WHERE I1.customer_number = I2.customer_number AND I1.customer_number = I3.customer_number AND I1.TT_Stop = DATE 9999-12-31 AND I2.TT_Stop = DATE 9999-12-31 AND I3.TT_Stop = DATE 9999-12-31 AND NOT EXISTS (SELECT * FROM Customer AS I4 WHERE I4.customer_number = I1.customer_number AND I4.TT_Stop = DATE 9999-12-31 AND I2.VT_End < I4.VT_End AND I4.VT_Begin < I3.VT_Begin) UNION SELECT I1.customer_number FROM Prop_Owner AS I1 WHERE I1.TT_Stop = DATE 9999-12-31 AND NOT EXISTS (SELECT * FROM Prop_Owner AS I4 WHERE I4.customer_number = I1.customer_number AND I4.TT_Stop = DATE 9999-12-31 AND I1.VT_Begin < I4.VT_End AND I4.VT_Begin < I1.VT_End)) By studying the particulars of the desired temporal integrity constraint, often a much simpler expression is possible. Another way to proceed is to look more closely at what the sequenced/current referential integrity is doing and to attempt to come up with a more streamlined version. We already did that analysis for valid-time state tables, developing CF-5.23. This can be generalized to a sequenced/current constraint on bitemporal tables by simply adding a transaction currency predicate for each correlation name. 10.5 Code Fragment 10.50 TEMPORAL PARTITIONING* 329 The customer number in Prop Owner is a foreign key referencing the Customer table (valid-time sequenced/transaction-time current, version 2). CREATE ASSERTION CHECK (NOT EXISTS ( SELECT * FROM Prop_Owner AS P WHERE P.TT_Stop = DATE 9999-12-31 AND NOT EXISTS ( SELECT * FROM Customer AS C WHERE P.PCN = C.PCN AND C.TT_Stop = DATE 9999-12-31 AND C.VT_Begin <= P.VT_Begin AND P.VT_Begin < C.VT_End) OR NOT EXISTS ( SELECT * FROM Customer AS C WHERE P.PCN = C.PCN AND C.TT_Stop = DATE 9999-12-31 AND C.VT_Begin < P.VT_End AND P.VT_End <= C.VT_End))) This approach yields a much shorter assertion, but requires more analysis; the rst approach is largely mechanical. While the temporal analog of a nontemporal foreign key integrity constraint is normally a sequenced/sequenced conFor referential integrity straint, there are exceptions. First, as already noted, transactionconstraints between tables time sequenced can be replaced with transaction-time current. supporting differing aspects of Second, for valid time, if the referencing table does not suptime, use a current constraint if port valid time, then we should only use the current state of the time support is missing. the referenced table, a valid-time current constraint. 10.5 TEMPORAL PARTITIONING* While a bitemporal table with valid and transaction period timestamps is convenient for many types of queries, as illustrated in Section 10.3, keeping both the valid-time history and the history of the changes in a single table often greatly decreases query performance. To perform a current/current query (“at now as best known”) may require scanning the entire bitemporal table, rejecting the records relating to prior dates in valid time and the erroneous records that were subsequently corrected. 330 CHAPTER TEN : BITEMPORAL TABLES Table 10.11 The bitemporal table corresponding to the time diagram of Figure 10.19. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 145 827 827 7797 7797 7797 7797 7797 7797 7797 7797 3621 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 1998-01-12 1998-01-15 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-20 9999-12-31 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-28 1998-01-31 1998-01-15 1998-01-28 1998-01-20 1998-01-28 1998-01-26 1998-01-28 1998-01-30 9999-12-31 9999-12-31 Temporal partitioning was previously considered in the context of valid time in Section 7.5 and in the context of transaction time in Section 9.4. The alternatives, and their potential impact on performance, are even greater for bitemporal tables. We will briey examine a collection of temporal partitioning schemes for bitemporal tables here, continuing with the Prop Owner table. This table will be represented by two or more tables, each holding a subset of the bitemporal regions. While the general approach is termed “temporal partitioning,” often the constituent tables do not actually partition the data; information may be replicated in multiple tables, with the application held responsible for ensuring that the information is consistent. We illustrate the partitioning on the state of the Prop Owner table (Table 10.11) corresponding to the time diagram of Figure 10.19 on page 313. 10.5.1 VT Current/TT Current + Bitemporal State If current/current queries are prevalent, it is advantageous to materialize the current/current state (valid time = transaction time = “now”), in addition to the bitemporal state, resulting in two tables: the current store (PO Current) and the bitemporal store (PO Bitemp). The current store in the example will contain but a single row, indicating that Peter owns the at at Bygaden 4, as best known: customer number property number 827 3621 10.5 TEMPORAL PARTITIONING* 331 As an aside, this arrangement is not a strict partitioning, as the rows in the current store are also in the bitemporal state table. The other variants discussed below are true partitions. Current/current queries are easy: just apply them to the current store; no additional predicates are required. Of course, all the other kinds of queries can be applied to the bitemporal state table, which is still available. The current store must be changed as a side effect of modications applied to the bitemporal store. Current modications A current partition has the advantage that a valid-end time are simple: transform the modication as discussed in Section 10.2.1 to modify the bitemporal store, and also apply the modiof “forever” need not be stored; cation as is to the current store. Sequenced modications would the valid-end timestamp is be also applied to the current store if the period of applicaimplicit in the current store. bility overlapped “now.” Nonsequenced modications must be handled on a case-by-case basis. Interestingly, the current store can change just with the passage of time. Consider the modication that inserts Peter buying The current store has the the Bygaden at on January 15, illustrated in Figure 10.19 on disadvantage that the passage page 313. Say that this was instead a postactive modication— of time alone can cause rows to that it was performed on January 5. This row was not present in enter and exit this store; the current store on that date. Indeed, it remains absent until managing this movement is January 15 rolls around, at which point it must be inserted into awkward. the current store. One way to handle these future events is to execute the following action to reestablish consistency once a day, say, in the early morning: Code Fragment 10.51 Bring the PO Current table up-to-date. INSERT INTO PO_Current SELECT customer_number, property_number FROM PO_Bitemp WHERE TT_Stop = DATE 9999-12-31 AND VT_Begin = CURRENT_DATE DELETE FROM PO_Current WHERE EXISTS ( SELECT * FROM PO_Bitemp AS B WHERE PO_Current.customer_number = B.customer_number AND PO_Current.property_number = B.property_number AND TT_Stop = DATE 9999-12-31 AND VT_End = CURRENT_DATE) In the deletion, we need to delete those rows of the current store associated with rows in the bitemporal store with the same primary key. 332 CHAPTER TEN : BITEMPORAL TABLES If the granularity of valid time was smaller, say, a minute, then it might make sense to record the valid begin and end times in a separate table, PO Future, with a single column, When. Each modication to the bitemporal store would insert times into PO Future and would also set some variable indicating when the action should be evaluated. This action would remove the earliest time from the table and would reschedule itself for the next begin or end date. Alternatively, the above action could be run whenever a query was applied to the current store, to ensure that this state was up-to-date. Current/current queries are particularly easy and efcient: simply query the current store. Other queries can be applied to the bitemporal state table, which has all the information it did before. 10.5.2 VT State/TT Current + State/State Archive To avoid the complexity of having to modify the current store as a side effect of the passage of time, we can put the entire valid-time history, as best known, in what is termed a history store (PO History), with the corrected rows—those with a transaction-stop time other than “until changed”—residing in an archival store (PO Archive). The history store now has more information than the current store of the previous section. Note that the history store here has three timestamp columns: the delimiting times of the valid-time period, and the transaction-start time. The transaction-stop time is implicit; it is “until changed.” Making this implicit means that we don't have to come up with an encoding of “until changed” (that value was encoded as “forever” in the bitemporal state table). The history store contains all the rectangles with right pointers in Figure 10.19: customer number property number VT Begin VT End TT Start 827 827 7797 3621 1998-01-12 1998-01-15 1998-01-20 9999-12-31 1998-01-28 1998-01-31 Correspondingly, the archival store (Table 10.12) has fewer rows than the original bitemporal state table, as the current history is stored elsewhere. While not illustrated here, it is possible for future valid times to also be present in the history store, and in the archival store A history store is much easier to as well. We don't have to be concerned with moving such rows maintain than a current store in or moving rows that terminate in the future out, as we did and retains many of its with the current store. advantages. The archival store Modications—whether current, sequenced, or nonsecan be maintained quenced in valid time (recall that all modications are current automatically through triggers in transaction time)—are applied directly to the history store. dened on the history store. The archival store can be maintained entirely with triggers, 10.5 TEMPORAL PARTITIONING* 333 Table 10.12 Archival store. customer number property number VT Begin VT End TT Start TT Stop 145 145 827 827 145 145 145 7797 7797 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 1998-01-15 1998-01-28 1998-01-20 1998-01-28 1998-01-26 1998-01-28 1998-01-30 generalizing the approach used in Chapter 8 for maintaining a tracking log, specically CF-8.2 on page 221. These triggers retain a before-image in the archival store. Code Fragment 10.52 Triggers for maintaining the PO Archive table. CREATE TRIGGER Delete_PO AFTER DELETE ON PO_History FOR EACH ROW BEGIN INSERT INTO PO_Archive VALUES (OLD.customer_number, OLD.property_number, OLD.VT_Begin, OLD.VT_End, OLD.TT_Start, CURRENT_DATE) END CREATE TRIGGER Update_PO AFTER UPDATE ON PO_History FOR EACH ROW BEGIN INSERT INTO PO_Archive VALUES (OLD.customer_number, OLD.property_number, OLD.VT_Begin, OLD.VT_End, OLD.TT_Start, CURRENT_DATE) END In Section 10.2, we outlined a two-stage approach to implement modications on a bitemporal table: rst deal with valid time, then further transform the sequence of SQL statements to deal with transaction time. Under the history/archival store scheme, only the rst stage is required; the triggers effect the second stage, thus greatly simplifying the application code. The full bitemporal table can be (There is one remnant of the second stage: the transaction-start expressed as a view. time must be set/updated to “now” in the application code, in modications applied to the history store.) 334 CHAPTER TEN : BITEMPORAL TABLES Table 10.13 Another version of the archival store. customer number property number VT Begin VT End TT Start 145 145 827 827 145 145 145 7797 7797 7797 7797 7797 7797 7797 1998-01-10 1998-01-10 1998-01-15 1998-01-15 1998-01-03 1998-01-05 1998-01-05 9999-12-31 1998-01-15 9999-12-31 1998-01-20 1998-01-10 1998-01-10 1998-01-12 1998-01-10 1998-01-15 1998-01-15 1998-01-20 1998-01-23 1998-01-26 1998-01-28 Transaction-time current queries are applied to the history store. Transactiontime sequenced and nonsequenced queries should be applied to the following view: Code Fragment 10.53 Reinstate the bitemporal state table as a view. CREATE VIEW Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) AS (SELECT customer_number, property_number, VT_Begin, VT_End, TT_Start, CURRENT_DATE FROM PO_History UNION SELECT * FROM PO_Archive) 10.5.3 VT State/TT Current + State/Event Archive This organization differs from that of the previous section in that we use instant timestamping for transaction time, with the accompanying space savings. (In fact, this is the scheme that Nykredit utilizes for its property ownership table. The customer and property entities are maintained in transaction-time tables, each temporally partitioned into a current store, with the transaction-start timestamp—the transaction-stop time is implicitly “until changed”—and an archival store, instantstamped also with the transaction-start date.) Here the history and archival schemes are identical. The stores themselves will have the same number of rows as the scheme of the previous section; in fact, the history store is identical in the two schemes. The archival store (Table 10.13) omits the transaction-stop time. The reason that the transaction-stop time is not needed is that it can be found in another row, as the transaction-start time. The transaction-stop time of the rst row is found in the second row: January 15. This is because the (sequenced/sequenced) primary key, customer number and property number, match, and because the valid times overlap, implying that the second row invalidated the valid-time period of the rst row. Following owner 145 (Eva), the period of validity of the fth row does 10.5 TEMPORAL PARTITIONING* 335 not overlap that of the second row, so it can be viewed as additional information. However, both the second row and the fth row are invalidated by the sixth row. Finally, the fourth row invalidates, and provides the transaction-stop time for, the third row. As an aside, the ZPOS COMPENSATION HISTORY table of Chapter 5 includes a CHRONOLOGY KEY column, serving as a transaction timestamp, along with HISTORY START DATE and HISTORY END DATE columns, indicating when the information in the record applied (the period of validity). This table can also be considered to be a state/event bitemporal table, supporting both valid time (with period timestamping) and transaction time (with instant timestamping). The archival store can once again be maintained via triggers dened on the history store. This ensures that the transaction-time semantics is maintained. As before, to evaluate transaction sequenced or nonsequenced queries, we need to constitute the bitemporal state table, which is rather more involved than before. Code Fragment 10.54 Reconstitute the bitemporal state table as a view. CREATE VIEW Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) AS (SELECT customer_number, property_number, VT_Begin, VT_End, TT_Start, CURRENT_DATE FROM PO_History UNION SELECT P1.customer_number, P1.property_number, P1.VT_Begin, P1.VT_End, P1.TT_Start, P2.TT_Start FROM PO_Archive AS P1, PO_Archive AS P2 WHERE P1.customer_number = P2.customer_number AND P1.property_number = P2.property_number AND P1.TT_Start < P2.TT_Start AND NOT EXISTS (SELECT * FROM PO_Archive AS P3 WHERE P1.customer_number = P3.customer_number AND P1.property_number = P3.property_number AND P3.TT_Start BETWEEN P1.TT_Start AND P2.TT_Start) UNION SELECT PA.customer_number, PA.property_number, PA.VT_Begin, PA.VT_End, PA.TT_Start, PH.TT_Start FROM PO_Archive AS PA, PO_History AS PH WHERE PA.customer_number = PH.customer_number AND PA.property_number = PH.property_number AND PA.TT_Start < PH.TT_Start continued on page 336 336 CHAPTER TEN : BITEMPORAL TABLES continued from page 335 ) AND NOT EXISTS (SELECT * FROM PO_Archive AS P3 WHERE PA.customer_number = P3.customer_number AND PA.property_number = P3.property_number AND PA.TT_Start < P3.TT_Start) For those rows that were invalidated, we need to locate the row that invalidated it (from either the PO History or the PO The archival store can be Archive table) to locate the transaction-stop time. Those that narrowed by storing only one haven't been invalidated (i.e., those in the current store) have a transaction timestamp: transaction-stop time of “now.” transaction start. The drawback There is one complication with the structure. If the entire is a more complex view history of an owner-property pair can be deleted—say, with a reconstituting the bitemporal valid-time sequenced deletion with a period of applicability of state table. all of time—there is no place to store the transaction time of that deletion. If this is indeed possible, it is best to create a PO Deleted table, with columns owner number, property number, and TT Deleted. The view denition would then require another case. Code Fragment 10.55 Reinstate the bitemporal state table as a view, when history deletions are allowed. CREATE VIEW Prop_Owner (customer_number, property_number, VT_Begin, VT_End, TT_Start, TT_Stop) AS SELECT customer_number, property_number, VT_Begin, VT_End, TT_Start, CURRENT_DATE FROM PO_History UNION SELECT P1.customer_number, P1.property_number, P1.VT_Begin, P1.VT_End, P1.TT_Start, P2.TT_Start FROM PO_Archive AS P1, PO_Archive AS P2 WHERE P1.customer_number = P2.customer_number AND P1.property_number = P2.property_number AND P1.TT_Start < P2.TT_Start AND NOT EXISTS (SELECT * FROM PO_Archive AS P3 WHERE P1.customer_number = P3.customer_number AND P1.property_number = P3.property_number AND P3.TT_Start BETWEEN P1.TT_Start AND P2.TT_Start) AND NOT EXISTS (SELECT * FROM PO_Deleted AS P3 WHERE P1.customer_number = P3.customer_number 10.6 VACUUMING* 337 AND P1.property_number = P3.property_number AND P3.TT_Start BETWEEN P1.TT_Start AND P2.TT_Start) UNION SELECT PA.customer_number, PA.property_number, PA.VT_Begin, PA.VT_End, PA.TT_Start, PH.TT_Start FROM PO_Archive AS PA, PO_History AS PH WHERE PA.customer_number = PH.customer_number AND PA.property_number = PH.property_number AND PA.TT_Start < PH.TT_Start AND NOT EXISTS (SELECT * FROM PO_Archive AS P3 WHERE PA.customer_number = P3.customer_number AND PA.property_number = P3.property_number AND PA.TT_Start < P3.TT_Start) AND NOT EXISTS (SELECT * FROM PO_Deleted AS P3 WHERE P1.customer_number = P3.customer_number AND P1.property_number = P3.property_number AND P3.TT_Start BETWEEN P1.TT_Start AND P2.TT_Start) UNION SELECT PA.customer_number, PA.property_number, PA.VT_Begin, PA.VT_End, PA.TT_Start, PH.TT_Start FROM PO_Archive AS PA, PO_Deleted AS PD WHERE PA.customer_number = PD.customer_number AND PA.property_number = PD.property_number AND NOT EXISTS (SELECT * FROM PO_Archive AS P3 WHERE PA.customer_number = P3.customer_number AND PA.property_number = P3.property_number AND P3.TT_Start BETWEEN PA.TT_Start AND PD.TT_Start) The additional NOT EXISTS in the second and third cases are required if an ownerproperty pair's history is removed, then later inserted back. 10.6 VACUUMING* Vacuuming was rst introduced in Chapter 9, in the context of transaction-time state tables. Bitemporal tables present an even greater opportunity, and need, for vacuuming. Recording the history of the enterprise can result in many rows; also retaining the change history of the table can dramatically increase the size of the table. The relative sizes of the components of a bitemporal table can be surprising. In our example, Table 10.9, corresponding to the time diagram in Figure 10.19, 338 CHAPTER TEN : BITEMPORAL TABLES captures three relationships, two involving Peter and one involving Eva. The current/current state (“now as best known”) comprises just one row, the last one. The current transaction-time state (“history as best known”) comprises two rows, the last plus the next-to-last, both corresponding to Peter. The noncurrent transactiontime states, those with a transaction-stop time other than “forever,” comprise the other seven rows; these are usually placed in an archival store. This is in accord with our intuition: the current/current state should be the smallest; the transaction-time current should be larger, as it contains the current/current state; and the archival store should be the largest. However, often these relative sizes are not found in actual applications. In particular, it is often the case that the archival store is not large at all. The rows in the archival store originate from two separate processes. The rst is when a row is inserted with an unknown valid-time end time; in such cases we simply use “forever.” Later, the end time becomes known and is stored in the bitemporal table, with the previous row moved to the archival store. Two of the rows of Table 10.9, the rst and third rows, thus came into being. The second situation is when erroneous data was discovered and corrected; the data in error is retained in the archival store. This was the source of ve of the rows in the example table. The rst source of archival rows is not invoked when the period of validity is known a priori. Insurance policies, car loans, Often the history store is the and xed-term appointments are examples in which archival largest component of a bitemporal state table, implying rows need not be generated. And the second source of archival rows is thankfully not that common; a good percentage of data that vacuuming the archival is in fact correct and will not later be changed. (Alternatively, store may not be effective in the data may be incorrect, but we may never discover that.) For substantially reducing the size of these reasons, in many applications the current transaction state such a table. (“history as best known”) dominates the bitemporal table, with the archival store being a fraction of the rows. We can apply all of the techniques discussed in Section 9.5 to the archival portion of a bitemporal state table. Because valid time is present in such tables, it can be used to further rene the vacuuming. Code Fragment 10.56 Temporally vacuum old unused entities from the archival store for which no recent history exists. DELETE FROM Prop_Owner WHERE (CURRENT_DATE - TT_Stop DAY) > INTERVAL 731 DAY AND NOT EXISTS (SELECT * FROM Prop_Owner AS R WHERE TT_Stop = DATE 9999-12-31 AND (CURRENT_DATE - VT_End DAY) > INTERVAL 731 DAY AND customer_number = C.customer_number AND property_number = C.property_number) 10.8 SUMMARY 339 The rst predicate identies archival rows that are old in transaction time (the correction was made more than two years ago); the second predicate ensures that no recent history (less than two years) exists in valid time. 10.7 IMPLEMENTATION CONSIDERATIONS The CD-ROM contains all the code fragments in this chapter in Oracle8 Server, which run without change after transforming assertions to triggers. 10.8 SUMMARY A bitemporal table combines both valid time and transaction time into a single structure. It contains four timestamps, two denoting the valid-time period of validity and two denoting the transaction-time period of presence. Such a table can also be represented by several tables, such as a current store, a history store, and an archival store. Primary key constraints on such tables are generally valid-time sequenced and transaction-time current. Expressing such a constraint requires an SQL PRIMARY KEY constraint and an assertion. Often you will also want to constrain the validtime history for an entity (or relationship) to not have any gaps; this requires another assertion. Modications on bitemporal tables can be challenging. We examined several variants, all current in transaction time: valid-time current insertions, deletions, and updates; valid-time sequenced insertions, deletions, and updates; and validtime nonsequenced deletions. We saw that valid-time current modications were tedious, and valid-time sequenced modications even more so. For the latter, we advocated a two-stage conversion process: rst deal with valid time, with each such modication resulting in a series of SQL statements, then deal with transaction time, mapping each SQL statement into one or more statements that maintain the transaction-time semantics. The mapping was mechanical, but resulted in a long series of SQL statements. The worst case was that of sequenced update, in which a nontemporal update of only a few lines expanded to some 60 lines of SQL. We rst considered time-slice queries, in transaction, valid, and bitemporal varieties, then showed that there are nine versions of any nontemporal query. Some of these are more useful than others, but the benet of a bitemporal table is that it admits the full generality of temporal queries. Temporal integrity constraints parallel temporal queries; in fact, any temporal integrity constraint can be expressed as a temporal query embedded in a NOT 340 CHAPTER TEN : BITEMPORAL TABLES EXISTS assertion. This mechanical translation allows you to map a temporal constraint into SQL; further analysis may enable the assertion to be simplied. We examined several ways to represent a bitemporal state table via several tables, each holding a portion of the temporal extent of the table. There are two somewhat orthogonal decisions to be made: how to divide up the time diagram among the representational tables, and for each table, whether to use instant or period timestamping. Partitioning a bitemporal table renders some queries more efcient, at the expense of other queries. Transaction-time sequenced and nonsequenced queries are negatively affected; transaction-time current queries, especially the valid-time current subset, are made faster. If the performance of current/current queries is critical, having a separate materialized current store can be quite effective, though this arrangement introduces difculties in maintaining the current store. A nice compromise is a history/archival pair, with the former containing the transactioncurrent rows and the latter containing those rows with a transaction-stop time before “now.” The history store is period-stamped in valid time and instant-stamped in transaction time (the transaction-start time); the transaction-stop time is implicit and is equal to “until changed.” The archival store is period-stamped in both valid and transaction time. It is convenient to maintain the archival store via triggers dened on the history store. If space is at a premium, then it is best to use instant stamping in transaction time in the archival store, at a cost in query time for noncurrent transaction queries. The archival store component of bitemporal tables can be vacuumed; having valid time around allows more specic vacuuming specications. 10.9 READINGS The bitemporal time diagram was introduced by Christian S. Jensen and the author [53]. A variation of this diagram was independently explored by James Clifford and Tomás Isakowitz [24]; the diagram has also been extended to incorporate reference time [23]. Heidi Gregersen and Christian S. Jensen discuss implementing integrity constraints on tables with various kinds of temporal support [39]. Blaha and Premerlani differentiate, for portfolio databases, “the time when a transaction occurs” (in our terminology, the valid time of the transaction), “the time when the user records a transaction” (the transaction time of the transaction), “the time of valuation of an asset” (the valid time of the valuation), “the time a portfolio value is computed” (the valid time of the computed value), and “the time interval (starting time and ending time) for computing ROI” (the valid time of the ROI fact) [9, p. 195]. 10.9 READINGS 341 Table 10.14 Böhlen's classes of temporal integrity constraints. Böhlen's terminology This book's terminology nontemporal nontemporal intrastate valid-time sequenced valid-time nonsequenced interstate static dynamic transition intraelement interelement 1 transaction-time sequenced transaction-time nonsequenced transaction-time nonsequenced1 valid-time sequenced/ transaction-time sequenced valid-time nonsequenced/ transaction-time nonsequenced Example Every employee must be assigned to at least one project. At any point in his employment an employee must be assigned to at least one project. An employee who was assigned to the KAP92 project may not be assigned to the PMT project. At every database state, credit entries are limited to $20 million. A project credit may not be deleted and subsequently (i.e., at a later database state) reasserted with an increased credit value. A project credit may not be increased by updating the credit value. At every database state, it must hold that, at any point of his employment, an employee is assigned to at least one project. If a project gets credits over a period of six years, which is extended to a period of ten years, then the number of employees assigned to that project must be decreased by two within one year. The predicate will be of the form of meets, that is, TT Stop = TT Start. Michael Böhlen has investigated bitemporal integrity constraints in some detail. He developed a taxonomy of such constraints [15]. His terms can be mapped into our terminology, as illustrated in Table 10.14 with the constraints listed in that paper. The theory behind oscillators is presented in a delightfully approachable manner by James Jespersen and Jane Fitz-Randolph in their concise and highly readable book, From Sundials to Atomic Clocks [58]. Also approachable, though at a more advanced level, is Philip Woodward's book, My Own Right Time [104]. Gerhard Rossum's book History of the Hour: Clocks and Modern Temporal Orders [81] is an expansive history of the mechanical clock and its impact on European society, from the Middle Ages to the industrial revolution. The denition of “jiffy” may be found in the Hacker's Dictionary [98]. CHAPTER 11 O V E R V I E W The case studies in the preceding chapters We now reprise the initial case study—Brad have covered a lot of ground. The major De Groot's feed yard application. We have two concepts—including valid time; transaction aims in doing so. First, we use this case to show time; current, sequenced, and nonsequenced how best to design a temporal application. And queries; integrity constraints; modications; second, this case study serves to review all of user-dened time; and the expression of these these concepts within the context of a single concepts in SQL-92—have been discussed in application. detail. Temporal Database Design T he rst case study we studied was that of Brad De Groot's feed yard application, discussed informally in Chapter 2. We now return to that case study, this time with the benet of a deep understanding of temporal semantics conveyed in the intervening chapters. Brad started his investigation into the temporal relationships between putative risk factor exposure and subsequent health events by understanding the structure of the data les maintained by the feed yards as they track the movement of cattle between pens. He carefully merged these data denitions into a global schema. After months of work, Brad had constructed an entity-relationship (ER) schema with some 40 entity types and relationships and over 150 roles. Even when printed in a small font, this ER diagram required a large poster to see it in its entirety. The relational schema generated from this conceptual model contains 55 tables and about 850 columns. In sum, the schema is typical: large and complex and somewhat overwhelming. After Brad had nished the schema, he read an early draft of this book and realized that he had a bitemporal database on his hands. He worked with the author to understand his application in the framework presented in this book. This analysis pointed out semantic problems with the schema, which were solved by applying the methodology presented here. 11.1 PROPERLY SEQUENCING THE DESIGN The case studies appearing in the preceding chapters are inextricably entwined with the design decisions relevant to their particular needs. Should a new application match those needs closely, then perhaps the design decisions would be appropriate 344 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN for that application. The purpose of the present chapter is to take a more general view, to outline precisely when each time-related decision should be considered. Application design and implementation consist fundamentally of making a series of decisions, each impacting subsequent trade-offs, often in subtle and unexpected ways. Over the past two decades, experience and research has converged on a sequence of three basic steps: (1) conceptual design using the ER model, (2) logical design using the relational model, and nally (3) physical design to ensure adequate performance. Unfortunately, because both the ER and the relational model do not themselves adequately support time-varying information, current practice using these models is actually counterproductive in places. Among the most egregious is temporal partitioning, which is generally considered very early in conceptual design, when in fact it should be one of the last considerations in physical design. Overly complex ER schemas and relational schemas have resulted from considering time earlier rather than later. In the approach we espouse here, conceptual design initially ignores the time-varying nature of the application. We focus The temporal aspects of the on capturing the current reality and temporarily ignore any hisapplication should be initially tory that may be useful to capture. This selective amnesia someignored when developing the what simplies what is often a highly complex task of capturing conceptual schema. the full semantics of the application. An added benet is that existing conceptual design metholodologies apply in full. Only after the full design is complete do we augment the ER schema with the time-varying semantics of the application. We consider each component of the ER schema in turn, annotating that component with its temporal semantics. Entity types, relationship types, attributes, and keys are each individually addressed. These annotations are expressed in prose, so that they do not clutter the ER schema. Similarly, logical design proceeds in two stages. First, the nontemporal ER schema is mapped to a nontemporal relational schema, a collection of tables. Here again we ignore the temporal aspects of the application, and thus can apply existing mapping strategies, unencumbered by considering how to capture history. In the second stage of logical design, each of the annotations is applied to the logical schema, modifying the tables or integrity constraints to accommodate that temporal aspect. We proceed in a disciplined fashion, dealing with each annotation in turn. In the following, we start with a nontemporal ER schema and proceed to a fully elaborated SQL schema, taking into account the time-varying nature of the application. This serves as yet another ight through the core temporal concepts, and also serves to emphasize the utility of thinking of time-varying data in these terms. 11.2 11.2 CONCEPTUAL DESIGN 345 CONCEPTUAL DESIGN Contrary to current practice, all temporal aspects should be ignored during most of conceptual design. An ER schema should be constructed that has no temporal features. All design considerations should be visited at this time, including keys, integrity constraints, composite attributes, multivalued attributes, relationship participation (one-to-one, one-to-many, many-to-many, optional, or mandatory), weak and strong entity types, subclasses, superclasses, categories, specialization, generalization, and attribute inheritance. Once a carefully worked-out ER schema has been constructed, only then should the temporal aspects be considered. 11.2.1 Nontemporal ER Schema Figure 11.1 shows a fairly small portion (about a sixth) of the initial ER schema for Brad's application, in the traditional notation of rectangles for entities and diamonds for relationships. Note that in describing this diagram, we use present tense, as time is not yet involved. Entity and relationship type names are in all caps, attribute names are capitalized, and individual entities (such as a particular lot) and individual relationships are not capitalized. Strong Entity Types There are two (strong) entity types present: FEEDYARD and APPLICATION. Brad has data from ve feed yards. Weak Entity Types There are four weak entity types, indicated by a double rectangle; a double diamond indicates the identifying relationship type, which relates a strong entity type to the weak entity type. By necessity, this relationship is total, indicated with a double line. A pen is a fenced-in plot of land that can hold cattle. It is related to the FEEDYARD strong entity type via the IN PEN relationship type. Since the relationship is total, every PEN entity must be in a particular FEEDYARD entity. A lot is a specic group of cattle, resident in one pen or divided into multiple pens. The analysis of treatments and putative factors is carried out on lots of cattle. LOT is related to FEEDYARD through the IN LOT relationship type. The feed yards use FoxPro to collect this information; FoxPro stores each table in a dbf le. Brad then periodically copies these les onto a oppy disk and loads the information into his SQL database, running on Sybase SQLAnywhere. He terms each such transfer and loading, which can involve coordinating the data from multiple dbf les, a backup, for which a BACKUP weak entity is created. 346 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN FEEDYARD Feedyard_ID Mngr_LName Fdyd_Short_Name IS_ DESCRIBED_ BY IN_ PEN Pen_ID Pen_ TypeID Dat_ Processed Bkp_ID PEN IN_ LOT Lot_ID_Num BACKUP Year_Month Gndr_Code LOT Proj_Closeout (1, 1) DESCRIBES_ PEN (1, n) (1, n) DESCRIBES_ LOT (1, 1) Lot_ID (1, 1) from (1, 1) (1, 1) to MOVE (1, 1) Hd_Cnt (1, 1) (1, 1) (1, 1) MASS_ TRTMNT Code Avg_Wgt Hd_Cnt (1, 1) Hd_Cnt (D, m) DBF_Name (1, n) LOCATION (1, n) DBF_FILE CREATES APPLICATION A_Descriptor Figure 11.1 A nontemporal entity-relationship schema. DBF_UPDATE_ RecNo CONTAINS A_Name 11.2 CONCEPTUAL DESIGN 347 Entity Type Key Attributes In the ER model, every entity must have an attribute that identies that entity. Strong entity types have a key, which is underlined in the ER schema; weak entity types have a partial key, which is indicated with a dotted line. The key for FEEDYARD is Feedyard ID; for APPLICATION it is A Name. A combination of the key for the strong entity type and the partial key for the weak entity type identies each weak entity. Hence, a particular (Feedyard ID, Pen ID) pair will identify an individual pen. Attributes A few other attributes are included. You might ask, Why does the LOT entity type have both Lot ID and Lot ID Num attributes? It turns out that the former is a character string used by the feed yard; the latter is an assigned integer and is designated the partial key. The most interesting attributes in this context are the user-dened time attributes: Proj Closeout in LOT (the projected date that the lot will leave the feed yard), and Year Month and Date Processed in BACKUP, indicating when the backup was processed, and which month the data was associated with. These attributes are independent of the other attributes and of the relationships that the entity type participates in. In particular, they do not indicate the valid-time or transaction-time extent of the entities or relationships. Rather, they approximate when the backup was taken and when it was processed. Data within the backup is used to calculate a more precise valid time (to the granularity of day). Because of various consistency checking and cleansing activities, the actual transaction time may be different than the Date Processed. LOT.Valid is a Boolean attribute indicating whether the information in the entity has passed various validation tests. Note that we do not include timestamp attributes. Those attributes will be added when we map to the relational model (that is, to tables). Relationship Types There are ve relationship types, in addition to the identifying relationship types discussed earlier. LOCATION identies the pen(s) each lot is in. Cattle in a lot can reside in multiple pens, and a pen can hold cattle from multiple lots (thereby complicating the analysis of disease propagation). DESCRIBES relates lots to backups. A dbf le contains one or more lots. MASS TRTMNT is the administration of some drug regime to the cattle of a lot resident in one or more pens. This is a ternary relationship type, as we associate each individual relationship with the backup during which it was loaded. The MOVE relationship type is complex: it is quintary, capturing the movement of a (perhaps partial) lot of cattle from one pen (in the “from” role) to another pen 348 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN (in the “to” role). This movement was loaded during a backup, from a particular dbf le. Several of the relationship types have associated attributes. Both the MOVE and LOCATION relationship types include a Hd Cnt attribute; the MASS TRTMNT relationship type includes Avg Wgt and Trtmnt Code attributes. Participation Constraints Participation constraints must be specied for each entity type participating in a relationship type. Each constraint is denoted in the ER schema with a pair of integers, denoting the minimum and maximum participation. The minimum participation constraint (the rst component of the pair) differentiates optional from mandatory participation. A minimum participation of 0 is termed optional; a minimum participation greater than zero is termed total, or mandatory. All but the LOCATION relationship type are total; a particular pen may be empty. The maximum participation constraint (the second component of the pair) identies the relationship as one-to-one, one-to-many, or many-to-many. For example, the DESCRIBES LOT relationship is many-to-one. A backup describes many lots, but a lot is described by one backup. In a nontemporal ER schema, these constraints are considered to hold at any point in time. When the schema is later interpreted to be a temporal ER schema, the constraints will then be considered as sequenced, holding at each isolated point in time. In the feed yard schema, IN PEN, IS DESCRIBED BY, CREATES, DESCRIBES PEN, and DESCRIBES LOT are all one-to-many relationship types. Each location relationship denotes cattle from one lot residing in one or more pens. Each move relationship denotes the movement of cattle from one lot from one pen to another pen, as recorded by one dbf le and one backup. Each mass trtmnt relationship captures a treatment being applied to one lot in one pen, as recorded by one backup. 11.2.2 Adding Temporal Annotations Once the nontemporal conceptual schema is complete, it is annotated with the time-varying semantics of each component. You can either indicate such semantics in the ER schema with icons, or you can list the annotations separately, in prose, as we do here. Entity Lifespans Entities have a lifespan denoting when they existed. Entities are instantaneous (with an extremely short lifespan) or have a lifespan with a duration. The lifespan of an entity can be an instant, a single period, or a set of periods. An application may 11.2 CONCEPTUAL DESIGN 349 choose to model the lifespan of a person entity as starting at birth and terminatOne 10th-century table divided the day into hours ing at death, while the lifespan of an em(horae), which were further divided into points ployee entity may include several non(puncta, ve points to the hour) and ostenta (12 contiguous periods if she resigned and osts to the punct); each ost is equivalent to our was later rehired. minute. Other divisions, which could not have The designer may choose whether to been measurable, included the 12th-century divirecord the lifespan. If the entities of an sion of an hour into 4 points, 10 minutes, 15 parts, entity type exist for all of (modeled) 40 movements, 60 marks, and 22,500 atoms (a time, there may be no need to record the second is exactly 6 1=4 atoms). lifespan explicitly. Entity types with an implied lifespan are termed nontemporal. If the lifespan of entities is a subset of the modeled time, then the designer must decide whether it is relevant to the application to record the lifespan explicitly. If so, the designer should also specify the granularity of the lifespan. Interestingly, only one entity type, LOT, has a lifespan that we wish to record in the database; that entity type has an associated granularity of DAY. The entities of the other ve entity types exist for all of the modeled time (though we note in passing that two have a relevant transaction-time extent that should be stored). Puncta and Ostenta Relationship Valid Time A relationship type can either model instantaneous events, or it can model relationships that have a duration. The valid time for any specic relationship must be a subset of the intersection of the lifespans of the associated entities. A relationship is always associated with the same entities, regardless of whether it has a temporal duration and whether its attributes vary over time. The designer must choose whether to record the valid time of the relationship. If the valid time of the relationship type is recorded, the granularity should also be noted. Table 11.1 summarizes the valid times of the 10 relationship types. The valid time of most relationships is not recorded; such For each entity and relationship types are considered nontemporal relationship types. The granutype, decide whether the valid larities of the MOVE and LOCATION lifespans are indicated as time should be recorded, and if ner than a DAY. It turns out that several moves are possible in a so, its granularity. day, so the granularity is expressed as DATE along with a Move Order; multiple moves in a day are sequenced by the Move Order value. (As noted above, we do not include timestamp attributes in the ER schema, so the Move Order attribute will appear explicitly only when we map to tables.) 350 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Table 11.1 Valid time of relationship types. Relationship Type Valid-Time Granularity IN PEN Nontemporal IS DESCRIBED BY CREATES CONTAINS Nontemporal Nontemporal Nontemporal IN LOT Nontemporal DESCRIBES PEN Nontemporal DESCRIBES LOT MOVE Nontemporal Sub-DAY LOCATION Sub-DAY MASS TRTMNT DAY Valid Time of Attributes Comments This relationship type is between two nontemporal entity types, and is itself nontemporal. This relationship type is between a nontemporal entity type, DBF FILE, and a time-varying entity type, LOT. The relationship itself does not vary over valid time. While lots have a lifespan, their entire lifespan is spent in one feed yard. This relationship type is between two nontemporal entity types. The relationship does not vary over time. This relationship type doesn't have a duration: a move is an instantaneous event. Hence, it should be associated with a single valid time indicating the instant when the move event occurred. This is an important component, capturing which pen(s) the lot resides in. The location is denitely a time-varying relationship, so we record the lifespan. The granularity is the same as that of the MOVE relationship type. In fact, each LOCATION period is delimited by two MOVE instants. A treatment of the cattle of a specied lot in a specied pen is an instantaneous event. The value of an attribute may change over the lifespan of the associated entity or the valid time of the associated relationship, or may not vary over time. The valid time of an attribute's value for any specic entity (or relationship) must be a subset of the lifespan (valid time) of that entity For each attribute, determine if (relationship). the valid time of the attribute's We may want to record the valid time of the attribute. If the value should be captured, and if value is xed for all time, capturing the valid time is probably so, the associated granularity. not useful. Even if the attribute's value varies over time, we may be interested just in the current value, in which case there is no need to record the valid time. An attribute for which the valid time is not captured 11.2 CONCEPTUAL DESIGN 351 The Fourth Harrison “H-4” is the laconic name given to perhaps the most famous watch of all time. It was the fourth in a series of clocks that John Harrison (1693– 1776) constructed in an effort to win the longitude prize, $20,000 (several million dollars in today's currency), promised by the British Parliament for a solution to the problem of determining a ship's longitudinal position while at sea. H-4, a large pocket watch at 13 centimeters (5 inches) in diameter and weighing 1.5 kilograms (3 pounds), was the rst marine chronometer of sufcient precision to be used reliably for navigation. John Harrison ultimately collected the monetary award, though it took over 40 years (from H-1, which he started in 1730, to 1773) for Harrison to rene this exquisite manifestation of his mechanical genius. The watch and its predecessors are on display at the National Maritime Museum in the Old Royal Observatory at Greenwich, naturally. is termed nontemporal. For each such attribute, we associate but a single value with each entity. Table 11.2 summarizes the valid-time extent of the attributes, including some attributes for which there wasn't room in the ER schema. The attributes not mentioned are nontemporal. The Hd Cnt attributes for the MOVE and LOCATION relationship types differ in their valid time, emphasizing the need to consider the valid time of attributes separately from their associated entity or relationship type. An individual location relationship indicates that cattle from the specied lot resided in the specied pen. The valid time of this relationship extends from the rst day that at least one head was moved to that pen, to the day the last head of cattle from that lot was transferred out of the pen. During that period, other transfers may have taken place. As long as some cattle remained in the pen, this time-varying head count is associated with a single location relationship. For this reason, we wish to record the valid time of the Hd Cnt attribute, to the granularity of DAY. A particular move relationship captures the transfer of cattle from one pen to another. Recall that this models an instantaA time-varying key uniquely neous event. Hence, the head count is xed for this particular identies a particular entity at relationship, indicating that the attribute is itself nontemporal. each point in time. A The Hd Cnt attribute of MASS TRTMNT is nontemporal for the nontemporal key identies a same reason. particular entity over all time. Key attributes are particularly interesting. For such attributes, we may or may not record the valid time, independently of whether we record the lifespan of the entity type. In either case, it is important that the entity be identiable by its key value, and that this value be unique. Associating 352 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Table 11.2 Valid time of attributes. Attribute Valid-Time Granularity Comments BACKUP.Quirks BACKUP.VTRC Last Date Mod Nontemporal Nontemporal This is a comment attribute. This is a user-dened time attribute, utilized in consistency checking. As such, it is relevant to transaction time (when the data was cleansed and stored in Brad's database) but not valid time (when the data was valid in the real world). In fact, there is no real-world correspondent to this attribute, and so valid time is not relevant. This is also used during consistency checking. BACKUP.BRDR Last Date Mod BACKUP.ARCH Last Date Mod Nontemporal Nontemporal This is a third user-dened time attribute, used during consistency checking. LOT.Gndr Code LOT.Proj Closeout DAY DAY LOT.In-Weight DAY LOT.Owner LOT.Comment LOT.Valid DAY DAY DAY See the discussion on page 14. The projected closeout is a user-dened attribute, indicating when the cattle are scheduled to be moved from the feed yard to the slaughterhouse. This scheduled date can change, as the weight and health of the individual animals vary. As cattle are added to the lot, the value of this attribute may change. MOVE.Hd Cnt Nontemporal LOCATION.Hd Cnt DAY The head count for a particular location relationship is time-varying. MASS TRTMNT.Hd Cnt Nontemporal For a particular mass trtmnt relationship, this attribute is nontemporal. Comments can be tied to particular periods. Consistency checks are performed on the data from the feed yard as it is moved into Brad's database. If any of these checks fail, the Valid attribute is set to false, until Brad manually checks the data and corrects any problems. The information at each day can be independently valid or invalid. For a particular MOVE relationship, this attribute is nontemporal. 11.2 CONCEPTUAL DESIGN 353 Table 11.3 Transaction time of entity types. Entity Type Transaction-Time Granularity APPLICATION BACKUP — DAY DBF FILE FEEDYARD LOT — — DAY PEN — Comments A backup is a dump of a FoxPro database le at a particular date. The information in that backup is processed and inserted into the database, at which time a BACKUP entity is created. This is perhaps the most important entity type in the entire schema. The lots track cattle through the feed yard; data on lots must be as clean as possible. For this reason, Brad needs to record the transaction time of changes to the LOT entity, to a granularity of DAY (with the understanding that only a partial picture is captured). a time-varying key with an entity type indicates that, while the value changes over time, at any point in time it uniquely identies an entity. It turns out that for this schema, the valid time of the keys for all six entity types is not recorded. Transaction Time Recall that recording transaction time retains the sequence of stored states. This aspect is entirely orthogonal to valid time and should be considered separately for entity types, relationship types, and individual attributes. We rst consider the six entity types (see Table 11.3). Unlike valid time, the transaction time of an entity cannot be instantaneous. The transaction-time extent may not be relevant if the application doesn't care to track the changes of the database, or it may be explicitly stored. If the transaction time is to be recorded, then we also indicate the granularity. Transaction time is important in this application because the data from the feed yards is quite dirty (the feed yards themselves are very dirty). Inconsistencies abound, which must be corrected manually. By recording the transaction-time extent, Brad is able to track when the changes were made and can thus work backwards to nd exactly where the erroneous data originated. The idiosyncrasies of this application do not permit all changes to be captured. Brad visits each feed yard about once a month and makes copies of the FoxPro les created by the various feed yard programs. He then brings these les back to his 354 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Table 11.4 Transaction time of relationship types. Relationship Type Transaction-Time Granularity CREATES CONTAINS — DAY IN LOT IN PEN IS DESCRIBED BY DESCRIBES PEN DESCRIBES LOT LOCATION — — — — — DAY MASS TRTMNT MOVE — DAY Comments This relationship type is between an entity type that does not support transaction time (DBF FILE) and an entity type that supports transaction time (LOT). Brad wishes to track changes to this particularly important relationship for putative risk factor exposure. This relationship directly affects the LOCATION relationship, so changes to MOVE are tracked as well. database server, where he cleans and loads the data into his data warehouse. As such, he captures most changes to the granularity of a day. However, if some data were entered into a feed yard program, then subsequently modied before Brad had a chance to grab the le, then the older version will be lost. Hence, the record of the changes as reected in the transaction-time support is necessarily partial. One way to address this loss of information would be to modify all of the feed yard programs to maintain transaction time with their data. Next, we consider the relationship types (Table 11.4). If transaction time is recorded for none of the participating entity types, recording the transaction time for the relationship type is generally not indicated, but is still possible. In any case, the transaction time of a relationship must be contained by the intersection of the transaction times of the participating entities. Following the entity and relationship types, we draw our attention to the attributes (Table 11.5); again, we omit attributes whose transaction-time extent is not recorded. The transaction-time support of individual attributes is independent of the associated entity or relationship type, or of other attributes of that entity or relationship type. However, in any case, the transaction-time extent of an attribute's value must be contained in the transaction time of the associated entity or relationship. For each entity and relationship type, decide whether the transaction-time extent should be captured, and if so, its granularity. For each attribute, determine if the transaction time should be recorded, and if so, its granularity. 11.3 LOGICAL DESIGN 355 Table 11.5 Transaction time of attributes. Attribute BACKUP.Year Month Transaction-Time Granularity DAY BACKUP.Date Processed DAY BACKUP.Quirks BACKUP.VTRC Last Date Mod BACKUP.BRDR Last Date Mod BACKUP.ARCH Last Date Mod LOT.Lot ID Num DAY DAY LOT.Lot ID LOT.Gndr Code LOT.Proj Closeout LOT.In-Weight LOT.Owner LOT.Comment LOT.Valid LOT.DBF Valid LOCATION.Hd Cnt MOVE.Hd Cnt DAY DAY DAY DAY DAY DAY DAY DAY DAY DAY CONTAINS. DBF Update RecNo DAY 11.3 Comments Multiple backups might pertain to a particular year and month. Transaction time is recorded to a granularity of DAY, in order to tease apart the sequence of changes. As noted before, because of various consistency checking and cleansing activities, the actual transaction time may be different than the Date Processed. DAY DAY DAY Changes to the attributes of this critical relationship are tracked by recording the transaction time. This is also an important attribute to track. This attribute relates to that of the same name in LOCATION. This attribute species the record number utilized in the update. LOGICAL DESIGN At this point, we have a nontemporal entity-relationship conceptual schema (Figure 11.1), augmented with annotations in prose that describe the time-varying aspects of this schema. These annotations concern the lifespan and transaction-time aspects of entity types and the valid- and transaction-time aspects of relationship types, attributes, and integrity constraints. 356 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN We now map this schema into a logical data model, here, the relational model, resulting in a collection of tables. This mapping is done in two stages. In the rst stage, the temporal annotations are for the most part ignored, thereby arriving at a nontemporal logical schema. This logical schema is then modied to accommodate the time-varying aspects, adding timestamp column(s) and decomposing some tables into multiple constituent tables. Also during this second stage, various SQL assertions and constraints are dened on the tables to capture temporal integrity constraints. 11.3.1 Mapping to Relational Schema In this rst stage, the following mapping actions are performed. We are laconic only because this process doesn't concern time, and so should be familiar to you. Indeed, this stage can be performed automatically by CASE tools, as the steps do not concern temporal aspects. To keep things straight, we use a Roman font for conceptual constructs (e.g., the LOT entity type) and a sans-serif font for logical constructs (e.g., the LOT table). 1. Create a table for each regular entity type (FEEDYARD, APPLICATION). Add columns for each attribute. The primary key is the key of the corresponding entity type. 2. Create a table for each weak entity type (PEN, BACKUP, LOT, DBF FILE). Include the key of the strong entity type as a foreign key. The primary key is a combination of this entity type's partial key and the key of the strong entity type. 3. For each one-to-one relationship type, extend a table corresponding to one of the entity types with the key of the other entity type as a foreign key. We have no such relationship types here. 4. For each one-to-many binary relationship type, either extend a table or create a new table for the relationship type. For the DESCRIBES PEN, DESCRIBES LOT, and CONTAINS relationships, we extend the table on the “one” side (PEN, LOT, and LOT, respectively) with the key of the other entity type (of BACKUP, of BACKUP, and of DBF FILE, respectively) as a foreign key, as well as the attributes of the relationship. 5. Create a table for each remaining relationship type (MOVE, MASS TRTMNT, LOCATION). Add foreign keys for all participating entity types. The primary key is in general a subset of these foreign keys, but is usually (and in these cases) just the combination of them. 6. Create a table for each multivalued attribute. There are no such attributes here. The result of this rst stage is the nontemporal database schema listed in Figure 11.2, with the primary key columns underlined. We omit some of the FDYD 11.3 LOGICAL DESIGN 357 FDYD ( FDYD_ID, NAME, FDYD_SHORT_NAME, FDYD_MNGR_LNAME,..., UNIQUE (FDYD_SHORT_NAME)) LOT (FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, UNIQUE (FDYD_ID, LOT_ID_NUM, LOT_ID), FOREIGN KEY (FDYD_ID) REFERENCES FDYD, FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP, FOREIGN KEY (A_NAME, DBF_NAME) REFERENCES DBF_FILE ) PEN (FDYD_ID, PEN_AREA, FOREIGN KEY FOREIGN KEY ) PEN_ID, PEN_TYPE_CODE, BUNK_LENGTH, APRON_WIDTH, WATER_SPACE, BKP_ID, (FDYD_ID) REFERENCES FDYD, (FDYD_ID, BKP_ID) REFERENCES BKP APPLICATION (A_NAME, A_DESCRIPTION, A_DATA_DIRECTORY) DBF_FILE (A_NAME, DBF_NAME, DBF_DESCRIPTION, DBF_USED, FOREIGN KEY (A_NAME) REFERENCES APPLICATION ) BKP (FDYD_ID, BKP_ID, YEAR_MONTH, DATE_PROCESSED, QUIRKS, VTRC_LAST_DATE_MOD, BRDR_LAST_DATE_MOD, ARCH_LAST_DATE_MOD, FOREIGN KEY (FDYD_ID) REFERENCES FDYD ) Figure 11.2 Initial nontemporal logical schema (continued on page 358). columns to save space. Finally, we've changed a few table and column names to reect the actual names that Brad used. In Figure 11.3, the same (nontemporal) schema is shown using the crow's-feet notation employed by the PowerDesigner tool that Brad used to create the schema. The diamonds represent foreign keys, the crow's feet represent relationships that are many participation, the small circles denote optional participation, and the small slashes across links denote mandatory participation. 11.3.2 Applying Temporal Annotations In this second stage, we apply the temporal annotations, elaborated in Section 11.2.2. As we are revisiting the ground traversed in previous chapters, back point- 358 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN LOT_MOVE (FDYD_ID, LOT_ID_NUM, FROM_PEN_ID, TO_PEN_ID, HD_CNT, BKP_ID, A_NAME, DBF_NAME, FOREIGN KEY (FDYD_ID, FROM_PEN_ID) REFERENCES PEN(FDYD_ID, PEN_ID), FOREIGN KEY (FDYD_ID, TO_PEN_ID) REFERENCES PEN(FDYD_ID, PEN_ID), FOREIGN KEY (A_NAME, DBF_NAME) REFERENCES DBF_FILE, FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT, FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP ) LOT_LOC (FDYD_ID, LOT_ID_NUM, PEN_ID, HD_CNT, YEAR_MONTH, FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT, FOREIGN KEY (FDYD_ID, PEN_ID) REFERENCES PEN ) MASS_TRTMNT (FDYD_ID, LOT_ID_NUM, PEN_ID, M_TRTMNT_AVG_WGT, M_TRTMNT_CODE, M_TRTMNT_HD, BKP_ID, FOREIGN KEY (FDYD_ID, PEN_ID) REFERENCES PEN, FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT, FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP ) Figure 11.2 (continued) ers (in the form of page numbers in parentheses) are provided to the pages that introduce these approaches via the case studies, providing elaboration and other alternatives. User-Dened Time Attributes Each attribute is mapped to a column in the associated table. Attributes that record user-dened time values are differentiated by type: an instant (page 26), an interval (page 30), or a period (page 89). All temporal values have a granularity (page 74), though some DBMSs x the granularity of their temporal type(s). For anchored values (instants and periods), SQL-92 and some DBMSs allow a specied time zone to be stored (page 29). For the rest, the time zone is either implicit or xed. “Now” should be represented with “forever,” or a close approximation (page 120). Periods may be represented as a pair of instants (page 89), whether the representation of each of the delimiting instants is For each attribute that is a closed (contained in the period) or open (just outside the peuser-dened time, choose a riod). A closed-open period representation, in which the end granularity supported by timestamp species the granule after the last granule of the SQL-92. period, is preferable (page 91). The time zone, if any, may be stored with the rst instant (page 90). 11.3 LOT LOT_LOC LOT_ID_NUM HD_CNT LOT_ID MASS_TRTMNT FDYD GNDR_CODE FDYD_ID PROJ_CLOSEOUT NAME MNGR_LNAME … LOGICAL DESIGN M_TRTMNT_AVG_WGT M_TRTMNT_CODE IN_WEIGHT M_TRTMNT_HD VALID OWNER LOT_MOVE COMMENT HD_CNT PEN PEN_ID PEN_TYPE_CODE FROM TO BUNK_LENGTH APRON_WIDTH PEN_AREA WATER_SPACE APPLICATION DBF_FILE A_NAME DBF_NAME A_DESCRIPTION DBF_DESCRIPTION A_DATE_DIRECTORY DBF_USED BKP BKP_ID YEAR_MONTH DATE_PROCESSED QUIRKS VTRC_LAST_DATE_MOD BRDR_LAST_DATE_MOD ARCH_LAST_DATE_MOD Figure 11.3 A nontemporal crow's-feet schema. 359 360 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN There are six user-dened time columns: LOT.PROJ CLOSEOUT, of type DATE; BKP. YEAR MONTH, of type CHAR (since SQL-92 has no instant type of a MONTH granularity); BKP.PROCESSED, of type DATE; and the last three LAST DATE MOD columns in BKP, of type DATE. Entity Lifespans To each table corresponding to an entity type for which the lifespan, or valid time of an associated attribute, is captured (page 114), there are two alternatives for timestamps. One possibility is a single time specifying (1) when the entity occurred, if it is instantaneous, (2) when the entity's lifespan began, if the entity has duration, or (3) when an attribute became valid. Another possibility is a period of validity (page 116), generally represented with two instants, start and end. If the entity's lifespan consists of several disjoint periods, or if attributes change values over time, a single entity will be mapped to several rows in the corresponding table. One entity type has a recorded lifespan: LOT. Hence, we add FROM DATE and TO DATE columns to record the individual periods of that lifespan. Code Fragment 11.1 LOT is a valid-time state table. ALTER TABLE LOT ADD COLUMN FROM_DATE DATE ALTER TABLE LOT ADD COLUMN TO_DATE DATE Relationship Valid Time To each table corresponding to a relationship type with a recorded valid-time extent or having attribute(s) whose valid time is recorded, we add either instant or period timestamps. For tables corresponding to As indicated in Table 11.1, the valid time of three relationentity and relationship types for ship types, LOCATION, MOVE, and MASS TRTMNT, is recorded. which valid time is to be The LOCATION relationships have a temporal duration; relarecorded, add either a single tionships of the other two relationship types are instantaneous. instant timestamp column or a The LOT LOC table has an interesting timestamp, consisting of period timestamp, represented four (!) columns: FROM DATE, FROM MOVE ORDER, TO DATE, and TO with two instant timestamp MOVE ORDER. Recall that cattle can be moved twice (or more) in a columns. day; the move order differentiates these moves. Code Fragment 11.2 ALTER ALTER ALTER ALTER TABLE TABLE TABLE TABLE LOT LOC is a valid-time state table. LOT_LOC LOT_LOC LOT_LOC LOT_LOC ADD ADD ADD ADD COLUMN COLUMN COLUMN COLUMN FROM_DATE DATE FROM_MOVE_ORDER INT TO_DATE DATE TO_MOVE_ORDER INT For instantaneous relationship types, an instant timestamp is added to the associated table. For the LOT MOVE table, we add AT DATE and AT MOVE ORDER. 11.3 Code Fragment 11.3 LOGICAL DESIGN 361 LOT MOVE is a valid-time event table. ALTER TABLE LOT_MOVE ADD COLUMN AT_DATE DATE ALTER TABLE LOT_MOVE ADD COLUMN AT_MOVE_ORDER INT Code Fragment 11.4 MASS TRTMNT is a valid-time event table. ALTER TABLE MASS_TRTMNT ADD COLUMN AT_DATE DATE Valid Time of Attributes All attributes have a valid time; sometimes this time is recorded. If so, it is associated with a granularity. If the lifespan of the associated entity or the valid time of the associated relationship is not recorded, the time-varying columns should be placed in a separate table, along with the primary key of the original table, which also serves as a foreign key to that table. This task is termed temporal support decomposition. Fortunately, the only time-varying attributes listed in Table 11.2 are those associated with the LOT and LOCATION entity types, both of which have a recorded valid time. Symmetrically, if this time is recorded, but the valid time of an attribute is not recorded, it may be useful to put that column in a separate table, with a foreign key referencing the original, time-varying table. Another rub occurs when the granularity of the attribute is ner than that of the entity or relationship type to which the Decompose tables so that all attribute is attached. In such situations, there are two possible attributes of a table have an paths. Either we can change the granularity of the associated identical temporal support and table to that of the column (say, from YEAR to DAY), or we can precision. break off those columns(s) into a separate table, termed precision decomposition. The attributes of the LOT entity type all have the same granularity (DAY) as LOT itself; the Hd Cnt attribute of LOCATION has a granularity of DAY, which is coarser than the granularity (Sub-DAY) of the associated relationship type. Our analysis thus indicates that neither avor of decomposition applies to this schema. Transaction Time For each table associated with an entity or relationship type for whose transactiontime periods are recorded, or that is associated with attribute(s) whose transaction-time periods are recorded (page 249), there are two basic alternatives: instant-stamped or period-stamped tables. For an instant-stamped table, the choices are a tracking log, a restricted backlog, or a general backlog. A tracking log is a transaction-time table that retains the original, snapshot table (page 220). Its schema comprises the columns of the 362 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN monitored table, along with a single transaction timestamp column, indicating when the transaction committed. The value of For tables corresponding to entity and relationship types for the timestamp column can never extend past now (page 249). A backlog is a transaction-time table with an additional column, which transaction time is to be the operation, which may be an insertion, a deletion, or an uprecorded, add either two timestamps denoting the period date (page 233). In some cases, a restricted backlog, with insertions not recorded (page 220), is perfectly ne; in most other of presence or a single cases, it is best to go with the fully general backlog, using aftertransaction timestamp, images consistently (page 235). optionally with an additional The other alternative is a table with a period timestamp indioperation column, if the table is cating the period of presence (page 254), generally represented to be a backlog. with two instants, start and end, specifying the period starting when the row was inserted or updated and ending when the period was removed, as a side effect of a deletion or update. For the LOT table, we use period timestamps, adding two columns of the appropriate granularity to the associated tables. For the LOT MOVE, LOT LOC, and BKP tables, we use an instant timestamp, specically, a backlog containing after-images. Code Fragment 11.5 LOT, LOT MOVE, LOT LOC, and BKP are transaction-time tables. ALTER TABLE LOT ADD COLUMN START_DATE DATE ALTER TABLE LOT ADD COLUMN STOP_DATE DATE ALTER TABLE LOT_MOVE ADD COLUMN WHEN_CHANGED DATE ALTER TABLE LOT_MOVE ADD COLUMN OPERATION CHAR(1) ALTER TABLE LOT_LOC ADD COLUMN WHEN_CHANGED DATE ALTER TABLE LOT_LOC ADD COLUMN OPERATION CHAR(1) ALTER TABLE BKP ADD COLUMN WHEN_CHANGED DATE ALTER TABLE BKP ADD COLUMN OPERATION CHAR(1) As the LOT, LOT MOVE, and LOT LOC tables already had valid timestamps, adding transaction-time support renders them bitemporal (page 279). As with valid time, we must also consider temporal support decomposition. Basically, the tables should be decomposed unTransaction-time support may til the temporal support (which includes the details of whether induce additional temporal valid time is recorded, whether transaction time is recorded, and support decomposition. the granularity of each) of all attributes is identical. There is one place in this schema where temporal decomposition is indicated. Most of the attributes in LOT are bitemporal, but BKP ID, A NAME, DBF NAME, and DBF UPDATE RECNO, because they were obtained from the CONTAINS relationship type, which records only transaction time, do not vary in valid time, and thus differ from 11.3 LOGICAL DESIGN 363 the other attributes in that table in their temporal support. We move those attributes to a separate table, LOT CONTAINS, include the primary key of LOT, and transfer the foreign keys involving these attributes to LOT CONTAINS. Finally, we make LOT CONTAINS a backlog. Code Fragment 11.6 ALTER ALTER ALTER ALTER TABLE TABLE TABLE TABLE Move the BKP ID, A NAME, DBF NAME, and DBF UPDATE RECNO columns into a separate backlog table. LOT LOT LOT LOT DROP DROP DROP DROP COLUMN COLUMN COLUMN COLUMN BKP_ID A_NAME DBF_NAME DBF_UPDATE_RECNO CREATE TABLE LOT_CONTAINS (FDYD_ID, LOT_ID_NUM, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, WHEN_CHANGED DATE, OPERATION CHAR(1), PRIMARY KEY (FDYD_ID, LOT_ID_NUM), FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT, FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP, FOREIGN KEY (A_NAME, DBF_FILE) REFERENCES DBF_FILE ) Primary Keys Primary keys are handled differently for valid-time, transaction-time, and bitemporal tables, which we'll consider in order. If the entity (or relationship) type captures neither valid nor transaction time, the primary key remains as specied in the initial logical schema. This case applies to the FDYD, PEN, APPLICATION, and DBF FILE tables in Figure 11.2 on page 357. For entity types, we previously differentiated instantaneous entity types from entity types that have a temporal duration. All of these aspects will come into play when determining precisely what comprises the primary and foreign keys for the tables, as well as what additional assertions are required to correctly reect the ER schema as tables. Integrity constraints (ICs) for valid-time tables can be classiA valid-time sequenced primary ed according to whether they apply to the current state, termed a current IC (page 123); apply to each point in time indepenkey may require an assertion dently, termed a sequenced IC (page 118); or apply to the table and an additional surrogate treating the timestamp as just another column(s), termed a nonidentier column; there are sequenced IC (page 123). three cases. It is easy to confound keys in the conceptual ER schema with keys in the logical relational schema. To keep them straight, we strictly follow the terminological convention of referring to conceptual keys without the adjectives “primary” or “foreign” (e.g., the key of the LOT entity type) 364 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN The Bulova Accutron This watch advanced chronometry in two ways when it was introduced in 1960: it guaranteed a precision of at least a minute a month (2 seconds a day), and ensured that this guarantee would hold over the life of the watch. Previous watches, even if they started out with high precision, gradually became less accurate due to wear and the changing viscosity of the lubrication between moving parts. The Accutron did not use a pendulum to regulate an uncoiling spring; rather, it used the vibrations of an electrically driven tuning fork to advance the hands. This fork vibrated at 360 Hz, which moved a tiny arm back and forth, turning a miniscule ratchet wheel with 300 microscopic teeth, each separated from the next by a distance of 0.001 inch. Due to the very small forces involved, there is no wear, and since there is no oil at the tuning fork, the watch will hold its rate far better than a lubricated timepiece. The drawback is the difculty of repair; Bulova provides microscope kits for this purpose. and to logical keys with “primary” or “foreign” adjectives (e.g., the primary key of the LOT table). Also, logical keys may be current, sequenced, or nonsequenced, but conceptual keys never are. The primary key of a table associated with an entity or relationship type capturing its valid-time extent is a sequenced primary key. We have three cases to consider: Case 1 The entity or relationship type is instantaneous and the valid-time instant is recorded. A particular entity could occur at multiple points in time. A sequenced primary key constraint is required, but is especially easy to state for instantaneous entities and relationships: the timestamp column is added to the primary key of the associated table. This case applies to the MASS TRTMNT table. Case 2 The entity type has lifespan with duration, and the lifespan is recorded. An entity whose lifespan has duration raises the question of how to identify that two rows, with different primary key values, are associated with the same entity. The approach is to add a new column, a surrogate identier column, to the table, which then constitutes a time-invariant key, even as the original key varies over time. (As we'll see on page 378, sometimes the surrogate identier column is not required.) The surrogate identier column should be made the sequenced primary key of the table. Such keys cannot be expressed solely using SQL-92's PRIMARY KEY construct (page 117). Adding the start time of the timestamp of the row, or the end time, or both, does not serve to convert a nontemporal key to a sequenced key (page 118). Instead, a sequenced primary key can be expressed as an SQL assertion 11.3 LOGICAL DESIGN 365 or table constraint (page 118); to keep SQL happy, we also add FROM DATE to the declared primary key. Two other changes are required: (a) add an assertion stating that the combination of the surrogate column and the original primary key is sequenced unique, and (b) replace all foreign keys referencing this table with the new surrogate column. This case is not present in the example schema. Case 3 The relationship type has a valid-time extent, which is recorded. The original primary key on the valid-time state table should be interpreted as a sequenced primary key, which can be expressed as an SQL assertion or table constraint (page 118); we also add FROM DATE to the declared primary key. This case is not present. Code Fragment 11.7 MASS TRTMNT's primary key is valid-time sequenced. ALTER TABLE MASS_TRTMNT DROP PRIMARY KEY ALTER TABLE MASS_TRTMNT ADD PRIMARY KEY (FDYD_ID, LOT_ID_NUM, PEN_ID, AT_DATE) For transaction-time tables, things are a little easier because instantaneous tables are not possible. The original primary key on the table should be interpreted as a transaction-time sequenced primary key. As The WHEN CHANGED column contrasted with valid time, such keys can be expressed solely should be added to the primary key of transaction-time tables to using SQL-92's PRIMARY KEY construct, by simply adding the STOP DATE column, which serves to convert the original key to a effect a current, and thus current key, which is equivalent to a sequenced key in the case sequenced, primary key. of a transaction-time table (page 254). BKP and LOT CONTAINS are transaction-time tables. Code Fragment 11.8 The primary key of BKP and LOT CONTAINS is transaction-time sequenced. ALTER TABLE BKP DROP PRIMARY KEY ALTER TABLE BKP ADD PRIMARY KEY (FDYD_ID, BKP_ID, WHEN_CHANGED) ALTER TABLE LOT_CONTAINS DROP PRIMARY KEY ALTER TABLE LOT_CONTAINS PRIMARY KEY (FDYD_ID, LOT_ID_NUM, WHEN_CHANGED) For bitemporal tables, things get more interesting because the two kinds of time must be considered simultaneously. Fortunately, the alternatives combine in the predictable way. 366 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN This schema includes three bitemporal tables, LOT, LOT LOC, and LOT MOVE. The rst is associated with an entity type, and the other two are associated with relationship types. The rst two have a valid-time There are three cases for the extent, and the third is instantaneous. primary key of bitemporal The LOT entity type has a recorded lifespan, so we use the tables, mirroring those for second case for valid time to state that the LOT primary key valid-time tables. is valid-time sequenced/transaction-time sequenced. Again, we implement transaction-time sequenced with transaction-time current. As will be discussed on page 378, for LOT it turns out that the surrogate identier column is not required, so we don't include it here. Code Fragment 11.9 LOT has a valid-time sequenced/transaction-time sequenced primary key of (FDYD ID, LOT ID NUM). ALTER TABLE LOT DROP PRIMARY KEY (FDYD_ID, LOT_ID_NUM) ALTER TABLE LOT ADD PRIMARY KEY (FDYD_ID, LOT_ID_NUM, FROM_DATE, STOP_DATE) CREATE ASSERTION LOT_seq_seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM LOT AS L1 WHERE L1.STOP_DATE = DATE 9999-12-31 AND 1 < (SELECT COUNT(*) FROM LOT AS L2 WHERE L1.FDYD_ID = L2.FDYD_ID AND L1.LOT_ID_NUM = L2.LOT_ID_NUM AND L1.FROM_DATE < L2.TO_DATE AND L2.FROM_DATE < L1.TO_DATE AND L2.STOP_DATE = DATE 9999-12-31)) ) MOVE is an instantaneous relationship type, and thus utilizes the rst case for valid time. We need only add the valid and transaction timestamps to the primary key. Code Fragment 11.10 LOT MOVE has a valid-time sequenced/transaction-time sequenced primary key of (FDYD ID, LOT ID NUM, FROM PEN ID, TO PEN ID). ALTER TABLE LOT_MOVE DROP PRIMARY KEY ALTER TABLE LOT_MOVE ADD PRIMARY KEY (FDYD_ID, LOT_ID_NUM, FROM_PEN_ID, TO_PEN_ID, AT_DATE, AT_MOVE_ORDER, WHEN_CHANGED) 11.3 LOGICAL DESIGN 367 Finally, the key for LOT LOC, being associated with a noninstantaneous relationship type, utilizes the last case for valid time, resulting in a validtime sequenced/transaction-time sequenced primary key. HowFor transaction-time tables ever, because LOT LOC is implemented as a backlog, rather than as implemented as backlogs, only a transaction-time state table, we can't simply check for a STOP the last insert or update entry is DATE of “forever.” Instead, we must use the last relevant entry in relevant. the backlog that is an insert or an update entry. Code Fragment 11.11 LOT LOC has a valid-time sequenced/transaction-time sequenced primary key of (FDYD ID, LOT ID NUM, PEN ID). ALTER TABLE LOT_LOC DROP PRIMARY KEY (FDYD_ID, LOT_ID_NUM, PEN_ID) ALTER TABLE LOT_LOC ADD PRIMARY KEY (FDYD_ID, LOT_ID_NUM, PEN_ID, FROM_DATE, WHEN_CHANGED) CREATE ASSERTION LOT_LOC_seq_seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM LOT_LOC AS L1 -- L1 is the last insert or update entry WHERE (L1.OPERATION = I OR L1.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT_LOC AS L3 WHERE L3.FDYD_ID = L1.FDYD_ID AND L3.LOT_ID_NUM = L1.LOT_ID_NUM AND L3.PEN_ID = L1.PEN_ID AND L3.WHEN_CHANGED > L1.WHEN_CHANGED) AND 1 < (SELECT COUNT(*) FROM LOT_LOC AS L2 WHERE L1.FDYD_ID = L2.FDYD_ID AND L1.LOT_ID_NUM = L2.LOT_ID_NUM AND L1.PEN_ID = L2.PEN_ID AND L1.FROM_DATE < L2.TO_DATE AND L2.FROM_DATE < L1.TO_DATE -- L2 is the last insert or update entry AND (L2.OPERATION = I OR L2.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT_LOC AS L3 WHERE L3.FDYD_ID = L2.FDYD_ID AND L3.LOT_ID_NUM = L2.LOT_ID_NUM AND L3.PEN_ID = L2.PEN_ID AND L3.WHEN_CHANGED > L2.WHEN_CHANGED))) ) 368 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Referential Integrity There are 17 foreign keys specied in Figure 11.2: 7 for the one-to-many binary relationship types, 2 for the many-to-many LOCATION relationship type, 3 for the MASS TRTMNT ternary relationship type, and 5 for the quintary MOVE relationship type. The LOT CONTAINS table also comes with a foreign key (CF-11.6). The original foreign key constraints work ne if the referenced table is nontemporal (assuming that a nontemporal table If the referenced table is contains time-invariant data (page 126), which is the common nontemporal, the original assumption). Most relationship types here are nontemporal, and foreign key constraints may be so the associated referential integrity constraints specied before retained. can remain. Similarly, foreign keys referencing nontemporal tables are ne as is. We're thus satised with LOT ! FDYD, LOT CONTAINS ! DBF FILE, PEN ! FDYD, DBF FILE ! APPLICATION, BKP ! FDYD, LOT MOVE ! PEN (two referential integrity constraints), LOT MOVE ! DBF FILE, LOT LOC ! PEN, and MASS TRTMNT ! PEN. There are six variants of temporal integrity constraints (page 326). However, for referential integrity, the valid-time sequenced Referential integrity on variety is generally indicated. If both tables are valid-time tables, valid-time tables should be then an assertion is required, either on the referencing table inexpressed as a sequenced dividually (page 128), or on the referenced table stating that the constraint. histories are contiguous and on the referenced table stating that the history is contained in that of the referenced table (page 129). Ensuring the histories are contiguous can be done by lling the gaps in the referenced table (page 180). No foreign key constraints here apply to valid-time tables. If both tables are transaction-time tables, transaction-time current constraints sufce, which can be implemented by adding the STOP DATE to the foreign key (page 254). This also works for LOT MOVE ! BKP; since LOT MOVE is valid timestamped with an instant, we can ignore the valid time in the referential integrity constraint. Code Fragment 11.12 (LOT MOVE.FDYD ID, LOT MOVE.BKP ID) is a nonsequenced/current foreign key for BKP. ALTER TABLE LOT_MOVE DROP FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP ALTER TABLE LOT_MOVE ADD FOREIGN KEY (FDYD_ID, BKP_ID, WHEN_CHANGED) REFERENCES BKP If the referencing table is a nontemporal table (e.g., PEN ! BKP), then the most recent transaction-time state should be used. As BKP is a backlog, we employ the trick of CF-11.11 of using the last entry (or entries) in the backlog that is an insert or an update entry. 11.3 Code Fragment 11.13 LOGICAL DESIGN 369 (PEN.FDYD ID, PEN.BKP ID) is a transaction-time current foreign key for BKP. ALTER TABLE PEN DROP FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP CREATE ASSERTION PEN__Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM PEN AS P WHERE NOT EXISTS ( SELECT * FROM BKP AS B WHERE P.FDYD_ID = B.FDYD_ID AND P.BKP_ID = B.BKP_ID AND (B.OPERATION = I OR B.OPERATION = U) AND NOT EXISTS ( SELECT * FROM BKP AS B2 WHERE B2.FDYD_ID = B.FDYD_ID AND B2.BKP_ID = BKP._ID AND B2.WHEN_CHANGED > B.WHEN_CHANGED))) ) For a valid-time table referencing a transaction-time table, a current/current constraint is appropriate. In the case of MASS TRTMNT ! BKP, the referencing table is an instant-stamped table, so we use a valid-time nonsequenced constraint, simply ignoring the valid time. Code Fragment 11.14 (MASS TRTMNT.FDYD ID, MASS TRTMNT.BKP ID) is a nonsequenced/ current foreign key for BKP. ALTER TABLE MASS_TRTMNT DROP FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP CREATE ASSERTION MASS_TRTMNT__Curr_Curr_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM MASS_TRTMNT AS M WHERE NOT EXISTS ( SELECT * FROM BKP AS B WHERE M.FDYD_ID = B.FDYD_ID AND M.BKP_ID = B.BKP_ID continued on page 370 370 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN continued from page 369 ) AND (B.OPERATION = I OR B.OPERATION = U) AND NOT EXISTS ( SELECT * FROM BKP AS B2 WHERE B2.FDYD_ID = B.FDYD_ID AND B2.BKP_ID = B.BKP_ID AND B2.WHEN_CHANGED > B.WHEN_CHANGED))) For foreign keys involving bitemporal tables, we use an assertion to ensure that the foreign key is valid-time sequenced, on For foreign keys referencing the current state of the two tables (page 329), with variations bitemporal tables, if the if one of the two tables doesn't have valid-time or transactionreferencing table supports time support, or if one or both of the tables is associated with transaction time, use a an instantaneous entity or relationship type. transaction-time current For this schema, we need to consider the referential integrity constraint. If the referencing constraints in Table 11.1 that arise from the time-varying MOVE, table is instant-stamped in valid LOCATION, and MASS TRTMNT relationship types. However, time, simply ignore the valid only the LOT participating entity type has a recorded lifespan, time. so we are left with ve foreign key constraints to consider further: LOT CONTAINS ! BKP, LOT MOVE ! LOT, LOT LOC ! LOT, MASS TRTMNT ! LOT, and LOT CONTAINS ! LOT. To specify a sequenced/current foreign key constraint between two bitemporal tables, we augment the valid-time sequenced referential integrity assertion with a predicate selecting the currently valid information. For LOT, this translates to checking for a STOP DATE of “forever.” For LOT LOC, which is a backlog containing after-images, we use the last entry trick. Code Fragment 11.15 (LOT LOC.FDYD ID, LOT LOC.LOT ID NUM) is a sequenced/current foreign key for LOT. ALTER TABLE LOT_LOC DROP FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT CREATE ASSERTION LOT_LOC_Seq_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM LOT_LOC AS LL -- LL is one of the last entries WHERE (LL.OPERATION = I OR LL.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT_LOC AS L3 11.3 )) LOGICAL DESIGN 371 WHERE L3.FDYD_ID = LL.FDYD_ID AND L3.LOT_ID_NUM = LL.LOT_ID_NUM AND L3.PEN_ID = LL.PEN_ID AND L3.WHEN_CHANGED > LL.WHEN_CHANGED) AND (NOT EXISTS ( SELECT * FROM LOT AS L WHERE LL.FDYD_ID = L.FDYD_ID AND LL.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND L.FROM_DATE <= LL.FROM_DATE AND LL.FROM_DATE < L.TO_DATE) OR NOT EXISTS ( SELECT * FROM LOT AS L WHERE LL.FDYD_ID = L.FDYD_ID AND LL.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND L.FROM_DATE < LL.TO_DATE AND LL.TO_DATE <= L.TO_DATE) OR EXISTS (SELECT * FROM LOT AS L WHERE LL.FDYD_ID = L.FDYD_ID AND LL.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND LL.FROM_DATE < L.TO_DATE AND L.TO_DATE < LL.TO_DATE AND NOT EXISTS ( SELECT * FROM LOT AS L2 WHERE L2.FDYD_ID = L.FDYD_ID AND L2.LOT_ID_NUM = L.LOT_ID_NUM AND L2.STOP_DATE = DATE 9999-12-31 AND L2.FROM_DATE <= L.TO_DATE AND L.TO_DATE < L2.TO_DATE))) The LOT CONTAINS table is a transaction-time table with a foreign key to LOT. For transaction time we need only consider the most recent additions to the table, so this can be implemented as a transaction-time current foreign key. Since LOT also records valid time, we utilize the current valid-time state. 372 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Code Fragment 11.16 (LOT CONTAINS.FDYD ID, LOT CONTAINS.LOT ID NUM) is a current/ current foreign key for LOT. ALTER TABLE LOT_CONTAINS DROP FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT CREATE ASSERTION LOT_CONTAINS_Current_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM LOT_CONTAINS AS C WHERE (C.OPERATION = I OR C.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT_CONTAINS AS C2 WHERE C2.FDYD_ID = C.FDYD_ID AND C2.LOT_ID_NUM = C.LOT_ID_NUM AND C2.WHEN_CHANGED > C.WHEN_CHANGED) AND NOT EXISTS ( SELECT * FROM LOT AS L WHERE C.FDYD_ID = L.FDYD_ID AND C.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND L.FROM_DATE <= CURRENT_DATE AND CURRENT_DATE < L.TO_DATE)) ) For LOT CONTAINS ! BKP, both the referencing and referenced tables are transaction-time tables. This translates into a transaction-time current integrity constraint. As both tables are backlogs, we need to get the most recent entry from each. Code Fragment 11.17 (LOT CONTAINS.FDYD ID, LOT CONTAINS.BKP ID) is a transactiontime current foreign key for BKP. ALTER TABLE LOT_CONTAINS DROP FOREIGN KEY (FDYD_ID, BKP_ID) REFERENCES BKP CREATE ASSERTION LOT_CONTAINS_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM LOT_CONTAINS AS C -- C is the last relevant entry WHERE (C.OPERATION = I OR C.OPERATION = U) AND NOT EXISTS ( SELECT * 11.3 ) LOGICAL DESIGN 373 FROM LOT_CONTAINS AS C2 WHERE C2.FDYD_ID = C.FDYD_ID AND C2.LOT_ID_NUM = C.LOT_ID_NUM AND C2.WHEN_CHANGED > C.WHEN_CHANGED) -- There is not a match for C in BKP AND NOT EXISTS ( SELECT * FROM BKP AS B WHERE B.FDYD_ID = C.FDYD_ID AND B.BKP_ID = C.BKP_ID -- B is the last relevant entry AND (B.OPERATION = I OR B.OPERATION = U) AND NOT EXISTS ( SELECT * FROM BKP AS B2 WHERE B2.FDYD_ID = B.FDYD_ID AND B2.BKP_ID = B.BKP_ID AND B2.WHEN_CHANGED > B.WHEN_CHANGED))) For a sequenced referential integrity constraint from an event table to a state table, each instant timestamp in the referencing table must be contained in a period timestamp of the referenced table. Code Fragment 11.18 (LOT MOVE.FDYD ID, LOT MOVE.LOT ID NUM) is a sequenced/current foreign key for LOT. ALTER TABLE LOT_MOVE DROP FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT CREATE ASSERTION LOT_MOVE_Seq_Current_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM LOT_MOVE AS M WHERE (M.OPERATION = I OR M.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT_MOVE AS M2 WHERE M2.FDYD_ID = M.FDYD_ID AND M2.LOT_ID_NUM = M.LOT_ID_NUM AND M2.FROM_PEN_ID = M.FROM_PEN_ID AND M2.TO_PEN_ID = M.TO_PEN_ID AND M2.WHEN_CHANGED > M.WHEN_CHANGED) continued on page 374 374 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN continued from page 373 AND NOT EXISTS ( ) SELECT * FROM LOT AS L WHERE M.FDYD_ID = L.FDYD_ID AND M.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND L.FROM_DATE <= M.AT_DATE AND M.AT_DATE < L.TO_DATE)) This is shorter than CF-11.15 because for each row of LOT MOVE, For foreign keys over bitemporal there need be only one row of LOT whose period of validity contains the (instant) lifespan. In contrast, for each row of LOT LOC, tables, use sequenced/current many rows from LOT may coordinate to contain LOT LOC's period constraints. of validity. In general, for foreign keys over bitemporal tables, use sequenced/current constraints, unless one of the participating tables doesn't include valid- or transaction-time support or is associated with an instantaneous entity or relationship type, in which case the assertion is simplied. The nal foreign key to consider, MASS TRTMNT ! LOT, is even simpler because MASS TRTMNT does not record transaction time. Code Fragment 11.19 (MASS TRTMNT.FDYD ID, MASS TRTMNT.LOT ID NUM) is a valid-time sequenced foreign key for LOT. ALTER TABLE MASS_TRTMNT DROP FOREIGN KEY (FDYD_ID, LOT_ID_NUM) REFERENCES LOT CREATE ASSERTION MASS_TRTMNT_Seq_Referential_Integrity CHECK (NOT EXISTS ( SELECT * FROM MASS_TRTMNT AS M WHERE NOT EXISTS ( SELECT * FROM LOT AS L WHERE M.FDYD_ID = L.FDYD_ID AND M.LOT_ID_NUM = L.LOT_ID_NUM AND L.STOP_DATE = DATE 9999-12-31 AND L.FROM_DATE <= M.AT_DATE AND M.AT_DATE < L.TO_DATE)) ) We have now considered the implications of time-varying tables on all the foreign key constraints. 11.4 PHYSICAL DESIGN 375 Uniqueness Constraints The temporal analog of UNIQUE is sequenced uniqueness, which requires a table constraint (page 124). Other forms (current, value-equivalent, nonsequenced) are less useful, as they are more representational than semantic (page 139). FDYD SHORT NAME is unique. Since FDYD does not record valid time, the original UNIQUE statement may be retained. Concerning the LOT table, (FDYD ID, LOT ID NUM, LOT ID) is also unique. Since this relation is bitemporal, this corresponds to sequenced/current uniqueness, which requires an assertion. Code Fragment 11.20 (LOT.FDYD ID, LOT.LOT ID) is sequenced/current unique. ALTER TABLE LOT DROP UNIQUE (FDYD_ID, LOT_ID) ALTER TABLE LOT ADD ASSERTION LOT_ID_Seq_Curr_UNIQUE CHECK (NOT EXISTS ( SELECT * FROM LOT AS L1 WHERE L1.STOP_DATE = DATE 9999-12-31 AND 1 < (SELECT COUNT(*) FROM LOT AS L2 WHERE L1.FDYD_ID = L2.FDYD_ID WHERE L1.LOT_ID = L2.LOT_ID WHERE L1.LOT_ID_NUM = L2.LOT_ID_NUM AND L2.STOP_DATE = DATE 9999-12-31 AND L1.FROM_DATE < L2.TO_DATE AND L2.FROM_DATE < L1.TO_DATE)) ) 11.4 PHYSICAL DESIGN There is a sharp line between logical and physical design: logical design concerns preserving the semantics of the application as expressed in the ER schema, and physical design concerns ensuring efcient execution of application queries and modications. Physical design should properly be done after logical design, so that efciency considerations do not muddy the semantics. Conventional physical design involves specifying indexes and storage structures, and perhaps decomposing tables or merging tables. That some tables are timevarying adds temporal partitioning to this phase of the design. Tables with a valid-time extent can be temporally partitioned into a current store containing only current information and a history store storing data that became invalid before “now” (page 206). 376 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Crystal Clocks The longer the pendulum, or the longer the coiled spring, the more accurate the clock. However, physical constraints bound the achievable precision. The next advance exploited the “piezoelectric effect” of a quartz crystal, which vibrates when an electronic current of the correct frequency is applied to it. A quartz crystal can thereby replace the pendulum or hairspring as the resonator with a battery and simple electronic circuit providing the energy. Although a quartz oscillator will drift with temperature and with age, it is accurate to tenths of a second a day, due to its frequency of 32,768 Hz versus 360 Hz in an Accutron. A crystal clock is also much easier to manufacture and, hence, has sounded the death knell to mechanical watches. While there are still mechanical watches being manufactured, the attraction is more nostalgic than economic or desire for quality. Consumer Reports did a small experiment, comparing a $3 kid's quartz watch against a $1200 Rolex Oyster Perpetual, a superb mechanical watch. Over 6 days, the kid's watch lost 11 seconds, and the Rolex gained 22 seconds [41]. Mechanical clocks, and perhaps even analog displays, will soon be museum curiosities, right next to slide rules and mercury thermometers. The only valid-time table in this schema is MASS TRTMNT, which is associated with an instantaneous relationship, and thus cannot be temporally partitioned. A transaction-time state table may be temporally partitioned into a current store, an archival store, and possibly the monitored table itself (page 264). Sometimes the monitored table is best dened as a view, generally on the current store; often the state table itself is dened as a view (page 268). If a full backlog is used, the monitored table can be dened as a view on the tracking log (page 235). The only transaction-time tables are BKP and LOT CONTAINS, which we retain as audit logs. A bitemporal state table can be temporally partitioned into a current store (current/current), a history store (current in transaction time), and an archival store (not current in transaction time) (page 329). A current store improves the performance of current/current queries, but is awkward to maintain (page 331). A history store will also result in good current/current retrieval performance and is much easier to maintain (page 332). To reduce the space requirements of the archival store, it may be advantageous to store just one transaction timestamp (page 334). We have three bitemporal tables: LOT (a valid-time state/transaction-time state table), LOT LOC (a valid-time state/audit log table), and LOT MOVE (a valid-time event/ audit log table). Since most of the queries will be over the valid-time history of cattle coresiding in pens, an appropriate partitioning of the LOT table is a valid-time state/ transaction-time current history store and a valid-time state/transaction-time state archive, since disk space is not at a premium. We'll call the history table LOT and create a new archive table, LOT Archive. 11.5 Code Fragment 11.21 ADVANCED DESIGN ASPECTS* 377 Partition LOT into a history store and an archival store. ALTER TABLE LOT DROP COLUMN STOP_DATE CREATE TABLE LOT_Archive (FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, STOP_DATE, PRIMARY KEY (FDYD_ID, LOT_ID_NUM, FROM_DATE, STOP_DATE) ) CREATE ASSERTION LOT_Archive_seq_seq_primary_key CHECK (NOT EXISTS ( SELECT * FROM LOT_Archive AS L1 WHERE L1.STOP_DATE = DATE 9999-12-31 AND 1 < (SELECT COUNT(*) FROM LOT_Archive AS L2 WHERE L1.FDYD_ID = L2.FDYD_ID AND L1.LOT_ID_NUM = L2.LOT_ID_NUM AND L1.FROM_DATE < L2.TO_DATE AND L2.FROM_DATE < L1.TO_DATE AND L2.STOP_DATE = DATE 9999-12-31)) ) Foreign key assertions that reference LOT (CF-11.15, CF-11.16, CF-11.18, CF-11.19) substantially remain as they are, except that the WHERE condition LOT.STOP_DATE = DATE 9999-12-31 is no longer needed. Since LOT LOC and LOT MOVE both have instant transaction timestamps, partitioning either into a history store and an archival audit log is possible, but would not have a dramatic impact on integrity constraints or queries. 11.5 ADVANCED DESIGN ASPECTS* The time-varying nature adds a few further wrinkles that can be expressed as temporal annotations to the conceptual schema and mapped to changes to SQL tables. 11.5.1 Additional Temporal Annotations We rst list additional annotations that might be useful to include with the conceptual schema. 378 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Time-Invariant Keys In the nontemporal ER schema, the key of an entity type is assumed to identify an entity at each point in time. We may want to express a stronger integrity constraint, such as that the (Feedyard ID, Pen ID) value identies a particular pen over all time. This is termed a time-invariant key. As all the keys in this schema are nontemporal, they are automatically valid time-invariant. Time-Invariant Uniqueness Constraints In the nontemporal ER schema, the integrity constraints on individual attributes are assumed to hold at each point in time. We may want to express a stronger integrity constraint, such as that the Fdyd Short name for a particular feed yard is unique over all time. This is termed a time-invariant uniqueness constraint , as it applies over the entire lifespan of the entity. As another example, the LOT.Lot ID attribute is also time-invariant unique. Lots enter the feed yard with a Lot ID value. Once that lot has left the feedyard, a subsequently arriving lot could be assigned the same Lot ID value; Lot IDs are reused. So Brad generates a nonreusable Lot ID Num attribute to uniquely identify the lot; this attribute is the partial key for the LOT entity type. While Lot IDs may be reused, for any given lot entity, the Lot ID is unique over all time, termed time-invariant unique. Such constraints are not applicable to attributes associated with instantaneous entity and relationship types. Time-Invariant Participation Constraints This notion of a time-invariant constraint also applies to participation constraints. Conventional participation constraints are assumed to hold at any point in time. So, for example, each in pen relationship denotes a pen located in at most one (actually, exactly one) feed yard at any point in time, and each location relationship denotes cattle from one lot residing in one or more pens, at any point in time. We may want to express a stronger participation constraint, such as that each pen is located in exactly one feed yard over Some key, uniqueness, and all time. If a particular pen is located in a particular feed yard participation constraints may at one point in time, that pen will be located in that same feed hold over the entire lifespan (or yard at all other points of time during the lifespans of the pen valid time) of the associated and feed yard. This is termed a time-invariant participation conentity (or relationship) type, and straint . Such constraints are not applicable to instantaneous reare thus designated as lationship types. time-invariant. Of the relationships in this schema, the LOCATION relationship type has a many-to-many participation constraint applied over its valid-time extent, so this participation constraint is time-invariant. IN PEN, IN LOT, IS DESCRIBED BY, CREATES, CONTAINS, DESCRIBES PEN, and 11.5 ADVANCED DESIGN ASPECTS* 379 DESCRIBES LOT are nontemporal relationship types, and so their nontemporal participation constraints are also valid across their lifespan. The MOVE and MASS TRTMNT relationship types model instantaneous events. Transaction Time-Invariant Constraints As with valid time, we also consider whether the integrity constraints hold over the entire transaction-time period. Two of the entity types, LOT and BACKUP, have transaction-time support, so we must consider whether we wish to record the values of their key attributes as they vary. The (partial) key of the LOT entity, Lot ID Num, is generated when the data is loaded. As such, it normally doesn't change, unless some data is later discovered to be dirty and subsequently corrected. Hence, the Lot ID Num can possibly vary over transaction time. The partial key for BACKUP, BKP ID, is generated when the backup is taken, and so is invariant in transaction time. No attribute listed in Table 11.5 is transaction time-invariant unique. While DESCRIBES PEN and DESCRIBES LOT are many-to-one relationship types, they are both transaction time-invariant many-to-many because a particular pen or lot entity can be described by several backup entities Also consider whether the key, at different transaction times. Similarly, the LOCATION, MOVE, uniqueness, and participation and MASS TRTMNT relationship types all have transaction timeconstraints hold over the entire invariant participation constraints of many-to-many. transaction-time extent. Temporal Specialization Temporal specialization indicates whether the valid timestamp (or lifespan) and trans- action timestamp of an entity, relationship, or attribute are coupled. One entity type, LOT, is bitemporal; two relationship types, MOVE and LOCATION, are also bitemporal. LOCATION is a fully general bitemporal relationship type (also termed nonspecialized). A transaction changing the database—specically, the location of a lot of cattle in a pen—can mention a valid time Classify each bitemporal entity in the past, if some information is being corrected, or in the fuand relationship type as fully ture, if moves in the future are anticipated. There is no a priori general, retroactive, coupling between valid and transaction time for this relationdegenerate, or postactive. ship. MOVE is a retroactive relationship type, denoting that the valid time is always before (or equal to) the transaction time. Move records come directly from the feed yard FoxPro database, and thus concern the past; no updates are possible to a particular move relationship once it has been recorded. 380 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN A degenerate entity type denotes that the beginning of the entity's lifespan exactly corresponds to the beginning of the transaction time. Here, any change in the modeled reality is immediately recorded in the database, so that the valid and transaction times exactly correspond. A nal temporal specialization is a postactive entity or relationship type, in which the valid time is always after (or equal to) the transaction time: modications all concern the future, recording something that will later be true. 11.5.2 Applying Temporal Annotations We map these annotations to SQL constructs. Time-Invariant Keys If the key is valid time-invariant, a surrogate identier column, as discussed on page 364, is not needed, as for example with the LOT table. To ensure that the key is transaction time-invariant, we add an assertion stating that the periods associated with any particA transaction time-invariant ular key value are contiguous, which is a nonsequenced consequenced primary key requires straint (page 129). an assertion stating that the That the primary key for BKP is transaction time-invariant reperiods associated with any quires checking for contiguity, which fortunately is straightforparticular key value are ward on a backlog: the most recent entry cannot be an insert contiguous. entry that followed a previous delete entry. Code Fragment 11.22 BKP's primary key is contiguous. CREATE ASSERTION BKP_Contiguous_History CHECK (NOT EXISTS ( SELECT * FROM BKP AS B, BKP AS B2 WHERE B.WHEN_CHANGED < B2.WHEN_CHANGED AND B.FDYD_ID = B2.FDYD_ID AND B.BKP_ID = B2.BKP_ID AND B.OPERATION = D AND B2.OPERATION = I -- I is the last operation AND NOT EXISTS ( SELECT * FROM BKP AS B3 WHERE B3.FDYD_ID = B.FDYD_ID AND B3.BKP_ID = B.BKP_ID AND B2.WHEN_CHANGED < B3.WHEN_CHANGED) -- There are no operations between the delete and the insert AND NOT EXISTS ( SELECT * FROM BKP AS B3 WHERE B3.FDYD_ID = B.FDYD_ID AND B3.BKP_ID = B.BKP_ID 11.5 ADVANCED DESIGN ASPECTS* 381 Table 11.6 An excerpt of the LOT table. ... LOT ID 17 19 19 ... ... ... ) ... ... ... ... FROM DATE TO DATE 1998-01-01 1998-03-23 1998-05-12 1998-03-23 1998-04-01 9999-12-31 AND B.WHEN_CHANGED < B3.WHEN_CHANGED AND B3.WHEN_CHANGED < B2.WHEN_CHANGED)) Time-Invariant Uniqueness Constraints Time-invariant uniqueness constraints can be specied only if there is a timeinvariant primary key available. Consider the excerpt of the LOT table shown in Table 11.6. Is LOT ID time-invariant unique, that is, having only one value over all time for a particular LOT entity? It is impossible to tell whether the appearance of LOT ID values of 17 and 19 are problematic without knowing which rows are associated with which lots. So, in Table 11.7, we focus on the primary key of the LOT table, (FDYD ID, LOT ID NUM), which has already been specied as a time-invariant primary key. We can now see that this instance violates the time-invariant uniqueness constraint for LOT ID, as a single lot, with a LOT ID Time-invariant uniqueness NUM of 101, has two distinct values for the LOT ID. requires an assertion that the For (FDYD ID, LOT ID) to be time-invariant unique, it must be column(s) are unique with unique with respect to the time-invariant primary key, (FDYD respect to the time-invariant ID, LOT ID NUM). So we replace the assertion in CF-11.20 with the primary key. following assertion. Code Fragment 11.23 (LOT.FDYD ID, LOT.LOT ID) is valid time-invariant unique. ALTER TABLE LOT DROP ASSERTION LOT_ID_Seq_Curr_UNIQUE ALTER TABLE LOT ADD ASSERTION LOT_ID_VT_Invariant_UNIQUE CHECK (NOT EXISTS ( SELECT * FROM LOT AS L1 WHERE 1 < (SELECT DISTINCT COUNT(LOT_ID) FROM LOT AS L2 WHERE L1.FDYD_ID = L2.FDYD_ID AND L1.LOT_ID_NUM = L2.LOT_ID_NUM AND L2.STOP_DATE = DATE 9999-12-31)) ) 382 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Table 11.7 Focusing on the primary key. FDYD ID LOT ID NUM LOT ID 1 1 1 101 101 799 17 19 19 ... ... ... ... FROM DATE TO DATE 1998-01-01 1998-03-23 1998-05-12 1998-03-23 1998-04-01 9999-12-31 Temporal Specialization The valid-time start column may be dropped from a table corresponding to a degenerate entity type. 11.6 A degenerate entity type allows us to simplify the table(s) of that type. Since the beginning of the entity's lifespan (FROM DATE) exactly corresponds to the beginning of transaction time (START DATE), we can omit the latter column and replace all mention of it with the former column. No tables in this schema are degenerate. BENEFITS This case study provides empirical evidence of the efcacy of the design methodology followed in this chapter. Brad spent several months designing an initial logical schema for the 55-odd tables of his applications. He later then worked with the author to design tables following this methodology. The result is a set of two logical schemas drawn from the same requirements, one developed using the traditional approach, in which time is considAtomic Clocks ered from the beginning, and the schema developed here, in which time is considThe cesium atom has a natural vibration at ered only in the second stage of conceptual 9,192,631,770 Hz. If the driving frequency is just and logical design. a little off of that natural frequency of the atom, Brad feels that the latter design is preferit doesn't resonate. Laboratory cesium oscillators able in several ways. In particular, when keep time to about one second in 370,000 years, the methodology is followed and temporal or, alternatively, to about 3 microseconds per year. aspects are added later, rather than in the Satellites in geosynchronous orbit contain initial ER diagram, the following benets atomic clocks and send out timing signals from specic to this case study accrue: them. Small GPS (global positioning system) receivers use triangulation and the speed of light to calculate highly accurate location data; such calculations depends heavily on a highly accurate clock.    The ER diagram was simplied. The semantics of LOT LOC was cleaned up considerably. The valid-time semantics of LOT was highlighted. 11.7       APPLICATION DEVELOPMENT 383 We discovered during this analysis that LOT LOC has a transaction-time component. The transaction-time semantics of BKP was emphasized. Several of the integrity constraints were corrected. Some of the nullable columns were rendered not nullable. Twenty-ve columns were removed. One table and sixteen columns were added, thereby somewhat simplifying the logical model. Queries are easier to express on the revised logical model. Patience, in considering time later, is indeed a virtue. 11.7 APPLICATION DEVELOPMENT We now briey revisit the queries and modications mentioned in Chapter 2, as a review of the approaches discussed at length in the other case studies. 11.7.1 Queries We can express any nontemporal query in the three variants, current, sequenced, and nonsequenced. Note the correspondence between these variants. Current queries are the temporal analog of nontemporal queries. They require a simple addition to the WHERE clause (page 143). Code Fragment 11.24 How many head of cattle from lot 219 in yard 1 are (currently) in each pen? SELECT PEN_ID, HD_CNT FROM LOT_LOC WHERE FDYD_ID = 1 AND LOT_ID_NUM = 219 AND TO_DATE = DATE 9999-12-31 Sequenced queries, which are the “and when” analog of nontemporal queries, must be broken down into their algebraic equivalents to be translated into SQL. Selection, projection, sorting, and union are simple (page 145). Code Fragment 11.25 Give the history of how many head of cattle from lot 219 in yard 1 were in each pen. SELECT PEN_ID, HD_CNT, FROM_DATE, TO_DATE FROM LOT_LOC WHERE FDYD_ID = 1 AND LOT_ID_NUM = 219 Nonsequenced queries, which treat the timestamps as regular columns, are generally difcult to express in English, but relatively straightforward to express in SQL on state tables. 384 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Code Fragment 11.26 How many head of cattle from lot 219 in yard 1 were, at some time, in each pen? SELECT PEN_ID, HD_CNT FROM LOT_LOC WHERE FDYD_ID = 1 AND LOT_ID_NUM = 219 We now turn to temporal joins. Consider the following nontemporal join query. The query involves a self-join on the table, along with projection and selection. The rst predicate ensures that we don't get identical pairs; the second and third predicates test for coresidency. Code Fragment 11.27 Which lots are coresident in a pen (nontemporal version)? SELECT DISTINCT L1.LOT_ID_NUM, L2.LOT_ID_NUM, L1.PEN_ID FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID The current version of this query on the temporal table is constructed by adding a currency predicate (a TO DATE of forever) for each correlation name in the FROM clause. Code Fragment 11.28 Which lots are currently coresident in a pen? SELECT DISTINCT L1.LOT_ID_NUM, L2.LOT_ID_NUM, L1.PEN_ID FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND L1.TO_DATE = DATE 9999-12-31 AND L2.TO_DATE = DATE 9999-12-31 As before, nonsequenced joins are easy to specify: just ignore the timestamp columns. Code Fragment 11.29 Which lots were in the same pen, perhaps at different times? SELECT DISTINCT L1.LOT_ID_NUM, L2.LOT_ID_NUM, L1.PEN_ID FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID A sequenced join is challenging to express in SQL (page 151). We assume that the underlying table contains no (sequenced) duplicates; that is, a lot can be in a pen at most once at any time. 11.7 Code Fragment 11.30 APPLICATION DEVELOPMENT 385 Give the history of lots being coresident in a pen. SELECT L1.LOT_ID_NUM, L2.LOT_ID_NUM, FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND L2.FROM_DATE <= L1.FROM_DATE AND L1.TO_DATE <= L2.TO_DATE UNION SELECT L1.LOT_ID_NUM, L2.LOT_ID_NUM, FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND L1.FROM_DATE > L2.FROM_DATE AND L2.TO_DATE < L1.TO_DATE AND L1.FROM_DATE < L2.TO_DATE UNION SELECT L1.LOT_ID_NUM, L2.LOT_ID_NUM, FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND L2.FROM_DATE > L1.FROM_DATE AND L1.TO_DATE < L2.TO_DATE AND L2.FROM_DATE < L1.TO_DATE UNION SELECT L1.LOT_ID_NUM, L2.LOT_ID_NUM, FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND L2.FROM_DATE >= L1.FROM_DATE AND L2.TO_DATE <= L1.TO_DATE L1.PEN_ID, L1.FROM_DATE, L1.TO_DATE L1.PEN_ID, L1.FROM_DATE, L2.TO_DATE L1.PEN_ID, L2.FROM_DATE, L1.TO_DATE L1.PEN_ID, L2.FROM_DATE, L2.TO_DATE The SQL-92 CASE expression allows this query to be written as a single SELECT statement (page 152). Code Fragment 11.31 Sequenced temporal join using CASE. SELECT L1.LOT_ID_NUM, L2.LOT_ID_NUM, L1.PEN_ID, CASE WHEN L1.FROM_DATE > L2.FROM_DATE THEN L1.FROM_DATE continued on page 386 386 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN continued from page 385 ELSE L2.FROM_DATE END, CASE WHEN L1.TO_DATE > L2.TO_DATE THEN L2.TO_DATE ELSE L1.TO_DATE END FROM LOT_LOC AS L1, LOT_LOC AS L2 WHERE L1.LOT_ID_NUM < L2.LOT_ID_NUM AND L1.FDYD_ID = L2.FDYD_ID AND L1.PEN_ID = L2.PEN_ID AND (CASE WHEN L1.FROM_DATE > L2.FROM_DATE THEN L1.FROM_DATE ELSE L2.FROM_DATE END) < (CASE WHEN L1.TO_DATE > L2.TO_DATE THEN L2.TO_DATE ELSE L1.TO_DATE END) Reconstructing the monitored table at a point in time is a simple query or view on a transaction-time state table (compare with CF-9.7). Code Fragment 11.32 Provide the state of the LOT CONTAINS table on January 12, 1998. SELECT LOT_ID_NUM, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO FROM LOT_CONTAINS WHERE START_TIME <= DATE 1998-01-12 AND DATE 1998-01-12 < STOP_DATE We end with two queries on the bitemporal table LOT, one a sequenced/ nonsequenced query and one a nonsequenced/nonsequenced query. Code Fragment 11.33 Provide the history as best known on March 15, 1998. SELECT LOT_ID_NUM, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT FROM LOT WHERE START_TIME <= DATE 1998-03-15 AND DATE 1998-03-15 < STOP_DATE Code Fragment 11.34 When were steerings scheduled (as opposed to being recorded after the fact)? SELECT S.LOT_ID_NUM, S.FROM_DATE AS When_Scheduled, S.START_DATE AS When_Recorded FROM LOT AS C, LOT AS S WHERE C.FDYD_ID = S.FDYD_ID AND C.LOT_ID_NUM = S.LOT_ID_NUM AND C.GNDR_CODE = c AND S.GNDR_CODE = s 11.7 APPLICATION DEVELOPMENT 387 AND C.TO_DATE = S.FROM_DATE AND S.START_DATE < S.FROM_DATE 11.7.2 Modications When one or more of the tables managed by a legacy application is rendered temporal, all of the modications must be converted to current modications, whose period of applicability is “now” to “forever” (page 216). Modications on bitemporal state tables are written in two stages. First, the modication is transformed according to the valid-time semantics. Second, the resulting SQL statements are further transformed according to the transaction-time semantics (page 286). Current insertions are easy to code in SQL; the second transformation merely requires that the transaction timestamp be included. We illustrate such an insertion on the LOT table. Recall that this table is temporally partitioned into a history store (see CF-11.21), containing those rows with a transaction-stop time of “forever,” and an archival store, containing those rows with a transaction-stop time before “now.” We need not record a transaction-stop time in the LOT table because it is assumed to be “forever.” Code Fragment 11.35 Lot 433 arrives today. INSERT INTO LOT VALUES (1, 433, 7, h, DATE 1998-12-15, 14533, 1, Empire, B, 2, CURRENT_DATE, DATE 9999-12-31, CURRENT_DATE) A logical current deletion in the general scenario (page 183) is implemented as a physical update and a physical delete. But because LOT has transaction-time support, the update and delete cause the previous values to be retained in LOT Archive. The update is transformed into moving the old value to the archival store, thus retaining the new value in the history store. The delete is transformed into moving the row to be deleted to the archival store. Code Fragment 11.36 Lot 101 leaves the feed yard. -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE FDYD_ID = 1 AND LOT_ID_NUM = 101 continued on page 388 388 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN continued from page 387 AND TO_DATE >= CURRENT_DATE AND FROM_DATE < CURRENT_DATE UPDATE LOT SET TO_DATE = CURRENT_DATE WHERE FDYD_ID = 1 AND LOT_ID_NUM = 101 AND TO_DATE >= CURRENT_DATE AND FROM_DATE < CURRENT_DATE -- transformed deletion INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE FDYD_ID = 1 AND LOT_ID_NUM = 101 AND FROM_DATE > CURRENT_DATE DELETE FROM LOT WHERE FDYD_ID = 1 AND LOT_ID_NUM = 101 AND FROM_DATE > CURRENT_DATE These two pairs of statements can be done in either order, as the rows they alter are disjoint, but the insertion into the archival store should occur before the second statement of the pair. In the general scenario, a logical current update is more complicated, as there may exist rows that start in the future, as well as rows that end before “forever.” For the former, only the GNDR CODE need be changed. For the latter, the TO DATE must be retained on the inserted row. Compare with CF-7.11; again, we transform a physical update into an update of the history store and an insertion into the archival store, here, twice. Code Fragment 11.37 The cattle in lot 799 are being steered today. -- transformed insertion INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, s, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, CURRENT_DATE, DATE 9999-123-31, CURRENT_DATE FROM LOT WHERE FDYD_ID = 1 11.7 APPLICATION DEVELOPMENT 389 AND LOT_ID_NUM = 799 AND FROM_DATE <= CURRENT_DATE AND TO_DATE > CURRENT_DATE -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE FDYD_ID = 1 AND LOT_ID_NUM = 799 AND GNDR_CODE <> s AND FROM_DATE < CURRENT_DATE AND TO_DATE > CURRENT_DATE UPDATE LOT SET TO_DATE = CURRENT_DATE WHERE FDYD_ID = 1 AND LOT_ID_NUM = 799 AND GNDR_CODE <> s AND FROM_DATE < CURRENT_DATE AND TO_DATE > CURRENT_DATE -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE FDYD_ID = 1 AND LOT_ID_NUM = 799 AND FROM_DATE >= CURRENT_DATE UPDATE LOT SET GNDR_CODE = s WHERE FDYD_ID = 1 AND LOT_ID_NUM = 799 AND FROM_DATE >= CURRENT_DATE The last pair can appear anywhere, but the second and third statements must occur after the insertion. This store grows monotonically. Note that in a temporally partitioned store, only insertions are applied to the archival store. 390 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN A current modication applies from “now” to “forever.” A sequenced modication generalizes this to apply over a specied period, termed the period of applicability. This period could be in the past, in the future, or overlap “now.” Most of the previous discussion applies to sequenced modications, with CURRENT DATE replaced with the start of the period of applicability of the modication and DATE 9999-12-31 replaced with the end of the period of applicability. In a sequenced insertion, the application provides the period of applicability (page 188). Code Fragment 11.38 Lot 426, a collection of heifers, was on the feed yard from March 26 to April 14. INSERT INTO LOT VALUES (1, 426, 7, h, DATE 1998-12-15, 14533, 1, Empire,  , DATE 1998-03-26, DATE 1998-04-14, CURRENT_DATE) Sequenced deletions (page 190) require a little more work because the period of applicability of the deletion may end before the row ends. Recall that a current deletion in the general scenario is implemented as an update for those currently valid rows, and a delete for periods starting in the future. A sequenced deletion requires seven physical modications. In the following deletion, the period of applicability is DATE 1998-10-01 to DATE 1998-10-22. Code Fragment 11.39 Lot 234 will be absent from the feed yard for the rst three weeks of October, when the steering will take place (applied on a validtime version of LOT). -- transformed insertion INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, DATE 1998-10-22, TO_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE <= DATE 1998-10-01 AND TO_DATE > DATE 1998-10-22 -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-01 AND TO_DATE >= DATE 1998-10-01 11.7 APPLICATION DEVELOPMENT 391 UPDATE LOT SET TO_DATE = DATE 1998-10-01 WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-01 AND TO_DATE >= DATE 1998-10-01 -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-22 AND TO_DATE >= DATE 1998-10-22 UPDATE LOT SET FROM_DATE = DATE 1998-10-22 WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-22 AND TO_DATE >= DATE 1998-10-22 -- transformed deletion INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE >= DATE 1998-10-01 AND TO_DATE <= DATE 1998-10-22 DELETE FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE >= DATE 1998-10-01 AND TO_DATE <= DATE 1998-10-22 Updates are equivalent to a current deletion followed by a current insertion, and so can be implemented that way, taking care to correlate these two modications (pages 186 and 194). The rst transformation of a sequenced update yields two insertions and three updates; the second transformation explodes this into eight statements. In the following sequenced update, the period of applicability is DATE 1998-03-01 to DATE 1998-04-01. 392 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN Code Fragment 11.40 The lot was steered only for the month of March. -- transformed insertion INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, DATE 1998-03-01, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-03-01 AND TO_DATE > DATE 1998-03-01 -- transformed insertion INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, IN_WEIGHT, VALID, OWNER, COMMENT, DATE 1998-04-01, TO_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-04-01 AND TO_DATE > DATE 1998-04-01 PROJ_CLOSEOUT, -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-04-01 AND TO_DATE > DATE 1998-03-01 UPDATE LOT SET GNDR_CODE = s WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-04-01 AND TO_DATE > DATE 1998-03-01 -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 799 11.7 APPLICATION DEVELOPMENT 393 AND FROM_DATE < DATE 1998-03-01 AND TO_DATE > DATE 1998-03-01 UPDATE LOT SET FROM_DATE = DATE 1998-03-01 WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-03-01 AND TO_DATE > DATE 1998-03-01 -- transformed update INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-04-01 AND TO_DATE > DATE 1998-04-01 UPDATE LOT SET TO_DATE = DATE 1998-04-01 WHERE LOT_ID_NUM = 799 AND FROM_DATE < DATE 1998-04-01 AND TO_DATE > DATE 1998-04-01 Nonsequenced modications (page 197) are rare. They are generally easy to implement in SQL (since they are representational in nature). As with constraints and queries, a nonsequenced modication treats the timestamps identically to the other columns. A (nonsequenced/current) deletion turns into a pair of statements that move the row to the archival store. Code Fragment 11.41 Delete the records of lot 234 that have duration greater than three months. -- transformed deletion INSERT INTO LOT_Archive SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, TO_DATE, START_DATE, CURRENT_DATE FROM LOT WHERE LOT_ID_NUM = 234 AND (TO_DATE - FROM_DATE MONTH) > INTERVAL 3 MONTH DELETE FROM LOT WHERE LOT_ID_NUM = 234 AND (TO_DATE - FROM_DATE MONTH) > INTERVAL 3 MONTH 394 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN The current and sequenced deletions mention what happened in reality because they model changes. The nonsequenced statement concerns the specic representation (deleting particular records). Conversely, the associated SQL statements for the current and sequenced variants are much more complex than that for the nonsequenced delete for the same reason: the latter is expressed in terms of the representation. The following is a current update on a transaction-time table implemented as a backlog (compare with CF-9.6). All modications on backlogs are implemented as insertions, with the operation code indicating the type of modication. Code Fragment 11.42 Correct the backup identier for lot 433 to 37. -- transformed insertion INSERT INTO LOT_CONTAINS (FDYD_ID, LOT_ID_NUM, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, WHEN_CHANGED, OPERATION) SELECT FDYD_ID, LOT_ID, 37, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, CURRENT_DATE, I FROM LOT_CONTAINS AS L WHERE LOT_ID_NUM = 433 AND (OPERATION = I OR OPERATION = U) AND NOT EXISTS (SELECT * FROM LOT_CONTAINS AS L2 WHERE L.FDYD_ID = L2.FDYD_ID AND L.LOT_ID_NUM = L2.LOT_ID_NUM AND L.WHEN_CHANGED < L2.WHEN_CHANGED) -- transformed deletion INSERT INTO LOT_CONTAINS (FDYD_ID, LOT_ID_NUM, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, WHEN_CHANGED, OPERATION) SELECT FDYD_ID, LOT_ID, BKP_ID, A_NAME, DBF_NAME, DBF_UPDATE_RECNO, CURRENT_DATE, D FROM LOT_CONTAINS AS L WHERE LOT_ID_NUM = 433 AND BKP_ID <> 37 AND (OPERATION = I OR OPERATION = U) AND NOT EXISTS (SELECT * FROM LOT_CONTAINS AS L2 WHERE L.FDYD_ID = L2.FDYD_ID AND L.LOT_ID_NUM = L2.LOT_ID_NUM AND L.BKP_ID = L2.BKP_ID AND L.WHEN_CHANGED < L2.WHEN_CHANGED) We nish with a sequenced/current deletion on a bitemporal table (compare with CF-10.15). 11.7 Code Fragment 11.43 APPLICATION DEVELOPMENT 395 Lot 234 will be absent from the feed yard for the rst three weeks of October, when the steering will take place (applied on the bitemporal version of LOT). INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, DATE 1998-10-22, TO_DATE, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-01 AND TO_DATE > DATE 1998-10-22 AND STOP_DATE = DATE 9999-12-31 INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, FROM_DATE, DATE 1998-10-01, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-01 AND TO_DATE > DATE 1998-10-01 AND STOP_DATE = DATE 9999-12-31 UPDATE LOT SET STOP_DATE = CURRENT_TIMESTAMP WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-01 AND TO_DATE > DATE 1998-10-01 AND STOP_DATE = DATE 9999-12-31 INSERT INTO LOT SELECT FDYD_ID, LOT_ID_NUM, LOT_ID, GNDR_CODE, PROJ_CLOSEOUT, IN_WEIGHT, VALID, OWNER, COMMENT, DATE 1998-10-22, TO_DATE, CURRENT_TIMESTAMP, DATE 9999-12-31 FROM LOT WHERE LOT_ID_NUM = 234 AND FROM_DATE < DATE 1998-10-22 AND TO_DATE >= DATE 1998-10-22 AND STOP_DATE = DATE 9999-12-31 UPDATE LOT SET STOP_DATE = CURRENT_TIMESTAMP continued on page 396 396 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN continued from page 395 WHERE AND AND AND LOT_ID_NUM = 234 FROM_DATE < DATE 1998-10-22 TO_DATE >= DATE 1998-10-22 STOP_DATE = DATE 9999-12-31 UPDATE LOT SET STOP_DATE = CURRENT_TIMESTAMP WHERE LOT_ID_NUM = 234 AND FROM_DATE >= DATE 1998-10-01 AND TO_DATE <= DATE 1998-10-22 AND STOP_DATE = DATE 9999-12-31 11.8 IMPLEMENTATION CONSIDERATIONS The CD-ROM contains all the code fragments in this chapter in Oracle8 Server. As in previous chapters, assertions must be implemented as triggers. As an example, CF-11.17 can be implemented by the following Oracle8 Server trigger. Code Fragment 11.44 (LOT CONTAINS.FDYD ID, LOT CONTAINS.BKP ID) is a transactiontime current foreign key for BKP, in Oracle8. CREATE TRIGGER LOT CONTAINS Cur Ref Integrity BEFORE INSERT OR DELETE OR UPDATE ON LOT DECLARE valid INTEGER; BEGIN SELECT 1 INTO valid FROM DUAL WHERE NOT EXISTS ( SELECT * FROM LOT CONTAINS C -- C is the last relevant entry WHERE (C.OPERATION = I OR C.OPERATION = U) AND NOT EXISTS ( SELECT * FROM LOT CONTAINS C2 WHERE C2.FDYD ID = C.FDYD ID AND C2.LOT ID NUM = C.LOT ID NUM AND C2.WHEN CHANGED > C.WHEN CHANGED ) -- There is not a match for C in BKP 11.10 READINGS 397 AND NOT EXISTS ( SELECT * FROM BKP B WHERE B.FDYD ID = C.FDYD ID AND B.BKP ID = C.BKP ID -- B is the last relevant entry AND (B.OPERATION = I OR B.OPERATION = U) AND NOT EXISTS ( SELECT * FROM BKP B2 WHERE B2.FDYD ID = B.FDYD ID AND B2.BKP ID = B.BKP ID AND B2.WHEN CHANGED > B.WHEN CHANGED ) ) ); EXCEPTION WHEN NO DATA FOUND THEN RAISE APPLICATION ERROR( -20007, FDYD ID and BKP ID violate current/current foreign key ); END; 11.9 SUMMARY We followed a ve-step methodology in designing the feed yard application: (1) perform conceptual design ignoring time, yielding a conventional ER schema, (2) add temporal annotations in prose, (3) map the conventional ER schema into a logical SQL schema, (4) apply the temporal annotations, modifying the logical schema along the way, and (5) nish with physical design, including temporal partitioning. This approach moves consideration of temporal aspects from early in the design process to much, much later. The methology includes a systematic evaluation of the temporal aspects of each modeling construct, thereby breaking down the design task into answering (many) brief questions about individual constructs. Brad characterizes the process as “effecting Descartes's reductionism without losing sight of the whole.” More pragmatically, initially ignoring time results in less convoluted ER schemas, fewer errors introduced during logical design, and a deeper understanding of the application. 11.10 READINGS This case study was discussed in two articles in the August and September 1998 issues of Database: Programming and Design; the series has been collected in a tech- 398 CHAPTER ELEVEN : TEMPORAL DATABASE DESIGN nical report [88]. These articles focused on sequenced queries and on modications to the gender attribute. Heidi Gregersen and Christian S. Jensen have surveyed the many temporal entityrelationship models that have been proposed over the previous two decades [38]. Their model, the Time Extended EER Model (T IME ER [37]), is particularly elegant; I borrowed heavily from their characterization in my presentation in Section 11.2.2. T IME ER goes further, by proposing iconic indicators of the temporal aspects specied in this chapter in prose. Their approach to mapping TimeER schemas to the relational model [39] is the basis for the steps listed in Section 11.3. Christian S. Jensen and the author have written a comprehensive treatise on temporal logical design [55], as well as a more accessible example of these strategies [57], which informed the presentation of Section 11.3.2. The term lifespan was introduced by Manfred Klopprogge [62], time-invariant keys (TIKs) were rst mentioned by Shamkant Navathe and Ra Ahmed [74], and the concept of temporal specialization was advanced by Christian S. Jensen and the author [54]. David Landes discusses the alternative divisions puncta and ostenta [65]. He also summarizes the history of timing races in sports events, which slowly transitioned from quarter-seconds (1864) to fths, to tenths (the 1932 Olympics), to hundredths of a second (the Olympics in the 1970s). “There are few people outside the realm of organized religion who are as conservative as sports ofcials.” As an example, instruments capable of resolving hundredths of a second were introduced at the 1924 Paris Olympic games, yet handheld mechanical watches continued to pick the winner until the 1960 games. Handheld watches generally yielded faster races, as human judges had a tendency to jump the nish. Harrison's marine clocks (H-1 through H-5) provide the central thread of Dava Sobel's masterful account of the solving of what was considered the greatest scientic problem of the time [95]. This short (184-page) and diminutive (13 cm  20 cm) book, just slightly larger than H-4 itself, has just been reissued as a lavish coffeetable edition [96], with illustrations located and selected by William Andrewes, and has inspired a PBS science series, Lost at Sea: The Search for Longitude. CHAPTER 12 O V E R V I E W The case studies in this book have amply time, and transaction time. In this chapter we demonstrated that SQL-92 does not look fa- rephrase the applications of previous chapters vorably upon time-oriented applications. Even using these new constructs. That all can be the most simple tasks, such as specifying a pri- reimplemented in a single chapter is an indicamary key or joining two tables, become mired tion of the reduction in code length and comin complexity when time is introduced. Fortunately, the clouds part at the hori- plexity occasioned by these new constructs. Finally, we examine some public domain zon. A minor language extension proposed for and commercial tools that ease the transition SQL3 dramatically simplies coding such appli- until temporal support is directly incorporated cations by providing support for periods, valid into database systems. Language Directions T he case studies have shown that expressing integrity constraints, queries, and modications on time-varying data in SQL is challenging. We now look to the future, examining enhancements to SQL that bring temporal processing to the masses. With just a few additional concepts, SQL can as easily express temporal queries as it does now for nontemporal queries. 12.1 SQL-92 Many knotty problems arise when we have to contend with time-varying data in SQL-92.      Avoiding duplicates in a time-varying table requires an aggregate (CF-5.14) or a complex trigger (e.g., CF-5.26). A simple 3-line join when applied to time-varying tables explodes to a 29-line query consisting of four SELECT statements (CF-6.11) or a complex 23-line statement with four CASE expressions (CF-6.12). A 3-line UPDATE of a time-varying table translates into ve modication statements totaling 27 lines (CF-7.18). Maintaining a tracking log requires several triggers comprising some three dozen lines (CF-9.2). The same UPDATE of a bitemporal table translates into eight modication statements totaling 58 lines (CF-10.17)! In addition to being long, these statements are often highly convoluted, with multiple levels of correlated subqueries. Clearly something is amiss. 12.2 SQL-92 LIMITATIONS What is the source of this daunting complexity? While SQL-92 supports timevarying data through the DATE, TIME, and TIMESTAMP data types, the language 402 CHAPTER TWELVE : LANGUAGE DIRECTIONS Second By denition, there are exactly 24 sidereal hours in a sidereal day, 60 sidereal minutes in a sidereal hour, and 60 sidereal seconds in a sidereal minute. However, because the orbit and rotation of the earth vary slightly, the duration of a sidereal second is not constant. So instead, astronomers use an ephemeris second, which is a constant duration of time: 1/31,556,925.9747 of the period of the tropical year between the vernal equinoxes of 1899 and 1900. While this may seem an odd denition, the ephemeris second is actually the average value of a second calculated from astronomical observations over the 18th and 19th centuries. The advent of atomic clocks has provided another unit that is xed for all practical purposes. In October 1967, the atomic second was adopted as the fundamental unit of time (the SI second) by the international standards community, thereby shifting the basis of time from celestial to quantum mechanics. Specically, the second in the International System of Weights and Measures was dened to be 9,192,631,770 periods of the radiation emitted by the transition between two hyperne states of the cesium 133 atom in the ground state. On January 1, 1972, the atomic second became the practical unit of time. The UTC clock runs just a little fast with respect to mean solar time, gaining about a second a year. UTC is adjusted by applying leap seconds on January 1 or July 1 to keep UTC within 0.7 seconds of solar time. really has no notion of a time-varying table. SQL also has no concept of current or sequenced constraints, queries, modications, or views, nor of the critical distinction between valid time (modeling the behavior of the enterprise in reality) and transaction time (capturing the evolution of the stored data). In our terminology, all that SQL supports is nonsequenced operations, which we saw were often the least useful. 12.3 SQL3 All the time in the world Climbs the walls, swells the doors It goes ying out the window All the time in the world. . . These precious days we live through Thrown away like tissue I wish that I could give you all the time in the world —Beth Nielsen Chapman and Bill Lloyd, “All the Time in the World” At the heart of this book is the profound revelation that time is much more than just a column, and that SQL-92 is abysmally decient in the constructs it provides to express time-varying applications. Fortunately, there are now specic proposals 12.4 PERIODS 403 for temporal support in SQL3 that are being considered by the standards committees (see Section 12.16) and are being incorporated into products by vendors. This chapter will summarize these new SQL3 constructs and revisit the preceding case studies, showing how these constructs greatly simplify writing SQL for time-varying applications. In the following, when I mention an SQL3 construct, I am referring to the constructs introduced in proposals or already present in the draft SQL3. I should emphasize that these proposals are still under consideration for SQL3. The constructs may well change; indeed, SQL3 as a whole is still undergoing renement as it inches towards publication as an international standard. It is doubtful that SQL/Temporal will reach ISO standard status before the next millennium. That said, we examine these constructs as an indication of where things are going. Commercial implementations are already starting to appear; it is likely that one of the prevalent database systems will provide temporal support before such support is ofcially accepted as part of the SQL3 standard. We retain the chapter numbers of the case studies as section numbers in this chapter. As an example, the topic of Chapter 6, querying state tables (in SQL-92), parallels Section 6 of this chapter, on querying state tables in SQL3. That we can reimplement in SQL3 in a single chapter all four case studies, which took the bulk of this book to code in SQL-92, is itself testament to the purity and expressive power of the new constructs. 12.4 PERIODS SQL3 adds the PERIOD( ) constructor. An SQL data type constructor species a new type constructed out of a specied type. Examples are SQL sets, multisets (i.e., with duplicates), and lists (i.e., with ordering). In the case of the period type constructor, you can specify period data types of the SQL datetime data types as well as of exact numerics with a scale of 0 (i.e., integers). Hence, the following period data types are available. SQL3 has a period type constructor. Period types can be constructed from datetime and exact numeric element types.        PERIOD(DATE) PERIOD(TIME) and PERIOD(TIME WITH TIME ZONE) PERIOD(TIMESTAMP) and PERIOD(TIMESTAMP WITH TIME ZONE) PERIOD(INT) and PERIOD(INTEGER) PERIOD(SMALLINT) PERIOD(NUMERIC) PERIOD(DECIMAL) All but the rst allow a scale (number of fractional digits) to be specied, though for the last four types, this scale must be 0. 404 CHAPTER TWELVE : LANGUAGE DIRECTIONS 12.4.1 Period Literals Period literals are quite complex, for several reasons. First, all four variants of closed-closed, closed-open, open-closed, and open-open are supported. The closed variants use square brackets (`[' and `]'); the open variants, parentheses (`(' and `)'). Note, however, that this distinction concerns the period value that the literal denotes; it has nothing to do with the internal representation of a period, which is properly not specied in the standard. Second, the delimiters can each be a date value (denoting a date period literal), a time value (denoting a time period literal), or both (denoting a timestamp period literal). Third, only the ending delimiter can have an (optional) time zone; if present, it applies to both delimiters. Finally, the separator between the delimiting values can be either a minus sign, in which case there must be spaces around it, or a comma, in which case the surrounding spaces are optional. The following are all valid period literals and denote the same value, of type PERIOD(DATE). SQL3 period literals support all combinations of open and closed delimiting datetimes.      PERIOD PERIOD PERIOD PERIOD PERIOD [1997-01-01 - 1997-12-31] [1997-01-01 - 1998-01-01) (1996-12-31 - 1997-12-31] (1996-12-31 - 1998-01-01) [1997-01-01,1997-12-31] The following are also valid literals, of type PERIOD(TIMESTAMP WITH TIME ZONE). The time zone appears last in the literal.     12.4.2 PERIOD PERIOD PERIOD PERIOD [1997-01-01 [1997-01-01 (1996-12-31 (1996-12-31 00:00:00 00:00:00 23:59:59 23:59:59 - 1997-12-31 - 1998-01-01 - 1997-12-31 - 1998-01-01 23:59:59-07:00] 00:00:00-07:00) 23:59:59-07:00] 00:00:00-07:00) Predicates SQL3 denes several predicates on periods:     p OVERLAPS q (discussed for SQL-92 on page 35) is extended in SQL3 to allow either operand to be a period value, in addition to the datetime-datetime and datetime-interval pairs supported in SQL-92. p OVERLAPS q implements p overlaps q _ p overlaps 1 q _ p starts q _ p starts 1 q _ p nishes q _ p nishes 1 q _ p during q _ p during 1 q _ p equals q . p PRECEDES q implements before. p SUCCEEDS q implements before 1 . p MEETS q implements p meets q _ p meets 1 q. 12.4 PERIODS 405 The Hour Hand (First Major Advance) There have been three great transitions marking the increasing accuracy of clocks, enabled through technological advance. Interestingly, while some 2000 years separated the rst from the third transition, the latter came about just as this book was being written. The rst major advance was the addition of an  hour hand, or indicator, on a sundial when an accuracy of sufciently less than a day was possible. As we saw in the “Hours” sidebar in Chapter 2, the Chaldeans around 300 B . C . E . divided the day into 12 parts, based on the night being also divided into 12 parts, measuring these hours on a sundial. p CONTAINS q implements p during q ^ p 6= q. SQL3 raises an exception if the result of a period constructor is not a valid period. 12.4.3 Constructors SQL3 adds several datetime constructors:      BEGIN implements beginning . END implements ending . LAST implements last . PRIOR implements -1, when applied to a datetime. Hence, previous(p) can be expressed in SQL3 as PRIOR(BEGIN(p)). NEXT implements +1, when applied to a datetime. SQL3 adds one interval constructor, INTERVAL(p), which implements duration. An interval qualier can also be specied, as in INTERVAL(p DAY). SQL3 adds several period constructors:      PERIOD[a, b ) yields a period beginning at a and ending at b ; closed-closed, open- closed, and open-open variants are also included. p P UNION q implements `[' over periods; an exception is raised if NOT p OVERLAPS q. p P EXCEPT q implements ` ' over periods; an exception is raised if p CONTAINS q OR q CONTAINS p . p P INTERSECT q implements `\' over periods; an exception is raised if NOT p OVERLAPS q . CAST(p AS type) allows you to change the granularity of p . Table 12.1 summarizes how the period operations can be implemented in SQL/ Temporal. In the rst column, p and q denote period values, and i denotes an 406 CHAPTER TWELVE : LANGUAGE DIRECTIONS interval value. The OVERLAPS in the rst column, next-to-last line of the predicates is the SQL-92 OVERLAPS predicate. 12.5 DEFINING VALID-TIME STATE TABLES The University Information System consists of some 300 tables, 4 of which are listed below: EMPLOYEES(SSN, LAST NAME, FIRST NAME, ANNUAL SALARY) INCUMBENTS(SSN, PCN) POSITIONS(PCN, JOB TITLE CODE1) JOB TITLES(JOB TITLE CODE, JOB TITLE) These tables are snapshot tables, in that they capture the current state of the modeled reality. The EMPLOYEES table species each employee's current annual salary, the INCUMBENTS table identies the position code for each current employee, and the POSITIONS and JOB TITLES tables in concert provide the job title(s) for each position. SQL3 can express many useful queries on these tables. Code Fragment 12.1 What is Bob's position? SELECT JOB TITLE CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN SQL3 can also express integrity constraints on such tables. The following is an especially useful one. Code Fragment 12.2 (SSN, PCN) is a sequenced primary key for INCUMBENTS. ALTER TABLE INCUMBENTS ADD PRIMARY KEY (SSN, PCN) Valid-time support is specied in SQL3 with an ADD VALIDTIME clause. To indicate that the history of the time-changing reality is to be captured in the INCUMBENTS table, valid-time support is added to that table, associating with each row a period indicating when that row was valid in reality. SQL3 includes specic constructs to dene, query, and modify tables with valid-time support. 12.5 DEFINING VALID-TIME STATE TABLES Table 12.1 Period operations in SQL3. Period Operations Types: period Predicates: p equals q p before q p before 1 q p meets q p meets 1 q p overlaps q p overlaps 1 q p during q p during 1 q p starts q p starts 1 q 2 p nishes q p nishes 1 q p OVERLAPS q p IS NULL Datetime Constructors: beginning(p) previous(p) last (p) ending(p) Interval Constructors: duration(p) extract time zone(p) Period Constructors: p+i i+p p-i p extend q p q p-q p q p AT TIME ZONE i \ [ p AT LOCAL Other Operators: CAST(a AS PERIOD) CAST(p AS CHAR) SQL3 Equivalent PERIOD(datetime type) p =q p PRECEDES q p SUCCEEDS q END(p) = BEGIN(q) END(q) = BEGIN(p) BEGIN(p) < BEGIN(q) AND BEGIN(q) < END(p) BEGIN(q) < BEGIN(p) AND BEGIN(p) < END(q) BEGIN(q) < BEGIN(p) AND END(p) < END(q) BEGIN(p) < BEGIN(q) AND END(q) < END(p) BEGIN(p) = BEGIN(q) AND END(p) < END(q) BEGIN(p) = BEGIN(q) AND END(q) < END(p) BEGIN(q) < BEGIN(p) AND END(p) = END(q) BEGIN(p) < BEGIN(q) AND END(p) = END(q) p OVERLAPS q p IS NULL BEGIN(p) PRIOR(BEGIN(p)) LAST(p) END(p) INTERVAL(p), INTERVAL(p AS qual ) CAST(EXTRACT(TIMEZONE HOUR FROM BEGIN(p)) AS HOUR) + CAST(EXTRACT(TIMEZONE MINUTE FROM BEGIN(p)) AS MINUTE) PERIOD[BEGIN(p) + i, END(p) + i) PERIOD[BEGIN(p) + i, END(p) + i) PERIOD[BEGIN(p) - i, END(p) - i) not possible p P INTERSECT q p P EXCEPT q p P UNION q PERIOD[BEGIN(p) AT TIME ZONE i, END(p) AT TIME ZONE i) PERIOD[BEGIN(p) AT LOCAL, END(p) AT LOCAL) PERIOD[a, a] CAST(p AS CHAR) 407 408 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.3 Add valid-time support to INCUMBENTS. ALTER TABLE INCUMBENTS ADD VALIDTIME PERIOD(DATE) The period initially associated with each row has the indicated granularity, here, day, of “now” (that is, CURRENT DATE) to “forever” (that is, 9999-12-31). 12.5.1 Temporal Keys and Uniqueness The primary key was specied when INCUMBENTS was a snapshot table. An important property of SQL3 is that such integrity constraints continue to hold after valid-time support is added. This property is termed temporal upward compatibility, and requires that each integrity constraint on an associated snapshot database (e.g., the original INCUMBENTS table) be interpreted to hold on the current time-slice of the temporal counterpart of the database (the table with valid-time support). When INCUMBENTS did not have valid-time support, it modeled the current reality. As position assignments changed, the Constraints expressed on table was modied to reect the new situation. Integrity connontemporal tables are straints such as primary and foreign keys applied to the inforinterpreted in SQL3 as current mation currently in the table. constraints when valid-time When history is retained, by adding valid-time support to the support is added to the table. table, these integrity constraints still apply to the current information. Temporal upward compatibility thus implies that existing constraints on a nontemporal table become current constraints when valid-time support is added to the table. Compare the primary key constraint, CF-12.2 above, which still holds, with CF-5.12, which does the same thing in SQL-92, but requires nine lines in a CHECK constraint. This primary key constraint is perfectly ne if only current modications are made to the table. If sequenced or nonseAn SQL-92 statement can be quenced modications are possible, then we need to ensure that converted into a sequenced the primary key holds on all instants of time, even when the statement in SQL3 simply by information valid on a particular day may be changed by a later prepending VALIDTIME. modication. For that, we need a sequenced primary key constraint: “No employee can have the same position more than once simultaneously.” In SQL3, any statement can be rendered sequenced by prepending the reserved word VALIDTIME. Code Fragment 12.4 (SSN, PCN) is a sequenced primary key for INCUMBENTS. ALTER TABLE INCUMBENTS ADD VALIDTIME PRIMARY KEY (SSN, PCN) Compare this with CF-5.8, a 10-line CHECK constraint containing an aggregate and two levels of nested subqueries. 12.5 DEFINING VALID-TIME STATE TABLES The Minute Hand (Second Major Advance) After the hour hand was invented around 300 B . C . E ., the next transition had to await the passage of two millennia, to Huygens's pendulum clock in 1656 C . E . The dramatic vault in accuracy afforded by the pendulum enabled the addition of a minute hand. It is difcult to imagine now a society in which time was known only to roughly an hour. Code Fragment 12.5 409 As we've seen throughout this book, the sequenced variant is generally the one to use. It is for that reason that the SQL3 syntax is designed to succinctly indicate that a sequenced semantics is desired. As one further example, consider the uniqueness constraint: “No employee can have two identical positions.” On the original, nontemporal INCUMBENTS table, this is expressed as a uniqueness constraint. Prevent duplicates in INCUMBENTS. ALTER TABLE INCUMBENTS ADD UNIQUE (SSN, PCN) When valid-time support is added to the INCUMBENTS table, this constraint continues to be interpreted as current uniqueness. Expressing sequenced uniqueness, “At no time can an employee have two identical positions,” requires but a single additional reserved word. Code Fragment 12.6 Prevent sequenced duplicates in INCUMBENTS. ALTER TABLE INCUMBENTS ADD VALIDTIME UNIQUE (SSN, PCN) (Compare with CF-5.14.) 12.5.2 Referential Integrity We now revisit the various kinds of referential integrity (RI) and show how they may be expressed with the proposed constructs by examining the four cases from Section 5.6. Case 1 Neither table is temporal. Assume initially that neither the INCUMBENTS nor the POSITIONS table has temporal support. Referential integrity can then be expressed in SQL-92 as follows: Code Fragment 12.7 INCUMBENTS.PCN is a foreign key for POSITIONS.PCN (neither table is temporal). ALTER TABLE INCUMBENTS ADD FOREIGN KEY (PCN) REFERENCES POSITIONS 410 CHAPTER TWELVE : LANGUAGE DIRECTIONS Case 2 Only the referencing table is temporal. When valid-time support was added to the INCUMBENTS table, via ADD VALIDTIME PERIOD, the foreign key constraint still applies directly. It translates to a current constraint: “For each currently valid row of INCUMBENTS, the PCN is also in POSITIONS.” Temporal upward compatibility ensures that applications are not broken when temporal support is added to an underlying table. Case 3 Both tables are temporal. We now add temporal support to the referenced table, POSITIONS. Code Fragment 12.8 INCUMBENTS.PCN is a current foreign key for POSITIONS.PCN (both tables are temporal). ALTER TABLE POSITIONS ADD VALIDTIME PERIOD(DATE) The foreign key specied above (CF-12.7) when applied to referencing and referenced tables with valid-time support continues Unlike the complex statements to be interpreted as a current foreign key. (Compare with the required in SQL-92, the SQL-92 version, CF-5.20, at 12 lines.) sequenced variant in SQL3 is The sequenced RI constraint, “At each point in time, each inalmost identical to the cumbent's PCN is valid at that time,” is the most natural applicanontemporal analog. tion of the nontemporal RI constraint to time-varying information. This required a complex 32-line assertion (CF-5.21). Using the proposal constructs, only one additional keyword, VALIDTIME, is necessary to obtain a sequenced integrity constraint. Code Fragment 12.9 INCUMBENTS.PCN is a sequenced foreign key for POSITIONS.PCN (both tables are temporal). ALTER TABLE INCUMBENTS ADD VALIDTIME FOREIGN KEY (PCN) REFERENCES POSITIONS An SQL-92 statement can be converted into a nonsequenced statement in SQL3 simply by prepending NONSEQUENCED VALIDTIME. A nonsequenced RI constraint (“For each value of INCUMBENTS.PCN, there existed at some, possibly different, time that value in POSITIONS.PCN”) is equally simple to specify: we need only prepend the reserved word NONSEQUENCED. While nonsequenced constraints (and queries) are notoriously awkward to express in English, their translations to SQL-92 and SQL3 are almost identical, differing only in that single reserved word NONSEQUENCED. 12.6 Code Fragment 12.10 411 QUERYING STATE TABLES INCUMBENTS.PCN is a nonsequenced POSITIONS.PCN (both tables are temporal). foreign key for ALTER TABLE INCUMBENTS ADD NONSEQUENCED VALIDTIME FOREIGN KEY (PCN) REFERENCES POSITIONS Case 4 Only the referenced table is temporal. Here we drop the temporal support on the referencing table. Code Fragment 12.11 INCUMBENTS.PCN is a current foreign key for POSITIONS.PCN (only POSITIONS is temporal). ALTER TABLE INCUMBENTS DROP VALIDTIME The original RI constraint, CF-12.7, continues to apply and is equivalent to the 10line assertion in CF-5.24, in which every PCN value in INCUMBENTS must also occur in the current state of the POSITIONS table. In summary, temporal upward compatibility ensures that existing constraints, such as the referential integrity constraint of CF-12.7, are interpreted as current constraints when applied to tables with valid-time support. Sequenced constraints are specied by prepending VALIDTIME. 12.6 QUERYING STATE TABLES Although INCUMBENTS now has valid-time support, standard SQL queries still apply directly, retrieving (as before valid-time support was added) the current information. Code Fragment 12.12 What is Bob's position? SELECT JOB TITLE CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN This query is identical to CF-6.2 on the original INCUMBENTS table, without validtime support. This is another example of temporal upward compatibility (TUC). TUC in this context requires that each query will return the same result on an associated snapshot database (e.g., the original INCUMBENTS table) as on the temporal counterpart of the database (the table with valid-time support). TUC applies uniformly to all corners of the language. CF-6.3 requires 10 lines in SQL-92, but is shorter in SQL3 because the timestamp columns need not be mentioned. 412 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.13 What is Bob's current position and salary? SELECT JOB TITLE CODE1, AMOUNT FROM EMPLOYEES, INCUMBENTS, POSITIONS, SAL HISTORY WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND SAL HISTORY.SSN = EMPLOYEES.SSN Code Fragment 12.14 What employees currently have no position? SELECT FIRST NAME FROM EMPLOYEES WHERE NOT EXISTS ( SELECT * FROM INCUMBENTS WHERE EMPLOYEES.SSN = INCUMBENTS.SSN) (Compare with CF-6.4.) 12.6.1 Extracting States A valid time-slice query is nonsequenced. It is not a current query because it involves information in the past or future, and it is not a sequenced query because the result of the query has no timestamp. Nonsequenced queries are signaled by the NONSEQUENCED reserved word in SQL3. Additionally, the valid time-slice query needs to access the period timestamp to ensure information valid at the specied date is retrieved. To access the valid timestamp of a row, use the VALIDTIME( ) function, which evaluates to a period. A valid time-slice query is nonsequenced, with the associated timestamp period compared with the specied instant. Code Fragment 12.15 What was Bob's position at the beginning of 1997? NONSEQUENCED VALIDTIME SELECT JOB TITLE CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND VALIDTIME(INCUMBENTS) OVERLAPS DATE 1997-01-01 (Compare with CF-6.5.) 12.6.2 Sequenced Queries In all cases, a nontemporal query can be rendered sequenced by simply prepending VALIDTIME. 12.6 Code Fragment 12.16 QUERYING STATE TABLES 413 Who makes or has made more than $50,000 annually? VALIDTIME SELECT * FROM SAL HISTORY WHERE AMOUNT > 50000 Code Fragment 12.17 List the social security numbers of current and past employees. VALIDTIME SELECT SSN FROM SAL HISTORY In CF-6.7, we had to explicitly mention the timestamp columns. Here, SQL3 handles them automatically. Code Fragment 12.18 Sequenced sort INCUMBENTS on the position code (rst version). VALIDTIME SELECT * FROM INCUMBENTS ORDER BY PCN Here again, we needn't be concerned with where the timestamp columns should be placed in the ORDER BY clause (compare with CF-6.8). Code Fragment 12.19 Who makes or has made more than $50,000 annually or less than $10,000? VALIDTIME SELECT * FROM SAL HISTORY WHERE AMOUNT > 50000 UNION ALL SELECT * FROM SAL HISTORY WHERE AMOUNT < 10000 Here, the VALIDTIME applies to the entire query expression, which is SELECT . . . UNION ALL SELECT . . .. Sequenced joins are quite difcult in SQL-92, but only require adding one reserved word in SQL3. The sequenced variant in SQL3 of a nontemporal query retains the nontemporal query, adding only VALIDTIME. In SQL-92, converting to the sequenced analog requires completely rewriting the query. Code Fragment 12.20 Provide the salary and position history for all employees. VALIDTIME SELECT S.SSN, AMOUNT, PCN FROM SAL HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN In SQL-92, this query required some four UNIONs and 29 lines (CF-6.11), or four CASE expressions and 23 lines (CF-6.12), or two SQL/PSM FUNCTIONs (CF-6.14). 414 CHAPTER TWELVE : LANGUAGE DIRECTIONS The Second Hand (Not a Major Advance) While the minute hand was invented in 1656, after a period of two millennia, the second hand appeared astonishingly quickly, after but three decades, in 1690, for doctors' watches. The second hand was perfectly ne for determining a person's pulse rate, but was of little use in telling the time, for watches weren't, and generally still aren't, of sufcient accuracy to need a second hand: the second hand carries no information as to which instant it is. In 1776, an independent second train, an extraordinarily complex mechanical device, was invented to start and stop the second hand. That most modern watches do not have such a facility is more a testament to marketing (implying that the watch is accurate to the second) than to utility or performance. The second hand on the watch on your wrist is undoubtedly of the same use as on watches of 300 years ago: to provide a visual indication that your watch hadn't stopped. Nested queries are similarly converted into their sequenced analog. Code Fragment 12.21 List the employees who are or were department heads but were not also professors. VALIDTIME SELECT SSN FROM INCUMBENTS AS I1 WHERE PCN = 455332 AND NOT EXISTS (SELECT * FROM INCUMBENTS AS I2 WHERE I2.SSN = I1.SSN AND I2.PCN = 821197) The entire query, including the nested portion, is (conceptually) evaluated independently at each instant. This query requires four SELECTs UNIONed together, or 45 lines of SQL-92 (CF-6.18). This query can also be expressed via EXCEPT. Code Fragment 12.22 List the employees who are or were department heads but were not also professors (an equivalent version). VALIDTIME SELECT SSN FROM INCUMBENTS WHERE PCN = 455332 EXCEPT SELECT SSN FROM INCUMBENTS WHERE PCN = 821197 12.6 12.6.3 QUERYING STATE TABLES 415 Nonsequenced Queries Nonsequenced queries require (naturally) the NONSEQUENCED adverb in SQL3. As before, the timestamp is available via VALIDTIME( ). Code Fragment 12.23 List all the salaries, past and present, of employees who had been a hazardous waste specialist at some time. NONSEQUENCED VALIDTIME SELECT AMOUNT FROM INCUMBENTS, POSITIONS, SAL HISTORY WHERE INCUMBENTS.SSN = SAL HISTORY.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND JOB TITLE CODE1 = 20730 The phrases “past and present” and “at some time” indicate that the query is a nonsequenced one. This query in SQL3 is similar to the SQL-92 variant (CF-6.19); the only difference is the two added keywords. Code Fragment 12.24 When did employees receive raises? NONSEQUENCED VALIDTIME SELECT S2.SSN, BEGIN(VALIDTIME(S2)) AS RAISE DATE FROM SAL HISTORY AS S1, SAL HISTORY AS S2 WHERE S2.AMOUNT > S1.AMOUNT AND S1.SSN = S2.SSN AND VALIDTIME(S1) MEETS VALIDTIME(S2) Here, we access the timestamp in two places, in the SELECT clause, where we grab the beginning date of the timestamp (we could have just as easily used END(VALIDTIME(S1))), and in the WHERE clause. The MEETS predicate is quite useful in such situations. A nonsequenced query does not view the underlying table with valid-time support as a sequence of states; rather, it views the underlying table as one with an additional timestamp column (of type period) that can be accessed in the query via the function VALIDTIME( ). 12.6.4 Eliminating Duplicates Duplicate removal of any variant—current, sequenced, or nonsequenced—is specied in SQL3 using DISTINCT. You will notice an appealing consistency to the following three queries: Code Fragment 12.25 Remove current duplicates from INCUMBENTS. SELECT DISTINCT SSN, PCN FROM INCUMBENTS 416 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.26 Remove sequenced duplicates from INCUMBENTS. VALIDTIME SELECT DISTINCT SSN, PCN FROM INCUMBENTS Code Fragment 12.27 Remove nonsequenced duplicates from INCUMBENTS. NONSEQUENCED VALIDTIME SELECT DISTINCT * FROM INCUMBENTS The SQL-92 queries (CF-6.23, CF-6.24–6.26, and CF-6.21, respectively) vary dramatically, from 2 lines for nonsequenced to 19–30 lines for sequenced. 12.7 MODIFYING STATE TABLES SQL3's explicit support for current, sequenced, and nonsequenced statements applies equally to modication statements. 12.7.1 Current Modications Modications that don't involve the new reserved words when applied to tables with valid-time support are interpreted as current modications. Code Fragment 12.28 Bob joins as associate director of the Computer Center. INSERT INTO INCUMBENTS VALUES (111223333, 999071) Current modications in SQL3 are the same whether applied to nontemporal tables or to tables with valid-time support. Code Fragment 12.29 The default timestamp of PERIOD[CURRENT DATE, DATE 999912-31) is automatically provided when the underlying table has valid-time support. Current uniqueness, primary key, and referential integrity constraints are automatically maintained, so the gymnastics of CF-7.2–CF-7.5 is not necessary. Bob was just red as associate director of the Computer Center. DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 Compare with CF-7.7, in which a current deletion in the restricted case is implemented in SQL-92 as an UPDATE, or CF-7.8, in which a current deletion in the general case is implemented as an UPDATE and a DELETE statement. 12.7 Code Fragment 12.30 MODIFYING STATE TABLES 417 Today, Bob was promoted to director of the Computer Center. UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 Compare with CF-7.10 and CF-7.11. In particular, no complex case analysis is required. 12.7.2 Sequenced Modications The period of applicability of a sequenced modication is specied in SQL3 immediately after VALIDTIME. Code Fragment 12.31 A current modication applies from “now” to “forever.” A sequenced modication generalizes this to apply over a specied period of applicability, which could be in the past, in the future, or overlap “now.” In SQL3, the period of applicability is specied immediately after VALIDTIME. Bob was assigned the position of associate director of the Computer Center for 1997. VALIDTIME PERIOD [1997-01-01 - 1997-12-31] INSERT INTO INCUMBENTS VALUES (111223333, 999071) Of course, all (current and sequenced) primary key and referential integrity constraints continue to be checked. In SQL-92, these must be checked within the insertion (CF-7.13 and CF-7.14). Deletions also allow a period of applicability to be specied. Code Fragment 12.32 Bob was removed as associate director of the Computer Center for 1997. VALIDTIME PERIOD [1997-01-01 - 1997-12-31] DELETE FROM INCUMBENTS WHERE SSN=111223333 AND PCN = 999071 (Compare with CF-7.16.) Code Fragment 12.33 Bob was promoted to director of the Computer Center for 1997. VALIDTIME PERIOD [1997-01-01 - 1997-12-31] UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 Compare with CF-7.18, which consists of ve separate SQL-92 statements. No complex case analysis is required. 418 CHAPTER TWELVE : LANGUAGE DIRECTIONS A True Second Hand (Third Major Advance) The hour hand was invented around 300 B . C . E ., and the minute hand in 1656. A truly accurate second hand is just now becoming prevalent, in the form of radio watches that enclose Lilliputian radio receivers that tune into signals to synchronize with the standard atomic clocks. The most inexpensive of these watches retails for about $100 at the time 12.7.3 of this writing and will certainly fall dramatically in price as production and demand ramp up and as economies of scale come into play. You can marvel that one of the three most momentous transitions in horology over 2300 years occurred in your lifetime. Nonsequenced Modications As with constraints and queries, a nonsequenced modication treats the period timestamp (available via the VALIDTIME( ) function) identically to the other columns. Code Fragment 12.34 Delete Bob's records that include 1997 stating that he was associate director of the Computer Center. NONSEQUENCED VALIDTIME DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND VALIDTIME(INCUMBENTS) CONTAINS DATE 1997-12-31 The CONTAINS predicate is particularly useful here. Code Fragment 12.35 Extend Bob's position as associate director of the Computer Center for an additional year. NONSEQUENCED VALIDTIME UPDATE INCUMBENTS SET VALIDTIME = PERIOD(BEGIN(VALIDTIME(INCUMBENTS)), END(VALIDTIME(INCUMBENTS)) + INTERVAL 1 YEAR] WHERE SSN = 111223333 AND PCN = 999071 The SQL-92 and SQL3 versions of nonsequenced modications are quite similar. 12.7.4 In comparison with CF-7.20, this is one of the few situations in which the SQL3 version is longer (in this case, by one line) than the SQL-92 version. Except for details of syntax, though, the two versions are very similar. Modications That Mention Other Tables When one or more tables are rendered temporal, existing constraints, queries, and modications still apply over the period of applicability of “now” to “forever.” 12.7 Code Fragment 12.36 MODIFYING STATE TABLES 419 Bob is promoted to director of the Computer Center (current version). UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB TITLES WHERE POSITIONS.JOB TITLE CODE1 = JOB TITLE CODE AND JOB TITLE = DIRECTOR, COMPUTER CENTER) WHERE SSN = 111223333 Even complex sequenced modications over several tables can be easily expressed in SQL3 via the VALIDTIME construct. Code Fragment 12.37 It is perhaps no longer surprising that this requires some 30 lines of SQL-92 code (CF-7.22). You will also be able to easily express this update as a sequenced update, over a period of validity of the year 1997. Bob was promoted to director of the Computer Center for 1997 (sequenced version). VALIDTIME PERIOD [1997-01-01 - 1997-12-31] UPDATE INCUMBENTS SET PCN = (SELECT PCN FROM POSITIONS, JOB TITLES WHERE POSITIONS.JOB TITLE CODE1 = JOB TITLE CODE AND JOB TITLE = DIRECTOR, COMPUTER CENTER) WHERE SSN = 111223333 (Compare with CF-7.24, requiring eight SQL-92 statements and 77 lines.) 12.7.5 Temporal Partitioning* Temporal partitioning is effectively a physical design aspect, and as such should not impact the expression of queries or modicaTemporal partitioning is an tions on the partitioned table. Of course, as SQL-92 does not inaspect of physical design. clude the notion of tables with valid-time support, the partitioning must be implemented manually by the application programmer. As an analogy, if a DBMS didn't implement indexes, then they might be simulated by the application programmer via additional tables, which would dramatically complicate the SQL code. As SQL3 does support tables with valid-time support, it enables the underlying DBMS to include partitioning. A specic In SQL3, temporal partitioning syntax for specifying temporal partitioning is not included in has no impact on queries. SQL3 for the same reason that syntax to specify indexing is not included in SQL-92. In the following, we assume that temporal partitioning of the INCUMBENTS table has been specied in some DBMS-specic manner. 420 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.38 What is Bob's current position (partitioned)? SELECT JOB TITLE CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN This is similar to CF-7.25, with the exception that the original table, INCUMBENTS, is mentioned, rather than the current store, INCUMBENTS CURRENT. Code Fragment 12.39 Provide the salary and department history for all employees (partitioned). VALIDTIME SELECT S.SSN, AMOUNT, PCN FROM SAL HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN Incredibly, this requires 50 lines in SQL-92 (CF-7.26). Current modications work as before. Code Fragment 12.40 Bob was assigned the position of associate director of the Computer Center (partitioned). INSERT INTO INCUMBENTS VALUES (111223333, 6201945234) This is quite similar to the SQL-92 version (CF-7.27). The SQL3 version will also ensure that no current or sequenced integrity constraints are violated. Code Fragment 12.41 Bob was red as associate director of the Computer Center (partitioned). DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 SQL3 really shines in sequenced operations. Code Fragment 12.42 Bob was removed as associate director of the Computer Center for 1997 (partitioned). VALIDTIME PERIOD [1997-01-01 - 1997-12-31] DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 (Compare with the eight statements of CF-7.30.) Note that the core of the modication in SQL3 is unaffected by either the modication being sequenced or an underlying table being temporally partitioned. 12.8 Code Fragment 12.43 RETAINING A TRACKING LOG 421 Bob was promoted to director of the Computer Center for 1997 (partitioned). VALIDTIME PERIOD [1997-01-01 - 1997-12-31] UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 (Compare with CF-7.31 at 57 lines.) 12.8 RETAINING A TRACKING LOG The previous sections concerned tables with valid-Time support, capturing the history of the modeled reality. A tracking log is a quite different animal, as it captures the history of the table itself, allowing prior states to be retrieved. The states of the database at all previous points of time are retained, and modications are appendonly. Changes are not allowed on the past states, as that would prevent secure auditing. Instead, compensating transactions are used to correct errors. SQL3 supports transaction time in a fashion parallel to valid time, utilizing the TRANSACTIONTIME reserved word. 12.8.1 Dening Transaction-Time Tables The simplest way to implement a tracking log is to add transaction-time support to the monitored table. Transaction-time support may be specied in SQL3 with a simple ADD TRANSACTIONTIME. Code Fragment 12.44 Add transaction-time support to the PROJECTIONS table. ALTER TABLE PROJECTIONS ADD TRANSACTIONTIME Unlike valid-time support, the granularity is not specied, but instead is provided by the DBMS. Previously dened integrity constraints, such as PROJECTION ID being a primary key, are retained, interpreted as current constraints. Accomplishing this in SQL-92 required a set of triggers (CF-8.2). The DBMS is now responsible for maintaining transaction time for us. In particular, we don't have to worry about an application inadvertently corrupting past states (say, by incorrectly altering the timestamp The representation of a table with transaction-time support in columns), or a white-collar criminal intentionally “changing history” to cover up his tracks. The DBMS simply does not perSQL3 is specied with physical design statements supported by mit past states to be modied. The DBMS controls the representation of a table with the DBMS. transaction-time support. It might utilize a single instant timestamp, termed a tracking log on page 220, a pair of instants or 422 CHAPTER TWELVE : LANGUAGE DIRECTIONS a period as a timestamp, an instant timestamp coupled with an operation code, termed a backlog on page 233, or a backlog with after-images. The DBMS may provide syntax to choose among several representations; such physical design statements are not included in SQL3. 12.8.2 Queries A query on the current state of a table with transaction-time support is trivial: simply omit any mention of time. Code Fragment 12.45 List the information on projection 5. SELECT * FROM PROJECTIONS WHERE PROJECTION ID = 5 To reconstruct the table as of some point in the past, a transaction-time nonsequenced query is required. Code Fragment 12.46 Reconstruct the PROJECTIONS table as of April 1, 1996. NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE FROM PROJECTIONS AS P WHERE TRANSACTIONTIME(P) OVERLAPS DATE 1996-04-01 Here we use the TRANSACTIONTIME( ) function to access the transaction timestamp associated with each row. Compare with CF-8.3. This can also be dened as a view. Code Fragment 12.47 Reconstruct the PROJECTIONS table as of April 1, 1996, as a view. CREATE VIEW April PROJECTIONS ( PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE) AS (NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE FROM PROJECTIONS AS P WHERE TRANSACTIONTIME(P) OVERLAPS DATE 1996-04-01) CF-8.5 showed how to convert P Log to a transaction-time state table. Here, PROJECTIONS is already a state table. So perhaps an analogous operation would be to convert the PROJECTIONS table to one containing a When Changed column. 12.8 RETAINING A TRACKING LOG 423 More on the Second Hand Another way to have a watch accurate to a second is to frequently synchronize it with a known source of that accuracy. To do so, you can call by phone various national time services, such as the one in Boulder, Colorado. Often such services also broadcast the current time by radio, which can be listened to manually, or automatically, by the clock itself. Such radio-controlled clocks and watches became sufciently inexpensive for wide distribution only in 1998. I have such a clock in my bedroom. It cost $79 and is accurate to within a second, resynchronizing itself each night, by tuning into the appropriate frequency. With such a handy comparison, I nd Code Fragment 12.48 it easy to keep my watch to within a second or two of the correct time, and can thus condently provide a highly accurate answer to the question “What time is it?” With such an accurate chronometer, I have discovered that the Public Broadcasting Service starts its news service right on the half-hour, to the second, as does Headline News on the Cable News Network (CNN). However, the digital clock display in the lower right of the picture of CNN's Headline News is inexplicably off: tonight it is some 24 seconds behind, and I've seen it wrong by several minutes. Convert PROJECTIONS to an instant-stamped table. CREATE VIEW P Log (PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, When Changed) AS ( NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, END(TRANSACTIONTIME(PROJECTIONS)) ) FROM PROJECTIONS WHERE END(TRANSACTIONTIME(PROJECTIONS)) < CURRENT TIMESTAMP Transaction-time sequenced queries are signaled in SQL3 with the TRANSACTIONTIME prex. Code Fragment 12.49 Since all currently active rows have a transaction timestamp ending at “now,” we eliminate those in the WHERE clause, since they haven't been previously changed. Transaction-time sequenced queries (“when was it recorded”) are easy on tables with transaction-time support: just prepend TRANSACTIONTIME. When was it recorded that a projection had a type of 17? TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION TYPE FROM PROJECTIONS State WHERE PROJECTION TYPE = 17 424 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.50 List the projections recorded as having the same USGS zone code as the projection with ID 13447. TRANSACTIONTIME SELECT S1.PROJECTION NAME FROM PROJECTIONS state AS S1, PROJECTIONS state AS S2 WHERE S1.ZONE CODE = S1.ZONE CODE AND S2.PROJECTION ID = 13447 AND S1.PROJECTION ID <> 13447 (Compare with CF-8.18.) Another kind of nonsequenced query is the conversion to a tracking log (compare with CF-9.12–9.14), containing before-images, containing after-images, or as a backlog, respectively. Code Fragment 12.51 Extract before -images from a transaction-time state table. NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, END(TRANSACTIONTIME(PROJECTIONS)) AS When Changed FROM PROJECTIONS WHERE END(TRANSACTIONTIME(PROJECTIONS)) <> CURRENT TIMESTAMP Code Fragment 12.52 Extract after-images from a transaction-time state table. NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, BEGIN(TRANSACTIONTIME(PROJECTIONS)) AS When Changed FROM PROJECTIONS Code Fragment 12.53 Extract a backlog from a transaction-time state table. NONSEQUENCED TRANSACTIONTIME SELECT PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, BEGIN(TRANSACTIONTIME(P1)) AS When Changed, I AS Operation FROM PROJECTIONS AS P1 WHERE NOT EXISTS ( SELECT * FROM PROJECTIONS AS P2 WHERE P1.PROJECTION ID = P2.PROJECTION ID AND TRANSACTIONTIME(P2) MEETS TRANSACTIONTIME(P1)) UNION SELECT PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE, END(TRANSACTIONTIME(P1)) AS When Changed, D AS Operation 12.8 RETAINING A TRACKING LOG 425 FROM PROJECTIONS AS P1 WHERE END(TRANSACTIONTIME(P1)) <> CURRENT TIMESTAMP AND NOT EXISTS ( SELECT * FROM PROJECTIONS AS P2 WHERE P1.PROJECTION ID = P2.PROJECTION ID AND TRANSACTIONTIME(P1) MEETS TRANSACTIONTIME(P2)) UNION SELECT P1.PROJECTION ID, P1.PROJECTION NAME, P1.PROJECTION TYPE, P1.SPHEROID CODE, P1.PROJECTION UOM, P1.ZONE CODE, BEGIN(TRANSACTION(P2)) AS When Changed, U AS Operation FROM PROJECTIONS AS P1, PROJECTIONS AS P2 WHERE P1.PROJECTION ID = P2.PROJECTION ID AND TRANSACTIONTIME(P1) MEETS TRANSACTIONTIME(P2) Here again MEETS turns out to be quite useful. 12.8.3 Modications Sequenced and nonsequenced modications are not permitted on tables with transaction-time support, as such modications would violate the semantics of such tables. Instead, only current modications are allowed. Such modications in SQL3 are expressed on tables with transaction-time support without mention of time. Code Fragment 12.54 Insert a projection with an ID of 6. INSERT INTO PROJECTIONS (PROJECTION ID, PROJECTION NAME, PROJECTION TYPE, SPHEROID CODE, PROJECTION UOM, ZONE CODE) VALUES (6, New Projection, 22, 14, 93, 4) (Compare with CF-9.4.) Code Fragment 12.55 Delete projection 2. DELETE FROM PROJECTIONS WHERE PROJECTION ID = 2 Code Fragment 12.56 Change the type of projection 1 to 43. UPDATE PROJECTIONS SET PROJECTION TYPE = 43 WHERE PROJECTION ID = 1 Temporal upward compatibility ensures that such modications, which don't mention time, maintain the prior states. 426 12.9 CHAPTER TWELVE : LANGUAGE DIRECTIONS TRANSACTION-TIME STATE TABLES As mentioned previously, the representation of a table with temporal support is a physical design concern. The DBMS may provide syntax to choose among several representations; such physical design statements are not included in SQL3. Hence, the queries and modications presented above are still appropriate for a periodstamped representation. Here, we present the remaining queries. 12.9.1 Queries As with valid time, a sequenced transaction-time prex applies to the entire query, in the following case, to the UNION. Code Fragment 12.57 Give the change history for projections having a type of 12 or 18. TRANSACTIONTIME SELECT PROJECTION ID FROM P TT WHERE PROJECTION TYPE = 12 UNION SELECT PROJECTION ID FROM P TT WHERE PROJECTION TYPE = 18 (Compare with CF-9.9.) Code Fragment 12.58 When was it recorded that two projections had the same type? TRANSACTIONTIME SELECT P1.PROJECTION ID, P2.PROJECTION ID, P1.PROJECTION TYPE FROM PROJECTIONS AS P1, PROJECTIONS AS P2 WHERE P1.PROJECTION ID <> P2.PROJECTION ID AND P1.PROJECTION TYPE = P2.PROJECTION TYPE Auditing queries are often transaction-time nonsequenced queries. Code Fragment 12.59 When was the type of a projection erroneously changed to be identical to that of an existing projection? NONSEQUENCED TRANSACTIONTIME SELECT P1.PROJECTION ID, P1.PROJECTION TYPE AS Identical TYPE, P3.PROJECTION TYPE AS Prior TYPE, BEGIN(TRANSACTIONTIME(P2)) AS When Changed FROM P TT AS P1, P TT AS P2, P TT AS P3 WHERE P1.PROJECTION ID <> P2.PROJECTION ID AND P2.PROJECTION ID = P3.PROJECTION ID AND P1.PROJECTION TYPE = P2.PROJECTION TYPE AND P2.PROJECTION TYPE <> P3.PROJECTION TYPE AND TRANSACTIONTIME(P3) MEETS TRANSACTIONTIME(P2) 12.10 BITEMPORAL TABLES 427 The MEETS predicate is quite handy for “change” queries. Compare with CF-9.11. 12.9.2 Temporal Partitioning and Vacuuming Temporal partitioning is representational, and thus in the domain of physical design. You could envision the DBMS providing an ADD PARTITIONING clause to the ALTER TABLE statement. As with all physical design decisions, such a statement would not impact the specication of queries or modications. Hence, the code fragments given above work perfectly ne with a temporally partitioned representation. Vacuuming is not yet supported in SQL3. 12.10 BITEMPORAL TABLES Valid-time support and transaction-time support in concert result in a bitemporal table. Code Fragment 12.60 Valid-time support and transaction-time support are orthogonal in SQL3. They can be used separately, as above, or together, resulting in a table with both kinds of support, termed a bitemporal table. Create the Prop Owner table. CREATE TABLE Prop Owner ( customer number INT, property number INT) AS VALIDTIME PERIOD(DATE) AND TRANSACTIONTIME While the granularity of the valid timestamp is specied by the user (here, to a granularity of day), the granularity of the transaction timestamp is supplied by the DBMS. As before, nontemporal queries, views, constraints, assertions, and modications are interpreted as current (in both valid time and transaction time) when applied to a bitemporal table. The concepts of temporal upward compatibility, sequenced semantics, and nonsequenced semantics apply orthogonally to valid time and transaction time. The semantics is dictated by three simple rules:   The absence of VALIDTIME (respectively, TRANSACTIONTIME) indicates validtime (transaction-time) upward compatibility. The result of such a query does not include valid-time (transaction-time) support. VALIDTIME (respectively, TRANSACTIONTIME) indicates sequenced valid (transaction) semantics. An optional period expression temporally scopes the result. The result of such a query includes valid-time (transaction-time) support. 428 CHAPTER TWELVE : LANGUAGE DIRECTIONS  NONSEQUENCED denotes nonsequenced valid (respectively transaction) semantics. An optional period expression after NONSEQUENCED VALIDTIME (TRANSACTIONTIME) provides a valid-time (transaction-time) timestamp, yielding valid-time (transaction-time) support in the result. The valid-time and transaction-time clauses can be used together in assertions and constraints. Code Fragment 12.61 property number is a (valid-time sequenced, transaction-time sequenced) primary key for Prop Owner. CREATE ASSERTION P O seq primary key VALIDTIME AND TRANSACTIONTIME PRIMARY KEY (property number) (Compare with CF-10.2.) Code Fragment 12.62 The customer number in Prop Owner is a foreign key referencing the Customer table (valid-time sequenced/transaction-time current version). ALTER TABLE Prop Owner ADD VALIDTIME FOREIGN KEY (customer number) REFERENCES Customer (Compare with CF-10.49, at 48 lines, and CF-10.50, 18 lines.) 12.10.1 Queries We start with time-slice queries, which are generally nonsequenced in one dimension. The rst is a transaction time-slice query, resulting in a table with valid-time support (as such, it is sequenced in valid time). Code Fragment 12.63 Give the history of owners of the at at Skovvej 30 in Aalborg as of January 1, 1998. VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT customer number FROM Prop Owner WHERE property number = 7797 AND TRANSACTIONTIME(Prop Owner) OVERLAPS DATE 1998-01-01 The result is a table with one column, customer number, and one (valid) period timestamp. Here we again use the TRANSACTIONTIME function to extract the transaction timestamp. Compare with CF-10.19. The OVERLAPS predicate is not required for a current transaction time-slice. Code Fragment 12.64 Give the history of owners of the at at Skovvej 30 in Aalborg as best known. VALIDTIME SELECT customer number FROM Prop Owner WHERE property number = 7797 12.10 BITEMPORAL TABLES 429 The valid time-slice results in a transaction-time state table; it is nonsequenced in valid time but sequenced in transaction time. Code Fragment 12.65 When was the information about the owners of the at at Skovvej 30 in Aalborg on January 4, 1998, recorded in the Prop Owner table? NONSEQUENCED VALIDTIME AND TRANSACTIONTIME SELECT customer number FROM Prop Owner WHERE property number = 7797 AND VALIDTIME(Prop Owner) OVERLAPS DATE 1998-01-04 Here, the result has a transaction timestamp. A bitemporal time-slice takes as input two instants, a valid-time and a transaction-time instant, and results in a snapshot state of the information regarding the enterprise at that valid time, as recorded in the database at that transaction time. It is nonsequenced in both valid and transaction time. Code Fragment 12.66 Give the owner of the at at Skovvej 30 in Aalborg on January 13 as stored in the Prop Owner table on January 18. NONSEQUENCED VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT customer number FROM Prop Owner WHERE property number = 7797 AND VALIDTIME(Prop Owner) OVERLAPS DATE 1998-01-13 AND TRANSACTIONTIME(Prop Owner) OVERLAPS DATE 1998-01-18 The result includes no implicit timestamps. The current bitemporal time-slice is particularly easy to write in SQL3. Code Fragment 12.67 Give the owner of the at at Skovvej 30 in Aalborg today as best known. SELECT customer number FROM Prop Owner WHERE property number = 7797 Again, the result has but one column, and no implicit timestamps. The orthogonality of valid-time and transaction-time support enables us to combine in arbitrary ways current, sequenced, and nonsequenced semantics for both kinds of time, resulting in nine temporal variants of every nontemporal query. Current in valid time translates in English to “at now”; sequenced translates to “at the same time”; and nonsequenced translates to “at any time.” Current in transaction time translates to “as best known”; sequenced All combinations of current, sequenced, and nonsequenced queries over valid time and transaction time are easily expressed in SQL3. 430 CHAPTER TWELVE : LANGUAGE DIRECTIONS translates to “when did we think”; and nonsequenced translates to “when was it recorded” or “when was it corrected.” We illustrate this by providing all variants of the query “What properties are owned by the customer who owns property 7797?”, repeating the nine cases from Section 10.3.2. Unlike SQL-92, in which the variants can differ, sometimes dramatically, in SQL3 all the variants are identical, save their prexes. Case 1 Valid-time current and transaction-time current Code Fragment 12.68 What properties are owned by the customer who owns property 7797, as best known? SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner (Compare with CF-10.26.) Case 2 Valid-time sequenced and transaction-time current Code Fragment 12.69 What properties are or were owned by the customer who owned at the same time property 7797, as best known? VALIDTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner Case 3 Valid-time nonsequenced and transaction-time current Code Fragment 12.70 What properties were owned by the customer who owned at any time property 7797, as best known? NONSEQUENCED VALIDTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner 12.10 Case 4 BITEMPORAL TABLES 431 Valid-time current and transaction-time sequenced Code Fragment 12.71 What properties did we think are owned by the customer who owns property 7797? TRANSACTIONTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner Case 5 Valid-time sequenced and transaction-time sequenced Code Fragment 12.72 When did we think that some property, at some time, was owned by the customer who owned at the same time property 7797? VALIDTIME AND TRANSACTIONTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner Case 6 Valid-time nonsequenced and transaction-time sequenced Code Fragment 12.73 When did we think that some property, at some time, was owned by the customer who owned at any time property 7797? NONSEQUENCED VALIDTIME AND TRANSACTIONTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner Case 7 Valid-time current and transaction-time nonsequenced Code Fragment 12.74 When was it recorded that a property is owned by the customer who owns property 7797, as best known? NONSEQUENCED TRANSACTIONTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner 432 CHAPTER TWELVE : LANGUAGE DIRECTIONS Case 8 Valid-time sequenced and transaction-time nonsequenced Code Fragment 12.75 When was it recorded that a property is or was owned by the customer who owned at the same time property 7797? VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner Case 9 Valid-time nonsequenced and transaction-time nonsequenced Code Fragment 12.76 When was it recorded that a property was owned by the customer who owned at some time property 7797? NONSEQUENCED VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT P2.property number, BEGIN(TRANSACTIONTIME(P2)) AS Recorded Start FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner We end with the remaining bitemporal queries presented in the Nykredit chapter, providing additional examples of combinations of valid and transaction time with current, sequenced, and nonsequenced queries. Code Fragment 12.77 What is the estimated value of the property at Bygaden 4 (current/current)? SELECT estimated value FROM Property AS P WHERE P.address = Bygaden 4 Code Fragment 12.78 Who owns the property at Bygaden 4 (current/current)? SELECT name FROM Prop Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property number = PO.property number AND C.customer number = PO.customer number (Compare with CF-10.36, at 14 lines.) 12.10 Code Fragment 12.79 BITEMPORAL TABLES 433 How has the estimated value of the property at Bygaden 4 varied over time (sequenced/current)? VALIDTIME SELECT estimated value FROM Property AS P WHERE P.address = Bygaden 4 Code Fragment 12.80 Who has owned the property at Bygaden 4 (sequenced/current)? VALIDTIME SELECT name FROM Prop Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property number = PO.property number AND C.customer number = PO.customer number Code Fragment 12.81 When was the estimated value for the property at Bygaden 4 stored (current/nonsequenced)? NONSEQUENCED TRANSACTIONTIME SELECT estimated value, BEGIN(TRANSACTIONTIME(Property)) AS Recorded Start FROM Property WHERE address = Bygaden 4 Code Fragment 12.82 Who has owned the property at Bygaden 4, and when was this information recorded (sequenced/nonsequenced)? VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT name, BEGIN(TRANSACTIONTIME(PO)) AS PO Recorded, BEGIN(TRANSACTIONTIME(C)) AS C Recorded, BEGIN(TRANSACTIONTIME(P)) AS P Recorded Start FROM Prop Owner AS PO, Customer AS C, Property AS P WHERE P.address = Bygaden 4 AND P.property number = PO.property number AND C.customer number = PO.customer number Code Fragment 12.83 List all retroactive changes made to the Prop Owner table (nonsequenced/nonsequenced). NONSEQUENCED VALIDTIME VALIDTIME(Prop Owner) AND NONSEQUENCED TRANSACTIONTIME SELECT customer number, property number, BEGIN(TRANSACTIONTIME(Prop Owner)) AS Recorded Start FROM Prop Owner WHERE BEGIN(VALIDTIME(Prop Owner)) < BEGIN(TRANSACTIONTIME(Prop Owner)) 434 CHAPTER TWELVE : LANGUAGE DIRECTIONS Here we see an expression appearing after NONSEQUENCED VALIDTIME. This renders the result a table with valid-time support, with the specied period forming the period of validity of the row. The resulting table will have three columns, customer number, property number, and Recorded Start; each row will also be associated with a valid timestamp. Following NONSEQUENCED VALIDTIME with a period expression in SQL3 renders the result a table with valid-time support. 12.10.2 Integrity Constraints The following assertion is nonsequenced in valid time and current in transaction time: Code Fragment 12.84 Prop Owner.property number denes a contiguous valid-time history. CREATE ASSERTION P O Contiguous History NONSEQUENCED VALIDTIME CHECK (NOT EXISTS (SELECT * FROM Prop Owner AS P, Prop Owner AS P2 WHERE END(VALIDTIME(P)) < BEGIN(VALIDTIME(P2) AND P.property number = P2.property number AND NOT EXISTS ( SELECT * FROM Prop Owner AS P3 WHERE P3.property number = P.property number AND ((BEGIN(VALIDTIME(P3)) <= END(VALIDTIME(P))) AND (END(VALIDTIME(P) < END(VALIDTIME(P3)))) OR ((BEGIN(VALIDTIME(P3)) < BEGIN(VALIDTIME(P2))) AND (BEGIN(VALIDTIME(P2)) <= END(VALIDTIME(P3)))))) ) )) SQL3 integrity constraints on bitemporal tables can be any combination of current, sequenced, and nonsequenced. Code Fragment 12.85 (Compare with CF-10.3.) As with queries, assertions (and constraints and views) can also include with combinations of valid-time and transactiontime sequenced and nonsequenced prexes. Compare with CF-10.44–10.46. A customer who owns property 7797 shall own no other property (current/current). CREATE ASSERTION CHECK ( NOT EXISTS ( SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner)) 12.10 Code Fragment 12.86 BITEMPORAL TABLES 435 A customer who owned property 7797 shall concurrently own no other property (sequenced/current). CREATE ASSERTION VALIDTIME CHECK ( NOT EXISTS ( SELECT * FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner)) Code Fragment 12.87 A customer who owned property 7797 shall own no other property, even at a different time (nonsequenced/current). CREATE ASSERTION NONSEQUENCED VALIDTIME CHECK ( NOT EXISTS ( SELECT P2.property number FROM Prop Owner AS P1, Prop Owner AS P2 WHERE P1.property number = 7797 AND P2.property number <> P1.property number AND P1.property owner = P2.property owner)) 12.10.3 Modications During modications the DBMS provides the transaction time Current modications in SQL3 on of facts, in contrast with the valid time, which is provided by the user. This derives from the different semantics of transbitemporal tables are identical action time and valid time. Specically, when a fact is (logito their nontemporal cally) deleted from a table with transaction-time support, its counterparts. transaction-stop time is set automatically by the DBMS to the current time, “now.” When a fact is inserted into the table, its transaction-start time is set by the DBMS, again to the current time. An update is treated, concerning the transaction timestamps, as a deletion followed by an insertion. The transaction times that a set of modication transactions give to the modied rows must be consistent with the serialization order of those transactions. Most importantly, though, the semantics of transaction time across modication statements is maintained automatically by the DBMS. No user intervention is required, and no mention of transaction time is indicated, or is even possible, in modications of tables with transaction-time support, including bitemporal tables. Current valid-time modications are identical to their nontemporal versions. Code Fragment 12.88 Eva Nielsen buys the at at Skovvej 30 in Aalborg on January 10, 1998. INSERT INTO Prop Owner (customer number, property number) VALUES (145, 7797) (Compare with CF-10.4.) 436 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.89 Peter Olsen sells the at on January 20, 1998. DELETE FROM Prop Owner WHERE property number = 7797 Code Fragment 12.90 Peter Olsen buys the at on January 15, 1998, a current update. UPDATE Prop Owner SET customer number = 827 WHERE property number = 7797 The period of applicability for valid-time sequenced modications in SQL3 is specied immediately following the VALIDTIME prex. Code Fragment 12.91 A current modication carries with it an implied period of applicability of “now” to “forever.” Sequenced modications have an implied period of applicability of all of time: “beginning” to “forever.” In the latter, though, the user can specify a different period of applicability, right after the VALIDTIME reserved word. Eva actually purchased the at on January 3, performed on January 23. VALIDTIME PERIOD [1998-01-03 - 1998-01-10) INSERT INTO Prop Owner (customer number, property number) VALUES (145, 7797) Code Fragment 12.92 Eva actually purchased the at on January 5. VALIDTIME PERIOD [1998-01-02 - 1998-01-5) DELETE FROM Prop Owner WHERE property number = 7977 Code Fragment 12.93 Peter actually purchased the at on January 12. VALIDTIME PERIOD [1998-01-12 - 1998-01-15) UPDATE Prop Owner SET customer number = 145 WHERE property number = 7797 AND customer number <> 145 Code Fragment 12.94 Delete all records with a valid-time duration of exactly one week. NONSEQUENCED VALIDTIME DELETE Prop Owner WHERE INTERVAL(PERIOD(Prop Owner)) = INTERVAL 7 DAY 12.10.4 Temporal Partitioning and Vacuuming As has been emphasized before, temporal partitioning is a physical design decision, and as such has no impact on the expression of SQL3 queries, modications, integrity constraints, and so on. Vacuuming hasn't yet been specied for SQL3. 12.11 CAPSTONE CASE 437 Internet Time New requirements inspire new clocks. Consider the netizen, trying deep into the night to connect via a chatroom with a correspondent halfway across the world. Via email, he had suggested a rendezvous time, expressed in her local time, but he was off by an hour, and they miss their opportunity. Swatch, the Swiss watch company, responded with the Webmaster, a watch (retailing at 100. SFr) that displays both the local time and Internet Time, based on Biel Mean Time (BMT). Internet Time is the same time the world over, so no conversions are necessary. He tells his cyber partner to check in 12.11 at 750 BMT, or more colloquially, at 750 Swatch Beats, which corresponds, on this crisp winter day, to 6 P. M . in Biel, Switzerland (Central European Wintertime), 10 A . M . in Tucson, Arizona (Mountain Standard Time), and 4 A . M . (Eastern Summer Time) in Sydney, Australia. Each day contains 1000 Swatch Beats, each 1 minute and 26.4 seconds long. The BMT meridian may be seen on the façade of the Swatch International Headquarters on Jakob-Staempi Street in Biel. CAPSTONE CASE In this last case, Brad's feed yard application, everything comes together. This is actually the third time we're attacking this application. The rst time was in Chapter 2, where we surveyed the major concepts and expressed queries and modications in prose. In Chapter 11 we showed how to design temporal applications, using this case. Here, we reexpress the schema, queries, and modications in SQL3, as yet another example of how these constructs simplify development of temporal applications. 12.11.1 Temporal Relational Schema Section 11.1 emphasized a ve-step methodology for database design: (1) perform conceptual design ignoring time, yielding a conventional ER schema, (2) add temporal annotations in prose, (3) map the conventional ER schema into a logical SQL schema, (4) apply the temporal annotations, modifying the logical schema along the way, and (5) nish with physical design, including temporal partitioning. When using SQL3, we retain the rst three steps and greatly simplify the fourth step. The fth step is DBMS-dependent, as the SQL3 standard does not include constructs for physical schema specication. We start with the output from the third step: the initial nontemporal logical schema shown in Figure 11.2. We then apply the temporal annotations, paralleling the material in Section 11.3.2. 438 CHAPTER TWELVE : LANGUAGE DIRECTIONS User-Dened Time Attributes Attributes whose type is period can use the SQL3 PERIOD type directly, rather than simulating these with two instant columns. Entity Lifespans To each table corresponding to an entity type for which the lifespan or valid time of an associated attribute is captured, we add an AS VALIDTIME clause. One entity type has a recorded lifespan: LOT. Code Fragment 12.95 LOT is a valid-time state table. ALTER TABLE LOT ADD VALIDTIME PERIOD(DATE) Relationship Valid Time To each table corresponding to a relationship type with a recorded valid-time extent, or having attribute(s) whose valid time is recorded, we add an AS VALIDTIME clause. As indicated in Table 11.1, the valid time of three relationship types, LOCATION, MOVE, and MASS TRTMNT, is recorded. The For tables corresponding to entity and relationship types for LOCATION relationship type has a temporal extent; the other two are instantaneous relationship types. All three must use a which valid time is to be period timestamp because SQL3 does not (yet) support event tarecorded, use an AS VALIDTIME bles, that is, tables with an instant timestamp. Instead, a period clause in SQL3. of a single granule will be used. For LOCATION and MOVE, the granularity is denoted as “Sub-DAY” in Table 11.1. The MOVE ORDER column was used to differentiate multiple moves on a single day. As this is not possible in SQL3, we specify a granularity of MINUTE for the associated tables. Code Fragment 12.96 LOT LOC, LOT MOVE, and MASS TRTMNT have valid-time support. ALTER TABLE LOT LOC ADD VALIDTIME PERIOD(TIMESTAMP MINUTE) ALTER TABLE LOT MOVE ADD VALIDTIME PERIOD(TIMESTAMP MINUTE) ALTER TABLE MASS TRTMNT ADD VALIDTIME PERIOD(DATE) Valid Time of Attributes Tables should be decomposed so that all attributes in a table have identical temporal support. No temporal decomposition is indicated here. 12.11 CAPSTONE CASE 439 Transaction Time For each table associated with an entity or relationship type for whose transaction-time periods are recorded, or that are associated with attribute(s) whose transaction-time periods are recorded, the AS TRANSACTIONTIME clause should be used. SQL3 provides the granularity for transaction time; it may not be specied by the user. TRANSACTIONTIME without a stated granularity may be used in SQL3. Code Fragment 12.97 LOT, LOT MOVE, LOT LOC, and BKP are transaction-time tables. ALTER TABLE LOT ADD TRANSACTIONTIME ALTER TABLE LOT MOVE ADD TRANSACTIONTIME ALTER TABLE LOT LOC ADD TRANSACTIONTIME ALTER TABLE BKP ADD TRANSACTIONTIME As the LOT, LOT MOVE, and LOT LOC tables already had valid timestamps, adding transaction-time support renders them bitemporal. As with valid time, we must also consider temporal support decomposition. Most of the attributes in LOT are bitemporal, but Transaction-time support may BKP ID, A NAME, DBF NAME, and DBF UPDATE RECNO, because they induce additional temporal were inherited from the CONTAINS relationship type, which support decomposition. records only transaction time, do not vary in valid time, and thus differ from the other attributes in that table in their temporal support. We move those attributes to a separate transaction-time table, LOT CONTAINS, and include the primary key of LOT. Code Fragment 12.98 ALTER ALTER ALTER ALTER TABLE TABLE TABLE TABLE Move the BKP ID, A NAME, DBF NAME, and DBF UPDATE RECNO columns into a separate transaction-time table. LOT LOT LOT LOT DROP DROP DROP DROP COLUMN COLUMN COLUMN COLUMN BKP ID A NAME DBF NAME DBF UPDATE RECNO CREATE TABLE LOT CONTAINS (FDYD ID, LOT ID NUM, BKP ID, A NAME, DBF NAME, DBF UPDATE RECNO, PRIMARY KEY (FDYD ID, LOT ID NUM), FOREIGN KEY (FDYD ID, LOT ID NUM) REFERENCES LOT ) AS TRANSACTIONTIME 440 CHAPTER TWELVE : LANGUAGE DIRECTIONS Primary Keys For tables with valid-time support, the primary key should be valid-time sequenced; for tables with transaction-time support, the primary key should be transaction-time sequenced. In SQL3, the primary key should The original primary key for these tables, which is interpreted reect the temporal support as current/current, can be dropped if the table has some kind of accorded the table. temporal support. The collected result of these changes is shown in Figure 12.1. Time-invariant primary keys are The primary key for the BACKUP entity type is transactiontime invariant, which is translated into a NONSEQUENCED inherently nonsequenced. TRANSACTIONTIME PRIMARY KEY. Referential Integrity Referential integrity constraints are inherently sequenced. The prex for FOREIGN KEY depends on the temporal support of both participating tables:    Both tables have valid-time support. The prex should be VALIDTIME, indicating a valid-time sequenced foreign key. Only the referencing table has valid-time support. The prex should be NONSEQUENCED VALIDTIME, indicating a valid-time nonsequenced foreign key, ignoring the timestamp of the referencing table. The referencing table does not have valid-time support. No prex should be used, indicating a valid-time current foreign key, which applies to the current state of the referenced table, should it have valid-time support, and to the table as it is, should it not have valid-time support. The same rules hold for transaction-time support. Generally, in SQL3, if both the referencing table and the referenced table have valid-time support, then VALIDTIME is indicated; if only the referencing table has valid-time support, then NONSEQUENCED VALIDTIME is indicated. Transaction-time support is analogously handled. Uniqueness Constraints As with all integrity constraints, the presence of temporal support implies a sequenced constraint. The one exception is time-invariant integrity constraints, which are inherently nonsequenced. This may be seen in the uniqueness clause of the LOT table. In SQL3, integrity constraints should reect the temporal support accorded the table and be interpreted as sequenced. Time-invariant integrity constraints, which hold over all time, correspond to nonsequenced integrity constraints. 12.11 CAPSTONE CASE FDYD (FDYD ID, NAME, FDYD SHORT NAME, FDYD MNGR LNAME, . . ., PRIMARY KEY (FDYD ID), UNIQUE (FDYD SHORT NAME) ) CREATE TABLE PEN (FDYD ID, PEN ID, PEN TYPE CODE, BUNK LENGTH, APRON WIDTH, PEN AREA, WATER SPACE, BKP ID, PRIMARY KEY (FDYD ID, PEN ID), FOREIGN KEY (FDYD ID) REFERENCES FDYD, FOREIGN KEY (FDYD ID, BKP ID) REFERENCES BKP ) CREATE TABLE APPLICATION (A NAME, A DESCRIPTION, A DATA DIRECTORY, PRIMARY KEY (A NAME) ) CREATE TABLE DBF FILE (A NAME, DBF NAME, DBF DESCRIPTION, DBF USED, PRIMARY KEY (A NAME, DBF NAME), FOREIGN KEY (A NAME) REFERENCES APPLICATION ) CREATE TABLE LOT (FDYD ID, NAME, LOT ID NUM, LOT ID, GNDR CODE, PROJ CLOSEOUT, IN WEIGHT, VALID, OWNER, COMMENT, BKP ID, A NAME, DBF NAME, DBF UPDATE RECNO, VALIDTIME AND TRANSACTIONTIME PRIMARY KEY (FDYD ID, LOT ID NUM), FOREIGN KEY (FDYD ID) NONSEQUENCED VALIDTIME REFERENCES FDYD, NONSEQUENCED VALIDTIME AND TRANSACTIONTIME UNIQUE (FDYD ID, LOT ID NUM, LOT ID) ) AS VALIDTIME PERIOD(DATE) AND TRANSACTIONTIME CREATE TABLE LOT CONTAINS (FDYD ID, LOT ID NUM, BKP ID, A NAME, DBF NAME, DBF UPDATE RECNO, TRANSACTIONTIME PRIMARY KEY (FDYD ID, LOT ID NUM), FOREIGN KEY (FDYD ID, LOT ID NUM) TRANSACTIONTIME REFERENCES LOT, FOREIGN KEY (FDYD ID, BKP ID) REFERENCES BKP, FOREIGN KEY (A NAME, DBF FILE) REFERENCES DBF FILE ) AS TRANSACTIONTIME CREATE TABLE BKP (FDYD ID, BKP ID, YEAR MONTH, DATE PROCESSED, QUIRKS, VTRC LAST DATE MOD, BRDR LAST DATE MOD, ARCH LAST DATE MOD, Figure 12.1 SQL3 schema. 441 442 CHAPTER TWELVE : LANGUAGE DIRECTIONS NONSEQUENCED TRANSACTIONTIME PRIMARY KEY (FDYD ID, BKP ID), FOREIGN KEY (FDYD ID) REFERENCES FDYD ) AS TRANSACTIONTIME CREATE TABLE LOT MOVE (FDYD ID, LOT ID NUM, FROM PEN ID, TO PEN ID, HD CNT, BKP ID, A NAME, DBF NAME, VALIDTIME AND TRANSACTIONTIME PRIMARY KEY (FDYD ID, LOT ID NUM, FROM PEN ID, TO PEN ID), FOREIGN KEY (FDYD ID, LOT ID NUM) VALIDTIME AND TRANSACTIONTIME REFERENCES LOT, FOREIGN KEY (FDYD ID, FROM PEN ID) NONSEQUENCED VALIDTIME REFERENCES PEN (FDYD ID, PEN ID), FOREIGN KEY (FDYD ID, TO PEN ID) NONSEQUENCED VALIDTIME REFERENCES PEN (FDYD ID, PEN ID), FOREIGN KEY (FDYD ID, BKP ID) NONSEQUENCED VALIDTIME REFERENCES BKP, FOREIGN KEY (A NAME, DBF FILE) NONSEQUENCED VALIDTIME REFERENCES DBF FILE ) VALIDTIME PERIOD(TIMESTAMP MINUTE) AND TRANSACTIONTIME CREATE TABLE LOT LOC (FDYD ID, LOT ID NUM, PEN ID, HD CNT, YEAR MONTH, VALIDTIME AND TRANSACTIONTIME PRIMARY KEY (FDYD ID, LOT ID NUM, PEN ID), FOREIGN KEY (FDYD ID, LOT ID NUM) VALIDTIME AND TRANSACTIONTIME REFERENCES LOT, FOREIGN KEY (FDYD ID, PEN ID) NONSEQUENCED VALIDTIME REFERENCES PEN ) AS VALIDTIME PERIOD(TIMESTAMP MINUTE) AND TRANSACTIONTIME CREATE TABLE MASS TRTMNT (FDYD ID, LOT ID NUM, PEN ID, M TRTMNT AVG WGT, VALIDTIME PRIMARY KEY (FDYD ID, LOT ID NUM, PEN ID), FOREIGN KEY (FDYD ID, LOT ID NUM) VALIDTIME REFERENCES LOT, FOREIGN KEY (FDYD ID, PEN ID) NONSEQUENCED VALIDTIME REFERENCES PEN, FOREIGN KEY (FDYD ID, BKP ID) NONSEQUENCED VALIDTIME REFERENCES BKP ) AS VALIDTIME PERIOD(DAY) Figure 12.1 (continued) 12.11 CAPSTONE CASE 443 12.11.2 Queries As we've seen from the previous case studies, queries on time-varying tables are much easier to express in SQL3 than in SQL-92. We continue this comparison with the queries in Section 11.7.1. Code Fragment 12.99 How many head of cattle from lot 219 in yard 1 are (currently) in each pen? SELECT PEN ID, HD CNT FROM LOT LOC WHERE FDYD ID = 1 AND LOT ID NUM = 219 Code Fragment 12.100 Give the history of how many head of cattle from lot 219 in yard 1 were in each pen. VALIDTIME SELECT PEN ID, HD CNT FROM LOT LOC WHERE FDYD ID = 1 AND LOT ID NUM = 219 Code Fragment 12.101 How many head of cattle from lot 219 in yard 1 were, at some time, in each pen? NONSEQUENCED SELECT PEN ID, HD CNT FROM LOT LOC WHERE FDYD ID = 1 AND LOT ID NUM = 219 Temporal joins are handled in the same way. Code Fragment 12.102 Which lots are currently coresident in a pen? SELECT DISTINCT L1.LOT ID NUM, L2.LOT ID NUM, L1.PEN ID FROM LOT LOC AS L1, LOT LOC AS L2 WHERE L1.LOT ID NUM < L2.LOT ID NUM AND L1.FDYD ID = L2.FDYD ID AND L1.PEN ID = L2.PEN ID Code Fragment 12.103 Which lots were in the same pen, perhaps at different times? NONSEQUENCED VALIDTIME SELECT DISTINCT L1.LOT ID NUM, L2.LOT ID NUM, L1.PEN ID FROM LOT LOC AS L1, LOT LOC AS L2 WHERE L1.LOT ID NUM < L2.LOT ID NUM AND L1.FDYD ID = L2.FDYD ID AND L1.PEN ID = L2.PEN ID 444 CHAPTER TWELVE : LANGUAGE DIRECTIONS Give the history of lots being coresident in a pen. Code Fragment 12.104 VALIDTIME SELECT DISTINCT L1.LOT ID NUM, L2.LOT ID NUM, L1.PEN ID FROM LOT LOC AS L1, LOT LOC AS L2 WHERE L1.LOT ID NUM < L2.LOT ID NUM AND L1.FDYD ID = L2.FDYD ID AND L1.PEN ID = L2.PEN ID Code Fragment 12.105 Provide the state of the LOT CONTAINS table on January 12, 1998. NONSEQUENCED TRANSACTIONTIME SELECT LOT ID NUM, BKP ID, A NAME, DBF NAME, DBF UPDATE RECNO FROM LOT CONTAINS AS L WHERE TRANSACTIONTIME(L) OVERLAPS DATE 1998-01-12 Provide the history of the LOT table as best known on March 15, 1998. Code Fragment 12.106 VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT LOT ID NUM, GNDR CODE, PROJ CLOSEOUT, IN WEIGHT, VALID, OWNER, COMMENT FROM LOT WHERE TRANSACTIONTIME(LOT) OVERLAPS DATE 1998-03-15 Code Fragment 12.107 When were steerings scheduled (as opposed to being recorded after the fact)? NONSEQUENCED VALIDTIME AND NONSEQUENCED TRANSACTIONTIME SELECT S.LOT ID NUM, BEGIN(VALIDTIME(S)) AS When Scheduled, BEGIN(TRANSACTIONTIME(S)) AS When Recorded FROM LOT AS C, LOT AS S WHERE C.FDYD ID = S.FDYD ID AND C.LOT ID NUM = S.LOT ID NUM AND C.GNDR CODE = c AND S.GNDR CODE = s AND VALIDTIME(C) MEETS VALIDTIME(S) AND BEGIN(TRANSACTIONTIME(S)) < BEGIN(VALIDTIME(S)) 12.11.3 Modications We start with current modications, which are unchanged from their nontemporal analogs. Code Fragment 12.108 Lot 433 arrives today. INSERT INTO LOT VALUES (433, h) 12.11 Code Fragment 12.109 CAPSTONE CASE 445 Lot 101 leaves the feed yard. DELETE FROM LOT WHERE LOT ID NUM = 234 Code Fragment 12.110 The cattle in lot 799 are being steered today. UPDATE LOT SET GNDR CODE = s WHERE LOT ID NUM = 799 We now consider sequenced modications. Code Fragment 12.111 Lot 426, a collection of heifers, was on the feed yard from March 26 to April 14. VALIDTIME INSERT INTO LOT VALUES (426, h) The following modication will apply regardless of whether LOT has transactiontime support. Code Fragment 12.112 Lot 234 will be absent from the feed yard for the rst three weeks of October, when the steering will take place. VALIDTIME PERIOD [1998-10-01 - 1998-10-22) DELETE FROM LOT WHERE LOT ID NUM = 234 Code Fragment 12.113 Lot 799 was steered only for the month of March. VALIDTIME PERIOD [1998-03-01 - 1998-04-01) UPDATE LOT SET GNDR CODE = s WHERE LOT ID NUM = 799 This update when expressed in SQL-92 requires two INSERT statements and three UPDATE statements, or some 29 lines of code. Nonsequenced modications are also straightforward. Code Fragment 12.114 Delete the records of lot 234 that have duration greater than three months. NONSEQUENCED VALIDTIME DELETE FROM LOT WHERE LOT ID NUM = 234 AND INTERVAL(VALIDTIME(LOT) AS MONTH) > INTERVAL 3 MONTH 446 CHAPTER TWELVE : LANGUAGE DIRECTIONS Code Fragment 12.115 Correct the backup identier for lot 433 to 37. UPDATE LOT CONTAINS SET BKP ID = 37 WHERE LOT ID = 433 12.12 MIGRATION The potential users of the extensions to SQL3 just described are enterprises with applications that need to manage potentially large amounts of time-varying information. In the case studies we just covered, we tacitly assumed that we could code these applications in SQL3 from scratch. In reality, it is probable that these enterprises are already managing time-varying data using SQL-92 (more specically, a particular variant provided by the DBMS vendor) and that the temporal applications are already in place and working. Indeed, the uninterrupted functioning of applications is likely to be of vital importance. The question then becomes how to recast the application to use the new SQL3 constructs. We provide an effective migration path by identifying four successively more general levels of queries and modications. In this section, we differentiate the temporal constructs proposed for SQL3 from the (massive) remainder of SQL3. To do so, we use the name of Part 7 of SQL3— SQL/Temporal—to denote the temporal constructs, and we use the name of Part 2—SQL/Foundation—to denote the nontemporal portion. 12.12.1 Upward Compatibility Perhaps the most important aspect of ensuring a smooth transition is to guarantee that all application code without modication will work with the new system exactly with the same functionality as with the existing system. To explore the relationship between nontemporal and temporal data and queries, we employ a series of gures that demonstrate increasing query and update functionality. In Figure 12.2, a conventional table is denoted with a rectangle. The current state of this table is the rectangle in the upper-right corner. Whenever a modication is made to this table, the previous state is discarded; hence, at any time only the current state is available. The discarded prior states are denoted with dashed rectangles; the right-pointing arrows denote the modication that took the table from one state to the next state. When a query q is applied to the current state of a table, a resulting table is computed, shown as the rectangle in the bottom-right corner. While this gure only concerns queries over single tables, the extension to queries over multiple tables is clear. 12.12 MIGRATION 447 Time q Figure 12.2 Evaluating an SQL/Foundation query over a table without temporal support, to return a table also without temporal support. Upward compatibility states that (1) all instances of tables in SQL/Foundation are instances of tables in SQL/Temporal, (2) all SQL/Foundation modications to tables in SQL/Foundation result in the same tables when the modications are evaluated according to SQL/Temporal semantics, and (3) all SQL/Foundation queries result in the same tables when the queries are evaluated according to SQL/Temporal. By requiring that the temporal constructs be a strict superset (i.e., only adding language constructs), it is relatively easy to ensure that the temporal constructs are upward compatible with SQL/Foundation. 12.12.2 Temporal Upward Compatibility If an existing or new application needs support for the temporal dimension of the data in one or more tables, the table can be dened with or altered to add temporal support (e.g., by using the CREATE TABLE . . . AS VALID or AS TRANSACTION or ALTER . . . ADD VALID or ADD TRANSACTION statements). It is undesirable to be forced to change the application code that accesses the table without temporal support, when temporal support is added to that table. Previously we have mentioned a requirement that states that the existing applications on tables without temporal support will continue to work with no changes in functionality when the tables they access are altered to add temporal support. Specically, temporal upward compatibility requires that each query will return the same result on an associated 448 CHAPTER TWELVE : LANGUAGE DIRECTIONS Time q Figure 12.3 Evaluating an SQL/Foundation query over a table with temporal support, to return a table without such support. snapshot database as on the temporal counterpart of the database. Further, this property applies to modications to those tables with temporal support. Temporal upward compatibility is illustrated in Figure 12.3. When temporal support is added to a table, the history is preserved, and modications over time are retained. In this gure, the state to the far left was the current state when the table was made temporal. All subsequent modications, denoted by the arrows, result in states that are retained, and thus are solid rectangles. Temporal upward compatibility ensures that the states will have identical contents to those states resulting from modications of the table without temporal support. The query q is an SQL/Foundation query. Due to temporal upward compatibility, the semantics of this query must not change if it is applied to a table with temporal support. Hence, the query only applies to the current state, and a table without temporal support results. As an example from the University Information System, take the following SQL92 query on a nontemporal INCUMBENTS table: Code Fragment 12.116 What is Bob's position? SELECT JOB TITLE CODE1 FROM EMPLOYEES, INCUMBENTS, POSITIONS WHERE FIRST NAME = Bob AND EMPLOYEES.SSN = INCUMBENTS.SSN AND INCUMBENTS.PCN = POSITIONS.PCN 12.12 MIGRATION 449 After adding valid-time support to INCUMBENTS, this query is interpreted as a current query, returning Bob's current position (which is, after all, what the query did when evaluated on the nontemporal version of the INCUMBENTS table). Temporal upward compatibility applies to all SQL/Foundation statements. Consider the following SQL-92 modication on a nontemporal table: Code Fragment 12.117 Bob was promoted to director of the Computer Center. UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 Temporal upward compatibility demands that this modication, when applied to a table with valid-time support, be interpreted as impacting the current state of that table, that is, that it be interpreted as a current modication, and so it is. The same holds for tables with transaction-time support and for bitemporal tables. Temporal upward compatibility at its core says this: Take an application that doesn't involve time, that concerns only the current reality. An example is an application storing the current job assignments of employees. Alter one or more of the tables so that they now have temporal support (valid-time, transaction-time, or both). The application should run as before, without changing a single line of code. This is an extremely powerful notion. It is instructive to consider temporal upward compatibility in more detail. When designing information systems, two general approaches have been advocated. In the rst approach, the system design is based on the function of the enterprise that the system is intended for (the “Yourdon” approach); in the second, the design is based on the structure of the reality that the system is about (the “Jackson” approach). It has been argued that the latter approach is superior because structure may remain stable when the function changes, but the opposite is generally not possible. Thus, a more stable system design, needing less maintenance, is achieved when adopting the second design principle. This suggests that the data needs of an enterprise are relatively stable and only change when the actual business of the enterprise changes. When replacing a nontemporal system with a temporal system, that is, to utilize the constructs in SQL/Temporal, the enterprise is not changing its business, but wants the extra support offered by the temporal system for managing its temporal data. Thus, it is atypical for an enterprise to suddenly desire to record temporal information where it previously recorded only snapshot information. Such a change would be motivated by a change in the business. The typical situation is rather more complicated. The nontemporal database system is likely to already manage temporal data, which is encoded using tables without temporal support, perhaps using the techniques discussed in early chap- 450 CHAPTER TWELVE : LANGUAGE DIRECTIONS ters. When adopting the SQL/Temporal constructs, upward compatibility guarantees that it is not necessary to change the database schema or application programs. However, without changes, the benets of the added temporal support are also limited. Only when dening new tables or modifying existing applications can the new temporal support be exploited. The enterprise then gradually benets from the temporal support available in the system. Nevertheless, the concept of temporal upward compatibility is still relevant for several reasons. First, it provides an appealing intuitive notion of a table with temporal support: the semantics of queries and modication are retained from tables without such support; the only difference is that intermediate states are also retained. Second, in those cases where the original table contained no historical information, temporal upward compatibility affords a natural means of migrating to temporal support. In such cases, not a single line of the application need be changed when the table is altered to be temporal. Third, conventional tables that do contain temporal information and for which temporal support has been added can still be queried and modied by conventional SQL/Foundation statements in a consistent manner. 12.12.3 Sequenced Extensions The requirements covered so far have been aimed at protecting investments in legacy code and at ensuring uninterrupted operation of existing applications when achieving substantially increased temporal support. Upward compatibility guarantees that (nontemporal) legacy application code will continue to work without change when migrating, and temporal upward compatibility in addition allows legacy code to coexist with new temporal applications following the migration. The requirement introduced in this section aims at protecting investment in programmer training and at ensuring continued efcient, cost-effective application development upon migration. This is achieved by exploiting the fact that programmers are likely to be comfortable with SQL. Sequenced semantics states that SQL/Temporal must offer, for each query in SQL/ Foundation, a temporal query that “naturally” generalizes this query, in a specic technical sense. In addition, we require that the SQL/Temporal query be syntactically similar to the SQL/Foundation query that it generalizes. With this requirement satised, SQL/Foundation queries on tables with temporal support have semantics that are easily (“naturally”) understood in terms of the semantics of the SQL/Foundation queries on tables without temporal support. The familiarity of the similar syntax and the corresponding, naturally extended semantics make it possible for programmers to immediately and easily write a wide range of temporal queries, with little need for expensive training. Figure 12.4 illustrates this property. We have already seen that an SQL/Foundation query q on a table with temporal support applies the standard SQL3 semantics 12.12 q' = q q q q MIGRATION 451 q Figure 12.4 Evaluating a sequenced query over a table with valid-time support, to return a table with similar support. on the current state of that table, resulting in a table without temporal support. This gure illustrates a new query, q0 , which is an SQL/Temporal sequenced query. Query q0 is applied to the table with temporal support (the sequence of states across the top of the gure), and results in a table also with temporal support, which is the sequence of states across the bottom. We would like the meaning of q0 to be easily understood by the SQL/Foundation programmer. Satisfying sequenced semantics along with the syntactical similarity requirement makes this possible. Specically, the meaning of q0 is precisely that of applying SQL3 query q on each state of the input table (which must have temporal support), producing a state of the output table for each such application. And when q0 also closely resembles q syntactically, temporal queries are easily formulated and understood. To generate query q0 , we need only prepend the reserved word VALIDTIME or TRANSACTIONTIME to query q. As an example, let q be the following nontemporal query, Code Fragment 12.118 Provide the salary and department for all employees. SELECT S.SSN, AMOUNT, PCN FROM SAL HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN and q0 be the sequenced variant of q. 452 CHAPTER TWELVE : LANGUAGE DIRECTIONS m' = m m m m m Figure 12.5 Evaluating an SQL/Temporal modication on a table with valid-time support. Code Fragment 12.119 Provide the salary and department history for all employees. VALIDTIME SELECT S.SSN, AMOUNT, PCN FROM SAL HISTORY AS S, INCUMBENTS WHERE S.SSN = INCUMBENTS.SSN One small addition was made to the English statement, “history,” and one small addition was made to the SQL/Temporal statement, VALIDTIME. These concepts also apply to sequenced modications, illustrated in Figure 12.5. A valid-time modication destructively modies states as illustrated by the curved arrows. As with queries, the modication is applied on a state-by-state basis. Hence, the semantics of the SQL/Temporal modication is a natural extension of the SQL/ Foundation modication statement that it generalizes. Elaborating on the example, the following nontemporal modication m, CF-12.120, can modify all times with a sequenced version, m0 = VALIDTIME m, CF-12.121, or with a sequenced version with a specied period of applicability, CF-12.122. Code Fragment 12.120 Bob was promoted to director of the Computer Center. UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 Code Fragment 12.121 Bob was promoted to director of the Computer Center for all time. VALIDTIME UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 12.12 MIGRATION 453 q Figure 12.6 Evaluating a nonsequenced query over a table with valid-time support, to return a table with similar support. Code Fragment 12.122 Bob was promoted to director of the Computer Center for 1997. VALIDTIME PERIOD [1997-01-01 - 1997-12-31] UPDATE INCUMBENTS SET PCN = 908739 WHERE SSN = 111223333 12.12.4 Nonsequenced Queries and Modications In a sequenced query, the information in a particular state of the resulting table with temporal support is derived solely from information in the state at that same time of the source table(s). However, there are many reasonable queries that require other states to be examined. Such queries are illustrated in Figure 12.6, in which each state of the resulting table requires information from possibly all states of the source table. In this gure, two tables with temporal support are shown, one consisting of the states across the top of the gure, and the other, the result of the query, consisting of the states across the bottom of the gure. A single query q performs the possibly complex computation, with the information usage illustrated by the downwardpointing arrows. Whenever the computation of a single state of the result table may utilize information from a state at a different time, that query is nonsequenced. Such queries are more complex than sequenced queries, and they require a new construct in the query language, specically, the NONSEQUENCED reserved word. 454 CHAPTER TWELVE : LANGUAGE DIRECTIONS Figure 12.7 Evaluating a nonsequenced modication on a table with valid-time support. Code Fragment 12.123 List all the salaries, past and present, of employees who had been hazardous waste specialists at some time. NONSEQUENCED VALIDTIME SELECT AMOUNT FROM INCUMBENTS, POSITIONS, SAL HISTORY WHERE INCUMBENTS.SSN = SAL HISTORY.SSN AND INCUMBENTS.PCN = POSITIONS.PCN AND JOB TITLE CODE1 = 20730 The phrases “past and present” and “at some time” indicate that the query is a nonsequenced one. It is important to note that nonsequenced queries are very different from sequenced queries. In the latter, the query language is providing a temporal semantics; in the former, the query language interprets the timestamp as simply another column. For the user, this means that in nonsequenced queries (modications, assertions, etc.) the period timestamps must be manipulated explicitly. The operations, such as join and relational difference, are performed with respect to the periods themselves, rather than on the individual states of the tables with temporal support. Reserved words are used to syntactically differentiate temporally upward compatible queries, sequenced queries, and nonsequenced queries, each of which applies a distinct semantics. The concept of nonsequenced queries naturally generalizes to modications. Nonsequenced modications destructively change states, with information retrieved from possibly all states of the original table. In Figure 12.7, each state of the table with valid-time support is possibly modied, using information from possibly all states of the table before the modication. Nonsequenced modications include future modications. (We note in passing that nonsequenced modications are only permitted on tables with valid-time support; all modications are current in transaction time.) In the nonsequenced modication of CF-12.124, the deletion of a particular state is dependent on the PCN being in the state on December 31, 1997. 12.13 ADDITIONAL CONSTRUCTS OF SQL3* 455 Result of NORMALIZE: Figure 12.8 The NORMALIZE operator. Code Fragment 12.124 Delete Bob's records that include 1997 stating that he was associate director of the Computer Center. NONSEQUENCED VALIDTIME DELETE FROM INCUMBENTS WHERE SSN = 111223333 AND PCN = 999071 AND VALIDTIME(INCUMBENTS) CONTAINS DATE 1997-12-31 12.13 ADDITIONAL CONSTRUCTS OF SQL3* A few additional constructs are dened in SQL/Temporal and are mentioned here for completeness. A set constructor specialized to periods is included. The NORMALIZE(pset) operator, where pset is a set of periods, yields a potentially smaller set of periods that are disjoint, that is, they do not meet or overlap. Figure 12.8 illustrates the result of this operator on a set of periods. The six periods at the top comprise the input to the operator; the two periods at the bottom comprise the result. Effectively, the periods are coalesced with duplicate elimination. The parallel operation of coalescing while retaining duplicates is not provided. An EXPAND operator, which converts a period into a SET of the period's element type, is also provided. EXPAND(PERIOD [1997-01-01 00:00:00 - 1997-12-31 00:00:00]) would result in a value of type SET(TIMESTAMP(0)) (i.e., to the granularity of second), with 31,536,000 elements (!). This set can be converted back to the original period via a new NORMALIZE ON construct of the select statement. This 456 CHAPTER TWELVE : LANGUAGE DIRECTIONS construct is best explained with an example. The following statement EXPANDs a period column (ATable.APeriod), then normalizes it back into the original period. Code Fragment 12.125 Expanding each period into a set of granules, then normalizing back to a period. SELECT A, B, C, PERIOD[E3, E3] AS P FROM (SELECT A, B, C, EXPAND(APeriod) AS E FROM ATable) AS E1, TABLE(E1.E) AS E2(E3) NORMALIZE ON P This rather complex query expands the APeriod column of ATable; the resulting table E1 has a single timestamp column, E, of type SET(TIMESTAMP(0)). The second expression in the FROM clause makes a table out of each set; the value of the E3 column for each row of E2 is a particular timestamp value, such as TIMESTAMP 1997-10-21 17:05:30. The SELECT clause converts each of these times into a period of duration one second. The NORMALIZE ON clause then normalizes the result by collecting the values of P for rows with identical values for the remaining columns (A, B, and C), applying NORMALIZE to this set of periods, then associating a copy of the row with each of the resulting periods. (Whew!) As we'll see later, this idiom can be used to implement certain types of temporal queries. If the original table ATable contained duplicate rows, then this statement will normalize the periods associated with those rows, thereby removing sequenced duplicates. Say table ATable contained six rows with identical values for A, B, and C and with the periods shown in the top portion of Figure 12.8 as the value of the APeriod column. The result of the above statement would contain two rows, associated with the periods in the bottom portion of Figure 12.8. Finally, an EXPANDING clause is added to UNION, EXCEPT, and INTERSECT, but only if ALL is not specied. This clause provides another way to effect a sequenced query. Thus, the following query, on a table without temporal support , rather with an explicit When column of type PERIOD, implements a sequenced EXCEPT (compare with CF-12.22, which replaces the EXPANDING(When) with the prex VALIDTIME). Code Fragment 12.126 List the employees who are department heads but are not also professors (using EXPANDING). SELECT SSN FROM INCUMBENTS WHERE PCN = 455332 EXCEPT EXPANDING (When) SELECT SSN FROM INCUMBENTS WHERE PCN = 821197 12.14 IMPLEMENTATION CONSIDERATIONS 457 This is syntactic sugar for three steps: applying EXPAND to the timestamp, performing the operation, then normalizing the result. Code Fragment 12.127 List the employees who are department heads but are not also professors (using EXPAND and NORMALIZE). SELECT SSN, PERIOD[W2, W2] AS When FROM (SELECT SSN, W2 FROM (SELECT SSN, EXPAND(When) AS W FROM INCUMBENTS WHERE PCN = 455332) AS E1, TABLE(E1.W) AS E2(W2) EXCEPT SELECT SSN, W2 FROM (SELECT SSN, EXPAND(When) AS W FROM INCUMBENTS WHERE PCN = 821197) AS E1, TABLE(E1.W) AS E2(W2) ) AS E3 NORMALIZE ON When While this query, at 14 lines, is certainly shorter than CF-6.18, at 45 lines, it is highly inefcient as stated. Each row of INCUMBENTS is expanded into potentially millions of rows of E3, then normalized back to the result. And because NORMALIZE is used, duplicates are automatically removed. There is no parallel to EXCEPT EXPANDING ALL; instead, VALIDTIME . . . EXCEPT ALL . . . should be used. VALIDTIME lends a sequenced semantics to any query, and as such is preferred over the EXPANDING option, which is constrained to some uses of UNION, EXCEPT, and INTERSECT. In summary, many uses of EXPAND and NORMALIZE are more easily performed by sequenced queries using VALIDTIME or TRANSACTIONTIME, which provides a sequenced semantics to any nontemporal query, view, modication, assertion, and cursor. 12.14 IMPLEMENTATION CONSIDERATIONS SQL3 is in draft form, and vendors are still adding support for the SQL-92 standard; there is currently available (early 1999) no DBMS compliant at the Full SQL level. So understandably no DBMS yet supports the constructs just described. An alternative strategy is to implement temporal support outside the DBMS, as middleware imposed between the application and the DBMS. The user issues temporal statements, which are translated into the variant of SQL supported by the underlying DBMS. This strategy has been employed in several research prototypes, as well as one commercially available product. 458 CHAPTER TWELVE : LANGUAGE DIRECTIONS 12.14.1 T IME DB T IME DB is middleware that supports the constructs proposed for SQL3, including valid time, transaction time, queries, modications, views, assertions, and constraints. It also supports user-specied valid-time coalescing. It doesn't support the EXPAND, EXCEPT EXPANDING, and NORMALIZE constructs described in Section 12.13, though as we saw there, those constructs can often be simulated in a more natural fashion with sequenced statements. There are two quite separate versions of T IME DB. Both accept the same language, but are distinct code bases.   T IME DB 1: This system runs as a front end to Oracle, accepts textual input, and utilizes the Oracle Call Interface (OCI) to evaluate the user requests. The system is implemented in Prolog. Three versions are available, running under SICStus Prolog, Macintosh SICStus Prolog, and SWI Prolog. The T IME DB 1 source (about 10,000 lines of Prolog) is public domain and is included in the distribution. A main-memory emulator of OCI, also implemented in Prolog, allows the system to be used even if Oracle is not available. As SWI Prolog is available free for noncommercial use, T IME DB 1 allows exploration of the SQL3 constructs at no cost. T IME DB 2: This system is implemented in Java, provides a graphical user interface, and uses JDBC to communicate with the underlying DBMS. It has been tested with Oracle8 Server, Sybase's Adaptive Server Enterprise (Version 11.5), and Cloudscape's JBMS (Version 1.1). It is a commercial product from TimeConsult. Both versions of T IME DB were developed by Andreas Steiner. 12.14.2 T IGER T IGER is another front end to Oracle supporting the SQL3 temporal constructs. The T IGER source (about 4000 lines of SWI Prolog code) is freely usable for educational and research purposes. The language supported is ATSQL, which is similar to that proposed for SQL3, including valid time, transaction time, queries, modications, views, assertions, and constraints, with the following differences:     The reserved words VALID and TRANSACTION replace VALIDTIME and TRANSACTIONTIME, respectively. The functions VTIME( ) and TTIME( ) replace VALIDTIME( ) and TRANSACTIONTIME( ). The INTERVAL( ) function is replaced with the DURATION( ) function. SEQUENCED is a new reserved word. If VALID is used as a prex, either SEQUENCED or NONSEQUENCED is required in T IGER. There is a new SET VALID clause, permitting a wider range of expressions than that allowed in SQL3's VALIDTIME clause. 12.14   IMPLEMENTATION CONSIDERATIONS 459 User-speciable coalescing, either on valid time, transaction time, or both, in either order, is supported. EXPAND, EXCEPT EXPANDING, and NORMALIZE are not supported. T IGER was developed by a team directed by Michael Böhlen. 12.14.3 Synchrony Synchrony is a data warehouse query tool developed by the if. . . software company. A data warehouse is a collection of information, often extracted from multiple production databases, that supports sophisticated dimensional analysis tools. Data warehouses are always temporal: the fact table has a time attribute that is a foreign key to a time dimension table. As an example, a data warehouse supporting sales information might have time, store, product, and customer dimension tables in a star schema, in which the fact table has a foreign key to each dimension table. In a conventional data warehouse, the dimensions are themselves nontemporal, which limits their functionality. Suppose an unmarried customer buys a toaster in January. This would cause a row to be inserted into the fact table. If that customer later marries, her marital status would be updated in the customer dimension table. Since the customer table is nontemporal, the previous marital status is lost, and the information about the toaster sale is incorrect, as the warehouse implies that the toaster was bought by a married person. Synchrony is notable in that it supports in a comprehensive fashion time-varying dimension tables. Synchrony provides powerful data loading and query facilities for such tables. Queries such as “What percentage of customers have lived in the same home for over three years, and what percentage of overall sales do they account for?” can be easily expressed. Synchrony differs from the other systems described here in that it doesn't offer a temporal extension of SQL based on the relational model. Rather, Synchrony's query language is graphical and based on a star schema data model. However, Synchrony is similar to the other systems in that it extends a query language and data model to make it easier to express temporal queries, and it generates conventional SQL for evaluation by an underlying DBMS, thereby freeing the user from having to write these complex statements manually. 12.14.4 CD-ROM Materials A wealth of material is available on the CD-ROM:  Some 25 change proposals and expert contributions that have been submitted to the ANSI or ISO SQL3 committees are included. Of particular interest are the valid-time and transaction-time change proposals [92, 93]. 460 CHAPTER TWELVE : LANGUAGE DIRECTIONS      12.15 The full distribution of T IME DB 1 is included, along with all source code and over 30 demos. A demonstration version of T IME DB 2 is included as Java class les. The features missing in the demo version are views, assertions, constraints, update statements, delete statements, subqueries, and transaction-time support. A comprehensive manual is provided, as are over a dozen demos. Information, a thorough manual, and white papers on T IGER are included. T IGER may be run through a web browser at cs.auc.dk/tigeradm/. A white paper and a guide containing several demos of Synchrony are available on the CD-ROM. Several reports discuss the technical challenges of implementing the SQL3 temporal constructs and provide some solutions. SUMMARY In SQL-92, users must “roll their own” temporal support in the application code. SQL3 instead provides explicit support for periods and valid and transaction time, thereby dramatically simplifying the code that must be written. We rst examined the PERIOD data type, introduced in SQL/Temporal. We then looked at the valid-time support available, specically the VALIDTIME and NONSEQUENCED reserved words and the VALIDTIME function. Transaction-time support was introduced via the TRANSACTIONTIME reserved word and function. Bitemporal support is afforded by combining the orthogonal support for valid time and transaction time. These minimal constructs were illustrated by rephrasing the code fragments of the previous case studies in SQL3. Table 12.2 compares the SQL/Temporal code fragments of this chapter with the analogous SQL-92 code fragments for four major case studies: Brad De Groot's feed yard application, Cheryl Bach's University Information System, Nigel Corbin's oil eld application, and Jens Gadgaard's property ownership application. The code fragments in SQL-92 for these four applications totaled 1848 lines; only 520 lines of SQL3 were required to do exactly the same thing. These tables show that, over a wide range of data denition, query, and modication fragments, the SQL-92 version is three times longer in number of lines than the SQL3 version, and many times more complex. In fact, very few SQL3 fragments were more than 10 lines long; some fragments in SQL-92 comprised literally dozens of lines of highly complex code. 12.15 SUMMARY Table 12.2 Application development in SQL-92 and SQL3. Operation Valid-Time State Tables: adding valid-time support sequenced primary key constraint current uniqueness constraint sequenced uniqueness constraints referential integrity (referencing table is temporal) current referential integrity (both tables are temporal) current referential integrity (referenced table is temporal) sequenced referential integrity (both tables are temporal) nonsequenced referential integrity (both tables are temporal) current join queries current not exists query valid time-slice query sequenced selection query sequenced projection query sequenced sort queries sequenced union query sequenced join query sequenced nested query sequenced except queries nonsequenced join queries remove current duplicates remove sequenced duplicates remove nonsequenced duplicates current insertions current deletions current updates sequenced insertion sequenced deletion sequenced updates nonsequenced deletion nonsequenced update partitioned current join query SQL-92 Fragment(s) Lines of Code SQL3 Fragment Lines of Code 5.4 5.8 5.12 5.14 5.19 2 10 9 7 1 12.3 12.4 12.5 12.6 12.7 1 1 1 1 2 5.20 12 12.7 2 5.24 10 12.7 2 5.21 32 12.9 2 5.19 1 12.10 2 6.2, 6.3 6.4 6.5 6.6 6.7 6.8, 6.9 6.10 6.11–6.14 6.18 6.18 6.19, 6.20 6.23 6.24–6.26 6.21 7.1–7.3, 7.5 7.7, 7.8 7.10, 7.11, 7.22 7.12–7.14 7.16 7.18, 7.24 17 7 7 3 2 3 7 7–29 45 45 10 3 19–30 2 2–9 12.12, 12.13 12.14 12.15 12.16 12.17 12.18 12.19 12.20 12.21 12.22, 12.126 12.23, 12.24 12.25 12.26 12.27 12.28 11 5 6 3 2 3 7 3 7 7 11 2 2 2 2 5, 10 9–30 12.29 12.30, 12.36 3 3–6 2–28 24 27–77 2 3 3–6 7.19 7.20 7.25 5 4 5 12.31 12.32 12.33, 12.37 12.122 12.34 12.35 12.38 4 5 5 461 462 CHAPTER TWELVE : LANGUAGE DIRECTIONS Table 12.2 (continued) Operation Valid-Time State Tables (continued): partitioned sequenced join partitioned current insertions partitioned current deletion partitioned sequenced deletion partitioned sequenced update Transaction-Time Tables: adding transaction-time support current query extracting a prior state prior state as a view current state as a view converting to a state table converting to an event table sequenced selection queries sequenced union query sequenced join query sequenced self-join query nonsequenced query current insertions current deletions current updates entity vacuum temporally vacuum log the vacuuming operations Bitemporal State Tables: adding bitemporal support sequenced/sequenced primary key current/current integrity constraint SQL-92 Fragment(s) Lines of Code SQL3 Fragment Lines of Code 7.26 7.27, 7.28 7.29 7.30 7.31 50 2, 6 8 44 57 12.39 12.40 12.41 12.42 12.43 3 2 3 3 3 8.1+8.2, 8.12, 8.15, 9.1+9.2, 9.15+9.17, 9.20+9.21 8.4 8.3, 8.13, 8.14, 8.16, 9.7, 9.18 8.5, 8.17 8.20, 9.3 9.16, 9.19, 9.22 8.7 9.12–9.14 17–44 12.44 1 3 4–19 12.45 12.46 3 4 17–27 0–11 12.47 — 7 0 38 4–26 — 6–27 8.8, 9.8 9.9 9.10 8.18 9.11 8.9, 9.4 8.10, 9.5 8.11, 9.6 9.23 9.24–9.26, 9.28 9.27 3–4 8 8 13 10 4–6 2–4 3–14 4 2–6 — 12.48, 12.51–12.53 12.49 12.57 12.58 12.50 12.59 12.54 12.55 12.56 — — 8 — — 10.1, 10.52 10.2 7–17 13 12.60 12.61 4 2 10.44 12 12.85 6 3 7 5 5 10 4 2 3 — — 12.15 SUMMARY Table 12.2 (continued) Operation Bitemporal State Tables (continued): sequenced/current integrity constraint nonsequenced/current integrity constraint sequenced/current referential integrity contiguous history assertion transaction time-slice current transaction time-slice valid time-slice bitemporal time-slice current bitemporal time-slice current/current queries sequenced/current queries nonsequenced/current query current/sequenced query sequenced/sequenced query nonsequenced/sequenced query current/nonsequenced queries sequenced/nonsequenced query nonsequenced/nonsequenced queries current/current multiway join query sequenced/current join query sequenced/nonsequenced multiway join query current insertion current deletion current update sequenced insertion sequenced deletion sequenced update nonsequenced deletion reconstitute bitemporal state table as a view temporally vacuum Capstone Case: schema denition SQL-92 Fragment(s) Lines of Code SQL3 Fragment Lines of Code 10.45 10 12.86 6 10.46 8 12.87 6 10.49, 10.50 18–48 12.62 2 10.3 10.19 10.20 10.21 10.22 10.23 10.26, 10.35 10.27, 10.37 10.28 10.29 10.30 10.31 10.32, 10.39 10.33 10.31, 10.41 16 5 4 5 7 6 16 16 7 14 15 10 13 12 9 12.84 12.63 12.64 12.65 12.66 12.67 12.68, 12.77 12.69, 12.79 12.70 12.71 12.72 12.73 12.74, 12.81 12.75 12.73, 12.83 14 5 3 5 6 3 8 8 5 5 5 6 9 6 13 10.36 14 12.78 1 10.38 10.40 11 12 12.80 12.82 5 8 10.4 10.10, 10.11 10.7 10.12, 10.13 10.15 10.17 10.18 10.53–10.55 4 13–19 34 4–36 42 58 4 8–51 12.88 12.89 12.90 12.91 12.92 12.93 12.94 — 2 2 3 3 2 3 2 0 10.56 8 — — Fig. 11.2, 11.1–11.20, 11.22, 11.23 245 Fig. 12.1 82 463 464 CHAPTER TWELVE : LANGUAGE DIRECTIONS Table 12.2 (continued) Operation Capstone Case (continued): current queries sequenced queries nonsequenced queries nonsequenced/nonsequenced query extracting a prior state current modications sequenced modications nonsequenced modication SQL-92 Fragment(s) Lines of Code SQL3 Fragment Lines of Code 11.24, 11.28 11.25, 11.30 or 11.31 11.26, 11.29 11.34 11 20–36 12.99, 12.102 12.100, 12.104 8 7 8 9 12.101, 12.103 12.107 8 9 11.32, 11.33 11.35, 11.37, 11.42 11.38–11.40, 11.43 11.41 9 68 12.105, 12.106 12.108–12.110, 12.115 12.111–12.113, 12.112 12.114 15 10 149 10 12 3 To recap, ve requirements must be satised if a language or DBMS can be claimed to provide temporal support: 1. Both valid time and transaction time are supported, in a compatible and orthogonal manner. In particular, the semantics of transaction time, where the state as of a time in the past can be reconstructed, must be guaranteed by the DBMS. 2. Upward compatibility is ensured. Existing constructs applied to nontemporal data should operate exactly as before. This requirement is fairly easy to satisfy. 3. Temporal upward compatibility is ensured. This means that an existing nontemporal application will not be broken when temporal support is added to a table, say, via an ALTER TABLE statement. No changes to application code should be required when the history of the enterprise (valid time) or the sequence of changes to the data (transaction time), or both, are retained. This implies, for example, that a conventional query on tables with temporal support should be interpreted as a current query. Upward compatibility and temporal upward compatibility guarantee that legacy application code needs no modication when migrating and that new temporal applications may coexist with existing applications. They are thus aimed at protecting investments in legacy application code. 4. Sequenced variants should be easy to express for all constructs of the language, including queries, modications, views, assertions and constraints, and cursors. This requirement ensures that the extended query language is easy to use for programmers familiar with the existing query language, thus helping to protect investments in programmer training. In particular, complex rewritings of the statement should not be necessary. 12.16 READINGS 465 5. Nonsequenced variants should also be easy to express. In part, such variants enable data with temporal support to be converted to and from data without temporal support. The SQL/Temporal constructs discussed here satisfy these requirements: 1. Valid time can be added to a table via AS VALIDTIME PERIOD; transaction time can be added with AS TRANSACTIONTIME. Only current modications are allowed in transaction time to ensure that time-slices will be correct. Either kind of time can be used individually or together, forming a bitemporal table. 2. The temporal constructs of SQL/Temporal are dened as an upward compatible extension of the other parts of SQL3. 3. All conventional queries (modications, views, assertions, constraints, cursors) on tables with temporal support are interpreted as current queries (respectively, modications, etc.). As an example, when valid-time support was added to the INCUMBENTS table, the existing code of this application, perhaps tens of thousands of lines, did not require a single change. 4. An SQL/Foundation query can be converted to a sequenced query in SQL/Temporal simply by prepending the keyword VALIDTIME. This also holds for modications (e.g., VALIDTIME UPDATE), views (e.g., CREATE VIEW AS VALIDTIME SELECT), and constraints (e.g., VALIDTIME UNIQUE). And of course this also applies to transaction time, via the TRANSACTIONTIME keyword. 5. Nonsequenced statements require the additional keyword NONSEQUENCED. The valid timestamp associated with a row is accessible via the function VALIDTIME( ), and the transaction timestamp, via TRANSACTIONTIME( ). As we have shown with the case studies throughout this chapter, these proposed constructs (three new reserved words, VALIDTIME, TRANSACTIONTIME, and NONSEQUENCED, in addition to those already in SQL/Temporal) can greatly simplify application development, often reducing the amount of SQL code that needs to be written by a factor of three or more, while improving the comprehensibility of that code. Finally, we examined two prototypes (T IME DB 1 and T IGER) and a commercial product (T IME DB 2) that support these constructs, as well as another product, Synchrony, which supports time-varying dimensions in a data warehouse. 12.16 READINGS SQL-86 and SQL-89 had no notion of time. SQL-92 added datetime and interval data types, though no product has yet been validated for conformance to this standard (some products have been validated at the Entry level, which does not include the temporal data types). However, it has long been recognized in the temporal database research community, and as the case studies in this special series have 466 CHAPTER TWELVE : LANGUAGE DIRECTIONS illustrated, that these data types alone are inadequate. Momentum for a temporal extension to SQL designed by that community rst became evident at the Workshop on an Infrastructure for Temporal Databases, held in Arlington, Texas, in June 1993 [87]. The TSQL2 committee was subsequently formed, producing a preliminary language specication the following January. The nal version was completed in September 1994, and a book describing the language and examining in detail its underlying design decisions was released at the VLDB International Workshop on Temporal Databases in Zurich in September 1995 [91]. The ANSI and ISO SQL3 committees became involved in late 1994. A new part to SQL3, termed SQL/Temporal, was proposed and formally approved by the SQL3 International Organization for Standardization in Ottawa in July 1995 as Part 7 of the SQL3 draft standard. Jim Melton agreed to edit this new part [69]. There is presently a two-year experiment (ending in 2000) to allow drafts to be visible to the public. Hence, this draft may be viewed at ftp://jerry.ece.umassd.edu/isowg3/dbl/BASEdocs/public/sqltmprl.ps. PDF and ASCII text versions are also available. The rst task was to dene a PERIOD data type, which is now included in Part 7. Discussions then commenced on adding further temporal support. Two change proposals resulted, one on valid-time support and one on transactiontime support [92, 93]. These change proposals have been unanimously approved by the ANSI SQL3 committee (ANSI X3H2) for consideration by the ISO SQL3 committee (ISO/IEC JTC 1/SC 32/WG 3). The full story may be found at www.cs.arizona.edu/people/rts/tsql2.html. In the meantime, the SQL committees decided to focus on Parts 1, 2, 4, and 5 of the SQL3 draft standard. These parts are expected to be nalized as an international standard in 1999 [30]. At that time, the committees will revisit the other parts and move them through the exhaustive process towards standardization. Michael Böhlen and Robert Marti introduced the notion of temporal semicompleteness as a (highly desirable) property of a temporal query language [14]. Translated into our terminology, temporal semicompleteness says that a sequenced query should be a syntactic augmentation of the associated nontemporal query, with the augmentation consisting solely of constructs added before and after the query. SQL3 is thus temporally semicomplete because a nontemporal query can be rendered sequenced by simply prepending VALIDTIME. The initial design of this construct appeared in 1995 [15]. Transitioning from SQL-92 to SQL3 is covered in depth by John Bair et al. [3] and by the author and others [94]. System design based on the function of the enterprise is advocated by Edward Yourdon [106]; system design based on the structure of the reality that the system is about has been elaborated by Michael Jackson [46]. 12.16 READINGS 467 T IME DB was developed by the TimeConsult software company under the direction of Andreas Steiner. TimeConsult provides consulting in handling temporal data in relational, object-relational, and object-oriented DBMSs; implements temporal database applications; and supports their T IME DB 2 product. For more information, see their Web site at www.timeconsult.com or contact Andreas Steiner at steiner@timeconsult.com. T IGER was developed by a team directed by Michael Böhlen at the Department of Computer Science, Aalborg University, Denmark. He can be reached at boehlen@cs.auc.dk; his Web page is www.cs.auc.dk/boehlen/. The T IGER Web page is cs.auc.dk/tigeradm/, which includes an online demo. The Prolog code for both T IGER and T IME DB1 resembles that developed in the early 1990s to support ChronoLog [10]. T IGER supports the ATSQL language [12]. Synchrony is analytic software developed by the if. . . software company. if. . . develops analytic software designed for business analysts and decision makers to examine in-depth relationships across multiple aspects of their businesses. For more information, contact if. . . at 510-864-3480 or www.iftime.com. The Swatch Webmaster and BMT are described at www.swatch.ch, clicking on “.beat”. CHAPTER 13 Prospects S o we see that development of time-varying database applications in SQL is possible, but is devilishly difcult. There are proposals before the SQL3 committee for new language constructs that help immensely. How long will we have to wait until such facilities are widely available? In the near term, developers of time-oriented applications have three choices. The easiest option is to minimize the use of time in the application, reducing the complexity of the SQL needed, as well as the functionality of the delivered application. The second option is to use the concepts and techniques introduced in this book to develop powerful and correct time-oriented applications. Of course, the SQL code required will often be daunting. The last option is to use third-party software to translate temporal queries (expressed in the SQL/Temporal syntax, or a related syntax) into SQL-92. Such translators are already available commercially, and as the market for such middleware matures, their number and sophistication will grow. In the longer term, vendors will start integrating temporal support into the DBMS itself. Initially, this will be done by simply imposing a middleware translator between the application and the DBMS. While this is architecturally identical to the third option just described, the perception will be that the DBMS itself has temporal support, an important marketing distinction. The vendor can then gradually move the functionality from the middleware component to the internals of the DBMS, retaining the temporal language but gaining in efciency, with the timing of this transfer from middleware to DBMS internals based on market demand. Unlike other constructs, such as triggers and object-relational extensions that are now de rigueur for commercial DBMS offerings, a standard for temporal support was proposed before such support was implemented in a product. When a middleware or DBMS vendor decides to implement temporal support, the language of choice should be something similar to what has been proposed (and summarized in the previous chapter). The ever-present danger, existing in previous extensions 470 CHAPTER THIRTEEN: PROSPECTS and to which temporal extensions are susceptible, is that vendors will attempt to impose proprietary language constructs. We've already seen that occur with the basic temporal types, with many vendors basically ignoring the SQL-92 standard data types of DATE, TIME, and TIMESTAMP. We can only hope that when support for valid time and transaction time is added, the vendors utilize the mature language constructs already designed and rened by the SQL3 standards committees. Temporal extensions will not occur in a vacuum—they must be integrated with other facilities now being added or considered for the future. Fortunately, the requirements of upward compatibility, temporal upward compatibility, and sequenced support ensure that whatever constructs are later added will be usable in current, sequenced, and nonsequenced queries, views, modications, assertions, and cursors over tables with temporal support. Predicting when the transition from third-party middleware solutions to integrated temporal DBMS offerings will occur is difcult. I estimate that the rst will appear by the year 2000. As the benets of such support become clear and acknowledged (the readers of this chapter are already aware of these advantages), pressure will mount on the remaining DBMS vendors to follow suit. Very quickly thereafter, a phase shift will occur, with temporal support along the lines proposed for SQL3 appearing in all DBMS offerings, as such support becomes a mandatory requirement. Glossary This glossary is an extension of the ofcial one, which is in two parts, general concepts [49] and time granularity concepts [7]. The page in which the term is dened is indicated in parentheses. A . D . anno Domini, “in the year of our Lord”. after-image The new value of a modied row or column. A . H . anno Hegirae, the rst year of the Hijri (Islamic) calendar. A . M . (1) annus mundi, or “year of the world”. 6000 A . M . started October 27, 1997. (2) ante meridiem, or “before noon.” append-only A property of tables with transaction-time support, in which changes are implemented only as insertions, or changing the transaction-stop time to “now,” so that the changes always accummulate in the table. archival store The component of a temporally partitioned transaction-time state table containing rows that have been corrected, that is, rows with a transaction-time stop date before “now”. as-of date The (transaction-time) date for which a prior state of a monitored table is to be reconstructed. atom There are 22,500 atoms in an hour, so a second is exactly 6 1/4 atoms. atomic second 9,192,631,770 periods of the radiation emitted by the transition between two particular hyperne states of the cesium 133 atom in the ground state. A . U . C . ab urbe condita, or “from the foundation of the city”. A . U . C . was the prevailing year numbering system before the use of B . C .–A . D . 1 A . D . is 754 A . U . C . backlog A tracking log with the modication operation explicitly identied. B . C . An acronym for “before Christ”. B . C . E . The preferred term for B . C .; an acroymn for “before the Christian Era” or “before the Common Era”. before-image The previous value of a modied row or column. bitemporal table Having support for both valid time and transaction time. 472 GLOSSARY bitemporal time diagram bitemporal table. bitemporal time-slice A two-dimensional graphical notation of the information content of a A query or view that selects the snapshot state of a bitemporal table at specied valid-time and specied transaction-time instants. BMT Biel Mean Time, based on the meridian for Internet Time in Biel, Switzerland. B . P. An acronym for “before the present”. C . E . The preferred term for A . D .; an acronym for “Common Era”. chronology The science of timekeeping. See also horology. clepsydra A clock powered by the ow of water. coalesce Reduce the number of rows in a table by merging the periods of validity of value-equivalent rows. comparable In SQL-92, indicates whether values of two types can be compared. current duplicate Two rows that are sequenced duplicates in the current state. current insertion A row that became valid now. current integrity constraint Must hold only for the current state. current join A join over the current states of the two argument tables. current modication Concerns a change that occurred now. current store The component of a temporally partitioned state table containing rows that are still current, that is, rows with a stop date of “now”. current time-slice query Expressed on the current state of the table or database. current update Changes a fact now. current valid time-slice query Expressed on the current valid-time state of the table or database. DATE An SQL-92 data type, with a granularity of day. Supported by IBM DB2 UDB; by Informix– Universal Server; by Oracle8 Server, with a granularity of second; and by UniSQL, also with a granularity of second. datetime An SQL-92 instant data type or value. DATETIME A data type supported by Informix–Universal Server, with a speciable precision; by Microsoft Access, with a granularity of slightly less than one millisecond; by Microsoft SQL Server, with a granularity of 1/300 of a second; and by Sybase SQLServer, also with a granularity of 1/300 of a second. day-time interval An SQL-92 interval data type containing only the day, hour, minute, and second elds, with an optional fractional seconds. degenerate specialization A bitemporal entity type, relationship type, or table in which the beginning of the valid-time extent (the entity's lifespan) exactly corresponds to the beginning of the transaction time. dirty read An isolation level that allows transactions to read uncommitted values. entity vacuuming Purging entities that are judged to be less interesting from the archival store. ephemeris second 1/31,556,925.9747 of the period of the tropical year between the vernal equinoxes of 1899 and 1900. GLOSSARY 473 equation of time The difference between mean solar time and true solar time. equinoctial day A day for which the daylight is equal in duration to the night, that is, March 21 or September 21. escapement The mechanism within a mechanical clock that regulates the advancement of the hands, while subtly imparting energy to the oscillator, to keep the clock running. event An instantaneous fact, that is, something occurring at an instant in the modeled reality. fully general A bitemporal entity type, relationship type, or table that exhibits no coupling between its valid and transaction timestamps. gnomon The pointer portion of a sundial. gnomonics The science of sundials. See also chronology. granularity A partitioning of the time line, for example, years, days, microseconds. granule A specic unit element of a granularity. heliochronometer A sundial. hemicyclium A truncated, and thus lighter, hemispherium. hemispherium Berossos's sundial, made by hollowing out a half-sphere in a rectangular block of stone. history store The component of a temporally partitioned state table containing rows that were valid in the past, that is, rows with a stop date before “now”. horology The science of time measurement, and the art of constructing instruments that indicate time. hour 1/24 th of a mean solar day. instant A time point on an underlying time axis, or equivalently, an anchored location on that axis. Internet Time A day in Internet Time starts at midnight BMT and contains 1000 Swatch Beats. interstate integrity constraint A constraint applied across states of the table. See also nonsequenced integrity constraint. interval An unanchored contiguous portion of the time line. INTERVAL An SQL-92 data type, with a user-speciable granularity. See also day-time interval and year-month interval. Supported by Informix–Universal Server. intrastate integrity constraint A constraint applied independently to each state of the table. See also sequenced integrity constraint. jiffy In the United States and Canada, 1/60th of a second; in most other places, 1/50th of a second, though 10-millisecond jifes (1/100th of a second) are becoming more common. k'o Roughly a quarter hour, indicated by Chinese clepsydrae: each 14 minutes and 24 seconds long. labeled duration An IBM DB2 UDB construct consisting of a numeric expression followed by a time unit, singular or plural. lifespan The valid-time extent of an entity or of a relationship in the ER model. lunar day The average interval between successive moonrises. mean time The time calculated by a ctitious earth traversing at a constant speed around the sun. 474 GLOSSARY millennium bug A catch phrase for the year 2000 problem. monitored table A table for which a tracking log is maintained. monotonic vacuuming specication Repeated application of the vacuuming does not violate the specication. nonsequenced duplicate columns. Rows with identical values for their timestamp and nontimestamp nonsequenced integrity constraint Treats the timestamp as just another column. nonsequenced modication Treats the row's timestamp as just another column. nonspecialized See fully general. nontemporal entity type An entity type for which the lifespan is not recorded. nontemporal relationship type A relationship type for which the valid time is not captured. ost There are 60 osts (ostenta) to the hour, so an ost is equivalent to a minute. period The time between two instants, or equivalently, an anchored duration of the time line. PERIOD An SQL3 data type constructor, with a user-specied granularity. period of applicability The period over which a sequenced modication applies. period of presence The (transaction-time) period for which a row was logically resident in the table. period of validity The period for which a fact represented by a row is valid in the modeled reality. P. M . post meridiem, or “after noon.” point There are ve points (puncta) to the hour. position In SQL-92, the number of characters from the character set SQL TEXT that it would take to represent any value of that type. postactive modication A modication in which the period of applicability is after the transactionstart time. postactive specialization A bitemporal entity type, relationship type, or table in which the beginning of the valid timestamp is always after or equal to the beginning of the transaction timestamp. precision In SQL-92, the number of fractional digits allowed in the value of the associated data type. precision decomposition Columns with a ner granularity than that of the table they are associated with are placed in a separate table, with a timestamp of that ner granularity. proleptic Gregorian calendar The Gregorian calendar extrapolated backwards to 1 C . E .; used in SQL-92. reconstruct Retrieve a prior state of a monitored table, as of a specied date. retroactive modication A modication in which the period of applicability is before the transaction-start time. retroactive specialization A bitemporal entity type, relationship type, or table in which the beginning of the valid timestamp is equal to or before the beginning of the transaction timestamp. sequenced deletion Removes rows that became invalid now. sequenced duplicate Rows that are duplicates at some instant. sequenced integrity constraint Is applied independently at each point in time. GLOSSARY sequenced join argument tables. Join two tables by joining, at each point in time, the corresponding states of the sequenced primary key every state. sequenced update update. serialization sidereal day time. 475 A constraint stating that the specied columns constitute a primary key in Occurred independently in each state, over the period of applicability of the An isolation level in which only committed values may be read. The time between two meridian transits of a star, 23 hours and 56 minutes of true solar sidereal second 1/86,400th of a sidereal day. SMALLDATETIME A Microsoft SQL Server data type, with a granularity of minute, and a Sybase SQLServer data type, also with a granularity of minute. snapshot equivalent Two rows or tables in which all of their snapshots, resulting from a time-slice at an instant of time, are identical. snapshot of a table The rows of that table valid at (or within the period of presence of, for a transaction-time table) a specied instant. snapshot table A table that is not timestamped with either valid time or transaction time. solar day See true day. Sothic cycle When the lunar New Year coincides with the solar New Year in the Egyptian calendar, once every 1460 years. Swatch Beat One-thousandth of a solar day, of length 1 minute 26.4 seconds. temporal As a modier, used to indicate that the modied concept concerns some aspect of time. temporal constructor An expression that returns a temporal value. temporal specialization Denotes the coupling of the valid and transaction timestamps of a bitemporal entity type, relationship type, or table. temporal support decomposition Columns that differ in their temporal support from the enclosing table are placed in a separate table. temporal table A table supporting valid time or transaction time. temporal upward compatibility An SQL-92 statement (query, modication, view, assertion, constraint) will have the same effect on an associated snapshot database as on the temporal counterpart of the database. temporal vacuuming Purging old information from the archival store. temporally partitioned table A state table that is represented physically as two or more tables, with the criterion of which underlying table a row resides based on the temporal extent of that row. TIME An SQL-92 data type, with a default granularity of second. Supported by IBM DB2 UDB and by UniSQL, with a granularity of second. time-dependent assumption An often implicit assumption that will be invalidated purely by the course of time. The year 2000 problem is a specic instance. time-invariant Data or a table that doesn't vary over time. 476 GLOSSARY time-invariant key A key that identies a particular entity over its entire lifespan. time-invariant participation constraint A participation constraint that holds over the entire valid time of the relationship. time-invariant unique Attribute(s) that are unique for a particular entity or relationship over its entire lifespan or valid time. time-sequence Of an object, the sequence (ordered by time) of pairs of a data object and an instant. time-slice Of a row or a table: the value(s) at a specied instant of time. time-slice query A query applied to a particular state of a table or database. timestamp Of a row, either the period of validity or the period of presence of that row. Of a table, the table's timestamp column(s). TIMESTAMP An SQL-92 data type, with a default granularity of microsecond. Supported by IBM DB2 UDB and UniSQL, with a granularity of second. timestamp column The column(s) of the table denoting the timestamp. tracking log Records the past states of the monitored table. transaction time Of a fact, the time when the fact is current in the database and may be retrieved. This time is a period delimited by when the fact was inserted into the database and when it was modied or logically deleted. transaction time-invariant participation constraint A participation constraint that holds over the entire transaction-time period of the relationship. transaction time-invariant unique Attribute(s) that are unique for a particular entity or relationship over its entire transaction-time period. transaction time-slice A query or view that selects the snapshot state of a transaction-time table at a specied transaction time, or a valid-time state of a bitemporal table. transaction-time splitting A method of partitioning a region of a bitemporal time diagram into rectangles by inserting vertical splits, resulting in contiguous bands in transaction time. transaction-time state table One with facts timestamped with their transaction time. tropical year The time interval between two consecutive passages of the earth across a given point of its orbit. true day The time between two consecutive noons, 24 hours. true time The hour-angle of the sun starting from noon. user-dened time An uninterpreted datetime. Contrast with valid time and transaction time. vacuum Remove less desired information, for example, from an archival or history store. vacuuming criteria Additional predicates that characterize the rows to be purged from a temporal table. valid time Of a fact, when the fact was true in the modeled reality. valid time-slice A query or view that selects the snapshot state of a valid-time table at a specied valid time, or a transaction-time state of a bitemporal table. valid-time splitting A method of partitioning a region of a bitemporal time diagram into rectangles by inserting horizontal splits, resulting in contiguous bands in valid time. GLOSSARY valid-time state table 477 One that records the history of the modeled reality by timestamping facts with periods denoting when they were valid. valid-time support A row with an associated valid time, which is a value of the period data type. An SQL3 table is one in which each row is a row with valid-time support. value-equivalent Rows on the same schema with identical values for their nontimestamp columns. year-month interval An SQL-92 interval data type containing only the year and month elds. year 2000 problem A hardware or software bug arising from using just two digits to record the year. Y2K is the acronym for the year 2000 problem. Bibliography [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] Ahn, I., and R. T. Snodgrass. “Partitioned Storage Structures for Temporal Databases,” Information Systems 13(4):369–391, 1988. Allen, J. F. “Maintaining Knowledge about Temporal Intervals,” Communications of the ACM 26(11):832–843, 1983. Bair, J., M. Böhlen, C. S. Jensen, and R. T. Snodgrass. “Notions of Upward Compatibility of Temporal Query Languages,” Business Informatics (Wirtschafts Informatik) 39(1):25–34, 1997. Barnert, R., G. F. Knolmayer, and T. Myrach. Rules for Ensuring Referential Integrity in a Time-Extended Relational Model. Technical Report, University of Bern, Switzerland, 1996. Ben-Zvi, J. The Time Relational Model. Ph.D. dissertation, Computer Science Department, University of California at Los Angeles, 1982. Bernstein, A., V. Hadzilacos, and N. Goodman (eds.). Concurrency Control and Recovery in Database Systems. Addison-Wesley, Reading, MA, 1987. Bettini, C., C. E. Dyreson, W. S. Evans, R. T. Snodgrass, and X. S. Wang. “A Glossary of Time Granularity Concepts,” in [33], pp. 406–413, 1998. Bjork, L. A., Jr. “Generalized Audit Trail Requirements and Concepts for Data Base Applications,” IBM Systems Journal 14(3):229–245, 1975. Blaha, M., and W. Premerlani. Object-Oriented Modeling and Design for Database Applications. Prentice Hall, Upper Saddle River, NJ, 1998. Böhlen, M. H. The Temporal Deductive Database System ChronoLog. Ph.D. dissertation, Department Informatik, ETH Zurich, 1994. Böhlen, M. H. Valid Time Integrity Constraints. Technical Report 94–30, University of Arizona, Tucson, November, 1994. Böhlen, M. H., and C. S. Jensen. Seamless Integration of Time into SQL. Technical Report R-96-2049, Aalborg University, Aalborg, Denmark, December, 1996. Böhlen, M. H., C. S. Jensen, and R. T. Snodgrass. “Evaluating the Completeness of TSQL2,” in [25], pp. 153–174, 1995. 480 [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] BIBLIOGRAPHY Böhlen, M. H., and R. Marti. “On the Completeness of Temporal Database Query Languages,” in Proceedings of the First International Conference on Temporal Logic, pp. 283–300, July, 1994. Böhlen, M. H., R. T. Snodgrass, and M. D. Soo. “Coalescing in Temporal Databases,” in Proceedings of the International Conference on Very Large Databases, pp. 180–191, Mumbai (Bombay), India, September, 1996. Bourne, K. C. Year 2000 for Dummies. IDG Books Worldwide, Foster City, CA, 1997. Brackin, A. J. Clocks: Chronicling Time. Encyclopedia of Discovery and Invention, Lucent Books, 1991. Britannica Online. www.eb.com:180/cig-bin/g?DocF=micro/394/19.html Cannan, S. J. (ed.). Database Language SQL—Technical Corrigendum 3, ISO/IEC 9075:1992/Cor. 3:1998. Celko, J. “Regions, Runs, and Sequences,” Chapter 22 of SQL for Smarties: Advanced SQL Programming. Morgan Kaufmann, San Francisco, 1995. Celko, J. “Tooling Around,” DBMS Magazine 11(5):20–25, 1998. Chamberlin, D. Using the New DB2. Morgan Kaufmann, San Francisco, 1996. Clifford, J., C. E. Dyreson, T. Isakowitz, C. S. Jensen, and R. T. Snodgrass. “On the Semantics of `Now' in Databases,” ACM Transactions on Database Systems 22(2):171–214, 1997. Clifford, J., and T. Isakowitz. “On the Semantics of (Bi)temporal Variable Databases,” in Proceedings of the Fourth International Conference on Extending Database Technology, Cambridge, England, pp. 215–230, March, 1994. Clifford, J., and A. Tuzhilin (eds.). Recent Advances in Temporal Databases. Springer-Verlag, New York, 1995. Also Proceedings of the VLDB International Workshop on Temporal Databases. Dadam, P., V. Lum, and H. D. Werner. “Integration of Time Versions into a Relational Database System,” in Proceedings of the Conference on Very Large Databases, Singapore, pp. 509–522, 1984. Dershowitz, N., and E. M. Reingold. Calendrical Calculations. Cambridge University Press, Cambridge, 1997. Dyreson, C. E., and R. T. Snodgrass. “Timestamp Semantics and Representation,” Information Systems 18(3):143–166, 1993. Eisenberg, A., and J. Melton. “Standards in Practice,” ACM SIGMOD Record 27(3):53–58, 1998. Eisenberg, A., and J. Melton. “SQL:1999, Formerly Known as SQL3,” ACM SIGMOD Record 28(1):131–138, March, 1999. Electronics Industries Association. Recommended Practice for Line 21 Data Service. ANSI/EIA608-94, September, 1994. Ensor, D., and I. Stevenson. Oracle Design. O'Reilly & Associates, Sebastopol, CA, 1997. Etzion, O., S. Jajodia, and S. M. Sripada (eds.). Temporal Databases: Research and Practice. Springer-Verlag, New York, 1998. Fraser, J. Time: The Familiar Stranger. Tempus Books, Redmond, WA, 1987. Gould, S. J. Questioning the Millennium: A Rationalist's Guide to a Precisely Arbitrary Countdown. Harmony Books, New York, 1997. BIBLIOGRAPHY [36] [37] [38] [39] [40] [41] [42] [43] [44] [45] [46] [47] [48] [49] [50] [51] [52] [53] [54] 481 Gray, J., and A. Reuter. Transaction Processing: Concepts and Techniques. Morgan Kaufmann, San Francisco, 1993. Gregersen, H., and C. S. Jensen. Conceptual Modeling of Time-Varying Information. T IME C ENTER Technical Report TR-35, September, 1998. Gregersen, H., and C. S. Jensen. “Temporal Entity-Relationship Models—A Survey” to appear in IEEE Transactions on Knowledge and Data Engineering, 1999. Gregersen, H., L. Mark, and C. S. Jensen. Mapping Temporal ER Diagrams to Relational Schemas. T IME C ENTER Technical Report TR-39, December, 1998. Hofstadter, D. R. Gödel, Escher, Bach: An External Golden Braid. Vintage Books, New York, 1979. “How to Buy a Wristwatch,” Consumer Reports, 62(11):6, 1997. Howse, D. Greenwich Time and the Discovery of the Longitude. Oxford University Press, Oxford, 1980. ISO. Data Elements and Interchange Formats—Information Interchange—Representation of Dates and Times. ISO 8601:1988. ISO. Database language SQL. ISO/IEC 9075:1992. ANSI X3.135-1992. ISO. Database language SQL—Part 4: Persistent Stored Modules (SQL/PSM). ISO/IEC 90754:1995, ANSI/ISO/IEC 9075-4:1995. Jackson, M. A. System Development. Prentice Hall International Series in Computer Science. Prentice Hall, Englewood Cliffs, NJ, 1983. Jensen, C. S. “Vacuuming,” Chapter 23 of [91], pp. 451–462, 1995. Jensen, C. S., J. Clifford, R. Elmasri, S. K. Gadia, P. Hayes, and S. Jajodia (eds.). “A Glossary of Temporal Database Concepts,” ACM SIGMOD Record 23(1):52–64, 1994. Jensen, C. S., and C. E. Dyreson (eds.), M. Böhlen, J. Clifford, R. Elmasri, S. K. Gadia, F. Grandi, P. Hayes, S. Jajodia, W. Käfer, N. Kline, N. Lorentzos, Y. Mitsopoulos, A. Montanari, D. Nonen, E. Peressi, B. Pernici, J. F. Roddick, N. L. Sarda, M. R. Scalas, A. Segev, R. T. Snodgrass, M. D. Soo, A. Tansel, R. Tiberio, and G. Wiederhold. “A Consensus Glossary of Temporal Database Concepts—February 1998 Version,” in [33], pp. 367–413, 1998. Jensen, C. S., and L. Mark. A Framework for Vacuuming Temporal Databases. Technical Report CS-TR-2516, UMIACS-TR-90-105, Department of Computer Science, University of Maryland, College Park, MD, August, 1990. Jensen, C. S., and L. Mark. “Differential Query Processing in Transaction-Time Databases,” Chapter 19 of [102], pp. 457–492, 1994. Jensen, C. S., L. Mark, and N. Roussopoulos. “Incremental Implementation Model for Relational Databases with Transaction Time,” IEEE Transactions on Knowledge and Data Engineering 3(4):461–473, 1991. Jensen, C. S., and R. T. Snodgrass. “Temporal Specialization,” in Proceedings of the International Conference on Data Engineering, Tempe, Arizona, pp. 594–603, February, 1992. Jensen, C. S., and R. T. Snodgrass. “Temporal Specialization and Generalization,” IEEE Transactions on Knowledge and Data Engineering 6(6):954–974, 1994. 482 [55] [56] [57] [58] [59] [60] [61] [62] [63] [64] [65] [66] [67] [68] [69] [70] [71] [72] BIBLIOGRAPHY Jensen, C. S., and R. T. Snodgrass. “Semantics of Time-Varying Information,” Information Systems 21(4):311–352, 1996. Jensen, C. S., and R. T. Snodgrass. “Temporal Data Management,” IEEE Transactions on Knowledge and Data Engineering, 11(1):36–44, January/February, 1999. Jensen, C. S., and R. T. Snodgrass. “Temporally Enhanced Database Design,” to appear in Object-Oriented Data Modeling, M. P. Papazoglou, S. Spaccapietra, and Z. Tari (eds.), MIT Press, Cambridge, MA, 1999. Jespersen, J., and J. Fitz-Randolph. From Sundials to Atomic Clocks: Understanding Time and Frequency. Dover, Mineola, NY, 1982. Jones, C. “Bad Days for Software,” IEEE Spectrum 35(9):47–52, 1998. Katz, R. H., and T. Lehman. “Database Support for Versions and Alternatives of Large Design Files,” IEEE Transactions on Software Engineering 10(2):191–200, 1984. Kimball, K. A. The DATA System. Master's thesis, University of Pennsylvania, 1978. Klopprogge, M. R. “TERM: An Approach to Include the Time Dimension in the EntityRelationship Mode,” in Proceedings of the Second International Conference on the Entity Relationship Approach, pp. 477–512, October, 1981. Koch, G., and K. Loney. Oracle: The Complete Reference. Osborne McGraw Hill, Berkeley, CA, 1997. Kuhn, T. S. The Structure of Scientic Revolutions. University of Chicago Press, third edition, 1996. Landes, D. S. Revolution in Time: Clocks and the Making of the Modern World. Barnes & Noble Books, New York, 1998. Leung, T. Y. C., and H. Pirahesh. “Querying Historical Data in IBM DB2 C/S DBMS Using Recursive SQL,” in [25], pp. 315–331, 1995. Lum, V., P. Dadam, R. Erbe, J. Guenauer, P. Pistor, G. Walch, H. D. Werner, and J. Woodll. “Designing DBMS Support for the Temporal Dimension,” in Proceedings of the ACM International Conference on Management of Data, Boston, MA, pp. 115–130, 1984. Lum, V., P. Dadam, R. Erbe, J. Guenauer, P. Pistor, G. Walch, H. D. Werner, and J. Woodll. “Design of an Integrated DBMS to Support Advanced Applications,” in Proceedings Conference on Foundations of Data Organization, Kyoto, Japan, 1985. Melton, J. (ed.). (ISO Working Draft) Temporal (SQL/Temporal). American National Standards Institute X3H2-97-135, International Organization for Standardization DBL:LGW-013, April, 1997. Melton, J. Understanding SQL's Stored Procedures: A Complete Guide to SQL/PSM. Morgan Kaufmann, San Francisco, 1998. Melton, J., and A. R. Simon. Understanding the New SQL: A Complete Guide. Morgan Kaufmann, San Francisco, 1993. Myrach, T., G. F. Knolmayer, and R. Barnert. “On Ensuring Keys and Referential Integrity in the Temporal Database Language TSQL2,” in H.-M. Haav and B. Thalheim (eds.). Databases and Information Systems, Proceedings of the Second International Baltic Workshop, Tallinn, June BIBLIOGRAPHY [73] [74] [75] [76] [77] [78] [79] [80] [81] [82] [83] [84] [85] [86] [87] [88] [89] [90] [91] [92] 483 12–14, Volume I: Research Track, Tampere University of Technology Press, pp. 171–181, 1996. National Institute of Standards and Technology. Federal Information Processing Standard 127-2, Database Language (SQL), December 3, 1993. ftp://speckle.ncsl.nist.gov/vpl/sqlintro.htm, June 18, 1998. Navathe, S. B., and R. Ahmed. “A Temporal Relational Model and a Query Language,” Information Sciences 49:147–175, 1989. Neumann, P. G. “Y2K Update,” Communications of the ACM 40(9):128, 1998. Özsoyoglu, G., and R. T. Snodgrass. “Temporal and Real-Time Databases: A Survey,” IEEE Transactions on Knowledge and Data Engineering 7(4):513–532, 1995. Pais, A. Niels Bohr's Times, in Physics, Philosophy, and Polity. Clarendon Press, Oxford, 1991. Palmer, J. D. “Time, Tide and the Living Clocks of Marine Organisms,” American Scientist 84(6):570–578, 1996. Quinn, T. J. “The BIPM and the Accurate Measurement of Time,” Proceedings of the IEEE, 79(9):894–906, 1991. Rohr, R. R. J. Sundials: History, Theory, and Practice. Dover Publications, Mineola, NY, 1970. Rossum, G. D.-V. History of the Hour: Clocks and Modern Temporal Orders. The University of Chicago Press, Chicago, 1996. Rozenshtein, D., A. Abramovich, and E. Birger. “Loop-Free SQL Solutions for Finding Continuous Regions,” SQL Forum 2(6), November–December, 1993. Rudolph, J. S. Make Your Own Working Paper Clock. Harper Perennial, New York, 1983. Sarda, N. L. “Extensions to SQL for Historical Databases,” IEEE Transactions on Knowledge and Data Engineering 2(2):220–230, 1990. Skyt, J., and C. S. Jensen. Vacuuming Temporal Databases. T IME C ENTER Technical Report TR-32, September, 1998. Snodgrass, R. T. “The Temporal Query Language TQuel,” ACM Transactions on Database Systems 12(2):247–298, 1987. Snodgrass, R. T. “An Overview of TQuel,” Chapter 6 of [102], pp. 141–182, 1994. Snodgrass, R. T. “Managing Temporal Data—A Five-Part Series,” T EMP IS Technical Report TR28, September, 1998. www.cs.arizona.edu/people/rts/DBPD/. Snodgrass, R. T., and I. Ahn. “A Taxonomy of Time in Databases,” in Proceedings of the ACMSIGMOD International Conference on Management of Data, Austin, TX, pp. 236–246, May, 1985. Snodgrass, R. T., and I. Ahn. “Temporal Databases,” IEEE Computer 19(9):35–42, 1986. Snodgrass, R. T. (ed.). I. Ahn, G. Ariav, D. S. Batory, J. Clifford, C. E. Dyreson, R. Elmasri, F. Grandi, C. S. Jensen, W. Käfer, N. Kline, K. Kulkanri, T. Y. C. Leung, N. Lorentzos, J. F. Roddick, A. Segev, M. D. Soo, and S. M. Sripada. The TSQL2 Temporal Query Language. Kluwer Academic, Norwell, MA, 1995. Snodgrass, R. T., M. H. Böhlen, C. S. Jensen, and A. Steiner. Adding Valid Time to SQL/Temporal. Change proposal, ANSI X3H2-96-501r1, ISO/IEC JTC1/SC21/WG3 DBL MCI-146r2, November, 1996. ftp://ftp.cs.arizona.edu/tsql/tsql2/sql3/mad146.pdf. 484 [93] [94] [95] [96] [97] [98] [99] [100] [101] [102] [103] [104] [105] [106] [107] BIBLIOGRAPHY Snodgrass, R. T., M. H. Böhlen, C. S. Jensen, and A. Steiner. Adding Transaction Time to SQL/Temporal. Change proposal, ANSI X3H2-96-502r2, ISO/IEC JTC 1/SC 21/WG 3 DBLMAD-147r2, November, 1996. ftp://ftp.cs.arizona.edu/tsql/tsql2/sql3/mad147.pdf. Snodgrass, R. T., M. H. Böhlen, C. S. Jensen, and A. Steiner. “Transitioning Temporal Support in TSQL2 to SQL3,” in [33], pp. 150–194, 1998. Sobel, D. Longitude. Walker and Company, New York, 1995. Sobel, D., and W. J. H. Andrewes. The Illustrated Longitude. Walker and Company, New York, 1998. Soo, M. D., R. T. Snodgrass, and C. S. Jensen. “Efcient Evaluation of the Valid-Time Natural Join,” in Proceedings of the International Conference on Data Engineering, Houston, TX, pp. 282– 292, February, 1994. Steele, G. (ed.). The Hacker's Dictionary. Harper and Row, New York, 1983. Stoneman, M. Easy-to-Make Wooden Sundials: Instructions and Plans for Five Projects. Dover, Mineola, NY, 1981. Stork, D. G. (ed.). HAL's Legacy: 2001's Computer as Dream and Reality. MIT Press, Cambridge, MA, 1997. Sykes, J. M. Time Zones—A Tidying. ISO/IEC JTC 1/SC 21/WG 3 DBL MCI-068, April, 1996. Tansel, A., J. Clifford, S. K. Gadia, S. Jajodia, A. Segev, and R. T. Snodgrass (eds.). Temporal Databases: Theory, Design, and Implementation. Database Systems and Applications Series. Benjamin/Cummings, Redwood City, CA, 1994. Tsotras, V. J., and X. S. Wang. “Temporal Databases,” in Encyclopedia of Electrical and Electronics Engineering, John Wiley and Sons, New York, 1999. Woodward, P. My Own Right Time: An Exploration of Clockwork Design. Oxford University Press, Oxford, 1995. Wu, Y., S. Jajodia, and X. S. Wang. “Temporal Database Bibliography Update,” in [33], pp. 338–366, 1998. Yourdon, E. Managing the System Life Cycle. Yourdon Press, 1982. Zaniolo, C., S. Ceri, C. Faloutsos, R. T. Snodgrass, V. S. Subrahmanian, and R. Zicari. Advanced Database Systems. Morgan Kaufmann, San Francisco, 1997. Author Index Abramovich, A., 175, 483 Ahmed, R., xxi, 398, 483 Ahn, I., 217, 250, 479, 483 Allen, J. F., 108, 479 Andrewes, W. J. H., 398, 484 Ariav, G., 217, 483 Bair, J., xxi, xxii, 174, 466, 479 Barnert, R., 141, 217, 479, 483 Batory, D. S., 217, 483 Ben-Zvi, J., 216, 274, 479 Bernstein, S., 250, 479 Bettini, C., 471, 479 Birger, E., 175, 483 Bjork, L. A., Jr., 251, 479 Blaha, M., 340, 479 Böhlen, M. H., xxii, 23, 141, 174, 175, 341, 459, 460, 466, 467, 471, 479–481, 484 Bourne, K. C., 86, 480 Brackin, A. J., 480 Cannan, S. J., 8, 78, 85, 480 Carpenter, M. C., xxiii Celko, J., 175, 480 Ceri, S., 23, 484 Chamberlin, D., 251, 480 Chapman, B. N., xxiii, 30, 402 Clark, A. C., 87 Clifford, J., 23, 141, 216, 217, 250, 340, 471, 480, 481, 483, 484 Dadam, P., 274, 480, 482 DeMent, I., xxiii Denny, S., 224 Dershowitz, N., 87, 480 Dickinson, E., 28 Dyreson, C. E., 23, 87, 141, 217, 340, 471, 479–481, 483 Eisenberg, A., 9, 87, 480 Elmasri, R., 23, 217, 250, 471, 481, 483 Ensor, D., 140, 174, 480 Erbe, R., 274, 482 Erdrich, L., xxiii Etzion, O., 480 Evans, W. S., 471, 479 Faloutsos, C., 23, 484 Fitz-Randolph, J., 12, 341, 482 Fraser, J., 251, 480 Gadia, S. K., 23, 216, 250, 471, 481, 484 Goodman, N., 250, 479 Gould, S. J., xxiii, 6, 9, 37, 63, 481 Grandi, F., 23, 217, 471, 481, 483 Gray, J., ix, xxi, 250, 481 Gregersen, H., xxii, 340, 398, 481 Grifth, N., xxiii Guenauer, J., 274, 482 Haav, H.-M., 483 Hadzilacos, V., 250, 479 Hare, K., 9 Hayes, P., 23, 250, 471, 481 Hofstadter, D. R., 23, 481 House, D., 87, 481 Isakowitz, T., 141, 217, 340, 480 Jackson, M. A., 466, 481 Jajodia, S., 23, 216, 250, 471, 480, 481, 484 Jensen, C. S., xxi, xxii, 23, 141, 174, 175, 217, 250, 251, 274, 340, 398, 459, 466, 467, 471, 479–484 Jones, C., 87, 482 Käfer, W., 23, 217, 471, 481, 483 Kaplansky, L., xxiii Katz, R. H., 274, 482 Kimball, K. A., 251, 482 Kline, N., xxi, 23, 217, 471, 481, 483 Klopprogge, M. R., 398, 482 Knolmayer, G. F., 141, 217, 479, 483 Koch, G., 87, 482 Kuhn, T. S., xviii, 482 Kulkarni, K., 217, 483 Landes, D. S., 141, 217, 398, 482 Langewiesche, W., xxiii Lehman, T., 274, 482 Leung, T. Y. C., xxi, 175, 217, 251, 482, 483 Lloyd, B., 402 Loney, K., 87, 482 Lorentzos, N., 23, 217, 471, 481, 483 Lum, V., 274, 480, 482 Mark, L., xxii, 251, 274, 340, 398, 481 Marti, R., 466, 480 Melton, J., i, xxi, 8, 9, 68, 87, 174, 466–467, 480, 482 Mitsopoulos, Y., 23, 471, 481 Montanari, A., 23, 471, 481 Moore, A., xxiii Myrach, T., 141, 217, 479, 483 Navathe, S. B., 398, 483 Neumann, P. G., 87, 483 Nonen, D., 23, 471, 481 Özsoyoglu, G., 23, 483 486 AUTHOR INDEX Pais, A., 9, 483 Palmer, J. D., 251, 483 Peressi, E., 23, 471, 481 Pernici, B., 23, 471, 481 Pirahesh, H., 175, 251, 482 Pistor, P., 274, 482 Premerlani, W., 340, 479 Querry, R., xxiii Quindlen, A., xxiii Quinn, T. J., 87, 483 Reingold, E. M., 87, 480 Reuter, A., 250, 481 Roddick, J. F., 23, 217, 471, 481, 483 Rohr, R. R. J., 9, 149, 483 Romley, R., 175 Rossum, G. D.-v., 341, 483 Roussopoulos, N., 251, 481 Rozenshtein, D., 175, 483 Rudolph, J. S., 483 Sarda, N. L., 23, 216, 471, 481, 483 Scalas, M. R., 23, 471, 481 Segev, A., 23, 216, 217, 471, 481, 483, 484 Simon, A. R., 8, 174, 482 Skyt, J., xxii, 274, 483 Snodgrass, R. T., 23, 87, 141, 174, 175, 216, 217, 250, 340, 398, 459, 466, 471, 479–484 Sobel, D., xxiii, 398, 484 Soo, M. D., xxii, 23, 175, 217, 471, 480–481, 483, 484 Sripada, S. M., 217, 480, 483 Steele, G., 341, 484 Steiner, A., xxii, 175, 458, 459, 466, 467, 484 Stevenson, I., 140, 174, 480 Stoneman, M., 175, 484 Stork, D. G., 87, 484 Subrahmanian, V. S., 23, 484 Sykes, J. M., 80, 85, 484 Tansel, A., 23, 216, 471, 481, 484 Thalheim, B., 483 Tiberio, R., 23, 471, 481 Tsotras, V. J., 23, 484 Tuzhilin, A., 480 Walch, G., 274, 482 Wang, X. S., 23, 471, 479, 484 Werner, H. D., 274, 480, 482 Wiederhold, G., 23, 471, 481 Williams, D., xxiii Williams, L., xxiii Woodll, J., 274, 482 Woodward, P., 341, 484 Wu, Y., 23, 484 Yourdon, E., 466, 484 Zaniolo, C., 23, 484 Zicari, R., 23, 484 Subject Index A . D ., 27, 75, 471 A . H . (anno Hegirae), 471 A . M . (annus mundi), 471 A . U . C . (ab urbe condita), 75, 471 ADD PARTITIONING clause, 427 after-image, 218, 235, 471 backlogs with, 236 reconstruction algorithm with, 237 reconstruction and, 236 from transaction-time state table, 261, 424 using, 235–239 See also before-image Allen relations, 108 ALTER TABLE statement, 427 append-only table, 285, 471 archival store, 263–265, 471 for auditing changes, 269 before-image, 333 contents, 268, 333, 334 entity vacuuming, 269 maintained via triggers, 335 maintaining, 332 narrowing, 336 past state reconstruction with, 265 reducing, 269 rows in, 338 vacuuming, 270, 338 vacuuming based on combination of criteria, 271 AS TRANSACTIONTIME clause, 439 as-of date, 224, 471 as-of time, 232, 242 assertions, 132 checking, 185 IBM DB2 UDB and, 132 Microsoft Access and, 133 Microsoft SQL Server and, 135 nonsequenced valid-time, 281 Oracle8 Server and, 137 Sybase SQLServer and, 136 UniSQL and, 138 atom, 359, 471 atomic clocks, 382, 402 atomic (TAI) second, 402, 471 See also seconds ATSQL, 458–459 attributes, 347 entity type key, 347 key, 351 temporal support and precision, 361 user-dened time, 358–360, 438 valid time, 350–353, 361, 438 See also ER schema auditing query, 261, 426 B . C ., 27, 75, 471 B . C . E ., 75, 471 B . P., 75, 472 Babylonian sundials. See sundials Babylonic hours, 179 backlogs, 233–235, 471 accessing, 251 with after-image, 236 converting state table to, 262 converting, to transactiontime state table, 237–238 extract, from transaction-time state table, 262, 424–425 fully general, 362 modications on, 394 restricted, 362 sample, 241 transaction-time table implemented as, 367 See also tracking logs barycentric coordinate (TCB) second, 78 See also seconds barycentric dynamical (TDB) second, 78 See also seconds before-image, 218, 235, 471 in archival store, 333 from transaction-time state table, 261, 424 See also after-image beginning instant, 93 Berossos hemispherium, 7 See also sundials BETWEEN predicate, 35, 92 Biel Mean Time (BMT), 437, 472 bitemporal query, 276, 307–323, 339 combinations, 320 common, 320 types of, 312 See also queries bitemporal table partitioning, 330–337 See also temporal partitioning bitemporal table, 20, 276–341, 427, 471 append-only, 285 component sizes, 337 corresponding time diagram, 330 current deletions, 292–294 current modications, 283–294 current update, 284–291 deletions, 292–294 expressed as view, 333 feed yard case study, 20–21 foreign keys, 279, 374 implementation, 278, 339 insertions, 283–284 488 SUBJECT INDEX bitemporal table (continued) integrity constraints, 323–329, 339–340 modications, 276, 282–307, 339, 387 nonsequenced modications, 305–307 nontemporal modication on, 286 overview, 276 primary keys, 366–367 query spectrum, 312–323 reconstituting, as view, 335–336 referential integrity constraints, 329 reinstating, as view, 334, 336 sequenced modications, 294–305 SQL3, 427–436 state/event, 335 summary, 339–340 temporal partitioning, 329–337, 340 time-slice query, 307–312 timestamp columns, 279 translating modications on, 282 update, 284–291 usefulness of, 276 vacuuming, 337–339 valid time and, 285 valid time-slice of, 309 valid-time sequenced primary key, 281 valid-time state capture, 279 bitemporal time diagram, 283, 472 corresponding bitemporal table, 330 horizontal slice, 309 illustrated, 284 introduction of, 340 regions, 287 update impact on, 284, 285 variation, 340 vertical slice, 307 See also bitemporal table bitemporal time-slice, 311–312, 429, 472 current, 312 illustrated, 312 input, 311 BKP table, 362, 376 contiguous primary key, 380 nonsequenced/current foreign key for, 368, 369–370 primary key, 365 transaction-time current, 369, 372–373, 396–397 BMT (Biel Mean Time), 437, 472 Böhlen's classes of integrity constraints, 341 Bulova Accutron, 364 C . E ., 75, 472 calendars, 6 Gregorian, 37, 75, 76 Hijri, 49 Julian, 75 proleptic Gregorian calendar, 76, 474 candidate keys, 115 CASE expression, 152, 153, 298 CAST constructor, 40, 83 CD-ROM materials, 8 instants/intervals, 84 modifying state table, 215 periods, 108 querying, 173 SQL3, 459–460 state table denition, 138 Synchrony, 460 temporal database design, 396 TIGER, 460 TIMEDB, 460 tracking log, 247–248 transaction-time state table, 272 character constructors, 97 CHARACTER type as cast source for year-month intervals, 40 converted to datetime value, 38 chronology, 472 circadian clocks, 224 clepsydra, 115, 472 See also water clocks clocks accuracy of, 405, 409, 414 atomic, 382, 402 circadian, 224 clepsydra, 115, 472 components, 281 crown wheel, 201 crystal, 376 hairspring, 288 Harrison's marine, 351, 398 hour hand, 405 minute hand, 409 oscillator, 281 pendulum, 257, 281, 288 periodic, 281 resonator, 281 second hand, 414, 418, 423 transmission, 281 water, 115, 131, 181 closed-closed representation, 89 for period of validity, 119 closed-open representation, 89–90, 92, 358 COALESCE expression, 214 coalesced table, 161, 162 coalescing, 159–162, 174, 472 entirely in SQL, 165–166 entirely in SQL using COUNT, 166–167 IBM DB2 UDB, 169–170 reducing number of rows and, 160 variants, 160 via cursor, 167–168 while removing duplicates, 161, 162–169 while retaining duplicates, 161, 169 comparable values, 34, 472 complex modications, 198–205 converting, 198 current, 199–200 sequenced, 200–205 SQL3, 418–419 See also modications composite sort key, 148 conceptual design, 345–355 nontemporal ER schema, 345–348 temporal annotations, 348–355 See also temporal database design conceptual keys, 363 concurrency control system, 240 conformance testing, NSTL, 85–86 constraints attributes, 131–132 DEFERRABLE, 131 DEFERRABLE INITIALLY DEFERRED, 132, 140 expressed as nontemporal table, 408 foreign key, 327, 368 integrity, 323–329 key, 378 nontemporal, 326 participation, 348, 378–379 primary key, 117, 121–122, 124 referential integrity, 110, 126–131 types of, 139 uniqueness, 122, 124, 139, 375, 378 SUBJECT INDEX constructors, 36–42 CAST, 40, 83 character, 97 datetime, 37–39, 93–94 IBM DB2 UDB, 45–46 Informix–Universal Server, 47–48 interval, 39–40, 94–95 Microsoft Access 2000, 51–52 Microsoft SQL Server, 53–54 Oracle8 Server, 60–61 period, 95–97 periods and, 93–97 SQL3, 405–406 Sybase SQLServer, 56–57 temporal, 36 UniSQL, 64–65 CONTAINS predicate, 418, 439 contiguous histories, 129, 130 Coordinated Universal Time (UTC), 28, 77 See also UTC; seconds CREATE TRIGGER statement, 245, 246 crown wheel, 201 crystal clocks, 376 current deletions, 183–184 on bitemporal table, 291–294 cases, 190, 191 in general case, 183–184, 190 logical, 387 nonpartitioned, 209 on partitioned table, 209–210 period of applicability, 191 period of validity, 191 process, 190 in restricted case, 183 result of, 294 splitting into rectangles, 292 SQL3, 425 See also current modications; deletions current duplicates, 121, 472 assuming no further data, 123–124 removing, 159 removing (SQL3), 415 See also duplicates current insertions, 178–183, 472 on bitemporal table, 283–284 coding, in SQL, 387 ensuring referential integrity with, 180 ensuring uniqueness with, 179 in general case, 181 on partitioned table, 208 results, 291 specication, 178 SQL3, 425 See also current modications; insertions current integrity constraints, 123, 325, 472 current joins, 144, 472 current key constraint, 254 current modications, 16, 18, 19, 177–187, 444–445, 472 bitemporal, 283–294 complex, 199–200 deletions, 183–184 insertions, 178–183 mentioning other table, 199–200 on monitored table, 229 SQL3, 416–417 SQL3 bitemporal table, 435, 436 on transaction-time state table, 257 update, 184–187 See also modications current query, 142 bitemporal, 314–320 conventional query conversion to, 158 converting, 174 expressed against monitored table, 268 on tracking logs, 226, 250 temporal partitioning and, 206 temporally upward compatible, 174 time-slice, 145 transaction-time state table, 259 valid time-slice, 145 WHERE clause and, 383 See also queries current referential integrity constraints, 127–128, 130 current state extracting, 143–145 queries on, 265 current store, 206, 263–265, 330, 472 contents, 268 current/current query applied to, 331 disadvantage, 331 maintaining, 332 partitioned table, 208 tripartitioned state table, 266 truncated, 267 current time-slice query, 145, 472 current update, 176, 184–187, 472 on bitemporal table, 284–291 cases, 157, 187 of future row, 289 489 in general case, 186–187 logical, 388 partitioned table, 209 with period of validity, 187 in restricted case, 184–185 SQL3, 425 on transaction-time table, 394 See also current modications; updates current valid time-slice query, 145, 472 current/current constraint, 326, 369 current/current query, 320, 321 applied to current store, 331 efciency/ease of, 332 current/nonsequenced constraint, 326 current/nonsequenced query, 322 CURRENT DATE, 206 cursor-based coalescing, 167–168 Microsoft SQL Server, 171–172 See also coalescing date duration, 43 DATE type, 27, 28, 79, 401, 470, 472 B . C . E . and, 27 converted to datetime value, 39 IBM DB2 UDB, 68 Informix, 69 length, 27 Oracle8 Server, 73 year digits, 67 dates as-of, 224 coalescing in SQL and, 165 end, 120 literals, 27 NULL, 120 Oracle8 Server, 58–59 parsing of, 71 time-dependent assumptions, 66 datetime constructors, 37–39 IBM DB2 UDB equivalent, 45 Informix–Universal Server, 47 list of, 37–38 Microsoft Access, 51 Microsoft SQL Server, 53–54 Oracle8 Server, 60–61 periods and, 93–94 SQL3, 405 Sybase SQLServer, 56–57 types converted to, 38–39 UniSQL, 64 See also constructors 490 SUBJECT INDEX DATETIME type, 44, 472 Informix, 69 Microsoft SQL Server, 72 datetimes, 27, 74–80, 472 closed-open pair of, 92 containing time elds, 78 delimiting, 90 eld extraction from, 41 period comparison with, 92 day lunar, 224, 473 sidereal, 95, 475 solar, 95, 475 true, 95, 476 day-time intervals, 31, 32–33, 84, 472 casts resulting in, 40 elds, 32 leap seconds and, 81 literals, 33 types, 32–33 See also intervals DB2 Universal Database. See IBM DB2 UDB DECIMAL type, 43 decomposition precision, 361 temporal support, 362 degenerate entity type, 380, 472 degenerate specialization, 380, 472 DELETE statement, 176, 254, 416 states becoming true in future and, 184 See also UPDATE statement deletions on bitemporal table, 291–294, 299–302 current, 183–184, 258, 291–294 duplicates and, 184 monitored table, 269 nonsequenced, 306 nontemporal, 190, 215 period of applicability and, 417 projection, 229 sequenced, 190–193 SQL3, 425 transaction-time state table, 258 See also modications diffraction patterns, 1–2 digital perception of time, 217 dirty read, 242, 243, 472 duplicates current, 121, 123, 159 deletions and, 184 elimination, easy, 159 elimination (SQL3), 415–416 nonsequenced, 122, 159 period of applicability and, 188, 190 prevent, in INCUMBENTS table, 409 retaining, while coalescing, 160 sequenced, 121, 124 sequenced join, eliminating, 158–169 table containing, 121, 160 durations, 43 computing, 94 date, 43 entity lifespan, 364 instants and, 75 labeled, 43, 473 time, 43 timestamp, 43 valid-time, 306 EMPLOYEES table, 207 END DATE, 25, 159 ending instant, 93 entity lifespan, 348–349, 360–361 duration, 364 recorded, 364–365 SQL3, 438 entity types classifying, 379 degenerate, 380 implied lifespan, 349 instantaneous, 363 instantaneous and valid-time instant is recorded, 364 key, 378 key attributes, 347 lifespan with duration, and lifespan is recorded, 364–365 nontemporal, 474 postactive, 380 primary keys, 364 strong, 345 time-varying key association with, 351–353 transaction-time extent and, 354 valid time and, 349 weak, 345 See also relationship types entity vacuuming, 269, 472 archival store, 269 See also vacuuming ephemeris second, 402, 472 See also seconds equality predicates, 33–34 on periods, 91 types of, 33 See also predicates equation of time, 149, 473 equinoctial day, 115, 473 ER schema, 345–348 attributes, 347 entity type key attributes, 347 illustrated, 346 participation constraints, 348 relationship types, 347–348 strong entity types, 345 weak entity types, 345 See also feed yard case study escape wheel, 6 escapements, 6, 201, 473 tasks, 201 events, 74, 473 instantaneous, 349 EXCEPT statement, 175, 414 EXPAND operator, 455, 456, 457 EXPANDING clause, 456–457 extracting backlog from transaction-time state table, 262, 424–425 current state, 143–145 prior states, 145, 223–225 states (SQL3), 412 feed yard case study, 11–23, 342–398 benets, 382–383 bitemporal table, 20–21 ER schema, 345–348 gender transitions, 16 LOT bitemporal table, 20 LOT table, 16, 17, 20 LOT CONTAINS table, 19 LOT LOC table, 13 modications, 444–446 queries, 13–14, 15, 443–444 temporal annotations, 348–355 temporal relational schema, 437–442 transaction-time state table, 18–20 valid-time state table, 12–18 FINDER data model, 25–26 dates, 25 duration data, 26 Fac Daily Prod table, 25 intervals, 30 periods, 89 Seis Survey Hdr table, 30 Stage Flowback table, 30 Well Core Hdr table, 26 Well Log Service table, 30 Well Test Period table, 30 SUBJECT INDEX first instant function, 153, 170–171 foreign key constraints nontemporal referenced table and, 368 sequenced/current, 327 foreign keys, 126 bitemporal table, 279, 374 current/current, 372 nonsequenced/current, 368, 369–370, 370–371 sequenced, 128, 134 sequenced/current, 370–371, 373–374 transaction-time current, 369, 372–373, 396–397 valid-time sequenced, 374 violation, 193 FROM clause, 5, 145 FRS (Financial Records System), 111 fully general relationship type, 379, 473 future query, 226 gaps lling, 180, 182, 188 sequenced deletion, 193 See also modications geocentric coordinate (TCG) second, 78 See also seconds gnomonics, 7, 473 gnomon's shadow, 181 granularities, 74, 473 temporal, 12 timestamp, 427 valid time, 332 granules, 31, 473 GREATEST function, 322 Greenwich Mean Time (G.M.T.), 29 Gregorian calendar, 37, 75, 76 adoption of, 84 proleptic, 76, 474 H-4 (fourth Harrison), 351 hairspring, 288 heliochronometer, 31, 473 hemicyclium, 7, 473 hemispherium, 7, 473 Hijri calendar, 49 historical table, 23 history store, 332, 473 future valid times in, 332 maintaining, 332 rectangles, 332 size, 338 timestamp columns, 332 transaction-time current query applied to, 334 See also bitemporal table horology, 473 hours, 22, 473 sidereal, 402 IBM DB2 UDB, 8 assertions and, 132 CD-ROM materials, 84, 108, 138, 173, 215, 247 coalescing with duplicate elimination, 169–170 DATE, TIME, TIMESTAMP type support, 43 datetime constructors, 45 duration support, 43 implementation considerations, 83 interval constructors, 46 literals, 45 modifying state table and, 213 other operators, 46 period operations in, 97, 98–99 predicates, 45 prevent value-equivalent rows, 132 recursive query, 169 sequenced primary key in, 133 SQL-92 operations in, 44, 45–46 tracking logs, 244–245 triggers, 244 types, 45 year 2000 problem and, 68–69 implied century rule, 66 INCUMBENTS.SSN, 125–126 current unique, 126 nonsequenced unique, 125 sequenced unique, 125 INCUMBENTS table, 112 adding period timestamp to, 114 arbitrary modications, 186 coalesce, while removing duplicates, 162–168 coalesce, while removing duplicates (in Microsoft Server), 171–172 current state, 144 excerpts, 115, 147, 178 partitioning, 207 prevent current duplicates in, 123 prevent duplicates in, 409 prevent nonsequenced duplicates in, 123 491 prevent sequenced duplicates in, 124, 409 prevent value-equivalent rows in, 122 prevent value-equivalent rows in (DB2 UDB), 132 primary key, 117 remove duplicates from, 159 remove value-equivalent rows from, 159 sequenced join applied to, 151 sequenced primary key, 118, 119, 408 sequenced primary key, in DB2 UDB, 133 sequenced sort, on position code, 148 temporal partitioning of, 419–420 valid-time support, 408 See also University Information System (UIS) inequality predicates on periods, 93 sequenced join, 150 See also predicates Informix–Universal Server, 8, 44–48 CD-ROM materials, 84, 108 DATE type, 69 datetime constructors, 47 DATETIME type, 44, 69 first instant support, 170–171 formatting/converting date utilities, 44 instant type support, 44 interval constructors, 48 INTERVAL type, 44–46 last instant support, 170–171 literals, 47 other constructors, 48 partial interval support, 43 period operations in, 97, 100 predicates, 47 SQL-92 operations in, 47–48 types, 47 year 2000 compliance denition, 69 year 2000 problem and, 69–71 Ingres, 84, 108 INSERT statement, 176, 254 on bitemporal table, 289, 290, 293 sequenced update, 195 sequenced update mentioning other table, 205 492 SUBJECT INDEX insertions arbitrary, 232 on bitemporal table, 283–284, 295–299 current, 178–183, 257–258, 283–284 permitting, 230–233 projection, 229 in referencing table, 179 sequenced, 188–190 SQL3, 425 on tracking log, 230–233, 248 on transaction-time state table, 257–258 See also modications instant extractors, 93 instants, 3, 26–29, 84, 473 absolute nature of, 30 adding intervals to, 30 beginning, 93 calendar independence, 75 DATE, 12 distance between, 30 duration and, 75 ending, 93 last, 93 previous, 93 starting, 12 support for, 3–4 TIME, 12 TIMESTAMP, 12 instant-stamped table, 361 integrity constraints, 323–329, 339–340 application after modication statements, 326 Böhlen's classes of, 341 current/current, 326, 369 current/nonsequenced, 326 implementation, 323, 324 interstate, 473 intrastate, 141, 473 nonsequenced/current, 325, 326 nonsequenced/nonsequenced, 326 nontemporal variants, 326 query connection to, 323 sequenced/current, 325, 326, 328 sequenced/nonsequenced, 326 SQL3, 406, 434–435 temporal, 328 for valid-time table, 363 Internet Time, 437, 473 interstate integrity constraints, 473 interval constructors, 39–40 duration, 94 IBM DB2 UDB equivalent, 46 Informix–Universal Server, 48 list of, 39–40 Microsoft Access, 52 Microsoft SQL Server, 54 Oracle8 Server, 61 periods and, 94–95 SQL3, 405 Sybase SQLServer, 57 time zone extraction, 95 UniSQL, 64–65 See also constructors INTERVAL type, 30–31, 473 Informix–Universal Server, 44–46 intervals, 3, 30–33, 84, 473 adding, to instants, 30 characteristics of, 30 day-time, 31, 32–33, 84 direction, 30 eld extraction from, 41 elds, 31 Microsoft Access, 50 Microsoft SQL Server, 50 natural rules for, 81 Oracle8 Server, 62 qualier, 31 relative nature of, 30 spatial, 30 SQL handling of, 81 support for, 3–4 temporal, 30 year-month, 31–32, 84 intrastate integrity constraints, 141, 473 isolation levels dirty read, 242, 243, 472 serialization, 242 jiffy, 321, 473 joins current, 144, 472 nonsequenced, 384 sequenced, 148–153, 384, 385–386, 413 temporal, 384, 443 Julian calendar, 75 key constraints, 379 keys composite sort, 148 conceptual, 363 k'o, 131, 473 labeled durations, 43, 473 last instant function, 153, 170–171 leap seconds, 77, 81 LEAST function, 322 less-than predicate, 34–35 lifespan, 348, 473 entity, 348–349, 360–361, 364–365, 438 introduction of, 398 literals day-time interval, 33 IBM DB2 UDB, 45 Informix–Universal Server, 47 Microsoft Access, 48–49, 51 Microsoft SQL Server, 53 Oracle8 Server, 60 period, 90 Sybase SQLServer, 56 UniSQL, 64 local time, 78 logical design, 344, 355–375 initial nontemporal, 357 mapping to relational schema, 356–357 stages, 344 temporal annotations, 357–375 See also temporal database design logical keys, 364 LOT table, 16, 17, 20, 360, 362, 376 current/current foreign key for, 372 excerpt, 381 partitioning, 376, 377 primary key, 363, 364, 366 sequenced/current foreign key, 370–371, 373–374 valid-time sequenced foreign key, 374 LOT Archive table, 376 LOT CONTAINS table, 363, 376 foreign key, 37 primary key, 365 state, 386 LOT LOC table, 360, 362, 376 implemented as backlog, 367 instant transaction timestamps, 377 primary key, 367 LOT MOVE table, 361, 362, 376 instant transaction timestamps, 377 primary key, 366 lunar day, 224, 473 MASS TRTMNT table, 361 instantaneous relationship, 376 primary key, 365 mean solar second, 78 See also seconds SUBJECT INDEX mean time, 149, 473 MEETS predicate, 427 Microsoft Access, 8 assertions and, 133 CD-ROM materials, 84, 108, 138, 173, 215 datetime constructors, 51 implementation considerations, 83 interval constructors, 52 intervals, 50 literals, 48–49, 51 modifying state table and, 213 other operators, 52 period operations, 101, 102 predicates, 49, 51 sequenced foreign key in, 134 SQL-92 operations in, 51–52 types, 48, 51 year 2000 compliance denition, 71 Microsoft SQL Server, 8 assertions and, 135 CD-ROM materials, 84, 108, 138, 173, 215, 247, 272 cursor-based coalescing, 171–172 data type conversions, 50 datetime constructors, 53–54 interval constructors, 54 intervals, 50 literals, 53 modifying state table and, 213 other operators, 54–55 period operations, 101, 103–104 predicates, 53 sequenced primary key in, 135–136 SQL-92 operations in, 53–55 temporal types, 50, 53 tracking logs, 245–246 transaction-time state table, 272 triggers for maintaining P Log table in, 245–246 year 2000 problem and, 72 migration, 446–455 nonsequenced query/modications, 453–455 sequenced extensions, 450–453 temporal upward compatibility, 447–450 upward compatibility, 446–447 millennium, 63 bug, 474 start of, 79 See also year 2000 problem minutes, 321, 402 modications, 14, 176 arbitrary, 186 on backlogs, 394 on bitemporal table, 276, 282–307, 339, 387 complex, 198–205, 418–419 current, 16, 18, 19, 177–187, 416–417, 444–445 expression of, 17 feed yard case study, 444–446 implementing, 216 mentioning other table, 198–205, 216, 418–419 nonsequenced, 17, 18, 197– 198, 305–307, 393, 418, 445–446 nontemporal, 452 in nontemporal applications, 216 operation code indication, 394 period of applicability for, 21 postactive, 295, 331 retroactive, 295, 324, 474 rewritten, 257–259 sequenced, 18, 188–197, 294–305, 417, 445 SQL3, 416–421, 425 SQL3 bitemporal table, 435–436 SQL/Temporal, 452 temporal database design and, 387–396 temporal partitioning and, 208–212 on tracking log, 229–230 on transaction-time state table, 19 unrestricted, 182 in valid time, 332 on valid-time state table, 14–18 monitored table, 220, 223, 474 columns, 254 contents, 225 current modications on, 229 current query expressed against, 268 dened as views, 266 deletions, 269 past query on, 226 period-stamped table augmenting, 273 previous state reconstruction, 224 primary key, 254 state of, 241 triggers, 256 volatility of, 269 493 See also tracking logs monotonic vacuuming, 272, 474 nested query, 414 nonsequenced deletion on bitemporal table, 306 results, 307 See also deletions nonsequenced duplicates, 122, 474 removing, 159 removing (SQL3), 416 See also duplicates nonsequenced integrity constraints, 474 nonsequenced joins, 384 nonsequenced modications, 17, 18, 197–198, 445–446, 454, 474 on bitemporal table, 305–307 deletion, 306 in English, 197 evaluating, on table with valid-time support, 454 expression, 198 implementation, 198, 393 on partitioned table, 212 period timestamp manipulation, 454 ramications, 198 rarity, 198, 393 timestamp treatment, 197, 393 tracking logs and, 230 See also modications nonsequenced query, 156–158, 174 bitemporal, 314–320 evaluating, over table with valid-time support, 453 example, 158 expression of, 383–384 SQL3, 415–416 temporal partitioning and, 208 timestamps and, 158 on tracking logs, 229, 250 transaction-time state table and, 238 valid-time sequenced and, 319 WHERE clause and, 320 See also bitemporal query; queries nonsequenced referential integrity constraints, 128, 131 requiring contiguous history, 130 See also referential integrity constraints 494 SUBJECT INDEX NONSEQUENCED reserved word, 410, 428, 453, 465 nonsequenced query, 412, 415 with VALIDTIME clause, 428 nonsequenced valid-time assertions, 281 nonsequenced/current constraint, 325, 326 nonsequenced/nonsequenced constraint, 326 nonsequenced/nonsequenced query, 323 nonspecialized. See fully general relationship nontemporal crow's-feet schema, 359 nontemporal entity type, 347, 474 nontemporal ER schema, 345–348 nontemporal keys, 351 nontemporal query, 12, 13, 313 nontemporal relationship type, 347, 474 nontemporal update, 17 NORMALIZE operator, 455, 456, 457 NOT EXISTS construct, 154, 155, 166, 324, 337 nested, 165, 166 SELECT statements, 155 subqueries, 156 “now,” 119–120 NULL dates, 120 NULL predicate, 35 between period information, 36 values, 35 See also predicates open-closed representation, 90 open-open representation, 90 Oracle8 Server, 8, 55–62 assertions and, 137 CD-ROM materials, 84, 108, 138, 173, 215, 247, 396 date functions, 59 dates, 58–59 datetime constructors, 60–61 elds, 55 GREATEST function support, 173 implementation considerations, 83 interval constructors, 61 interval type and, 30 intervals, 62 LEAST function support, 173 literals, 60 modifying state table and, 213–214 other operators, 61–62 period operations, 101, 106 predicates, 60 sequenced primary key in, 137 SQL-92 operations in, 60–62 TO DATE function, 73 tracking logs, 246 types, 55, 60 year 2000 problem and, 73–74 Oracle PL/SQL, 167–168 ORDER BY clause, 148 See also clocks oscillator, 281 See also clocks ost, 349, 474 ostenta, 349 OVERLAPS predicate, 35–36, 82, 91 current transaction time-slice and, 428 format, 35 period information values, 82 returns, 35–36 See also predicates P. M . (post meridiem), 474 participation constraints, 348 minimum, 348 specifying, 348 time-invariant, 378–379, 476 partitioned table current deletions, 209 current insertion, 208 current query, 206–212, 216 current store of, 208 current update, 209 nonsequenced modications, 212 queries, 206–207 sequenced deletions, 209–210 sequenced insertions, 209 sequenced modications, 209–212 sequenced update, 211–212 past query, 226 pendulums, 257, 281, 288 PERIOD abstract type, 170, 171 period constructors, 95–97 list of, 95–97 SQL3, 88, 405 See also constructors period data types (SQL3), 403 period literals, 404 period of applicability, 188, 390, 474 deletions and, 417 duplicates and, 188, 190 periods outside of, 201 sequenced deletion, 191, 193 sequenced insertion, 390 sequenced modication, 417 sequenced update, 194, 196, 304 start of, 190 valid-time sequenced modications (SQL3), 436 period of presence, 254, 474 period of validity, 12, 110, 474 closed-closed representation for, 119 computing with CASE statement, 298 insertion, 296 merging value-equivalent rows and, 169 sequenced deletion, 191 sequenced update, 196 SET clause for, 201 specifying, 114 termination in the past, 186 WHERE clause for, 201 periods, 3, 88–108, 474 character constructors, 97 closed-closed representation, 89 closed-open representation, 89–90 constructors, 93–97 datetime comparison with, 92 datetime constructors, 93–94 deleting, 215–216 delimiting datetimes of, 90 equality predicates on, 91 FINDER schema and, 89 IBM DB2 UDB, 97, 98–99 implementation considerations, 97–108 inequality predicates on, 93 Informix–Universal Server, 97, 100 instant-pair representation, 89 interval constructors, 94–95 literals, 90 Microsoft Access, 101, 102 Microsoft SQL Server, 101, 103–104 no gaps within, 167 open-closed representation, 90 open-open representation, 90 operations in SQL3, 407 Oracle8 Server, 101, 106 order, 91 outside period of applicability, 201 overview, 88 period constructors, 95–97 SUBJECT INDEX predicates, 90–93 relationships between, 92 representations of, 88 SQL3 and, 88, 108 starting in future, 184 Sybase SQLServer, 101, 105 time zones of, 90 transaction-time, 361 UniSQL, 101, 107–108 value-equivalent, 163 period-stamped table, 273 physical design, 375–377 specication, 375 temporal partitioning as, 419 transaction-time support, 421 See also temporal database design PL/SQL, 167–168 P Log table, 220 backlog, 234 contents, 223 conversion to transaction-time state table, 227–228, 422 dening PROJECTIONS on a view on, 239 insert trigger for maintaining, 230 insertions in, 231 separate, 221 triggers for maintaining, 221, 235, 244–245 PO Archive table, 333 PO Current table, 331 points, 349, 474 polygonal region, splitting, 288 position, 27, 474 POSITIONS table, 149 ll gap in, 180, 182, 213, 214, 215 no gaps in, 182 period of validity for, 202 postactive entity/relationship type, 380 postactive modications, 295, 331, 474 example, 295 See also modications postactive specialization, 380, 474 See also temporal specialization precision, 28, 474 precision decomposition, 361, 474 predicates, 33–36, 82 BETWEEN, 35, 92 CONTAINS, 418, 439 equality, 33, 90–91 IBM DB2 UDB, 45 inequality, 93 Informix–Universal Server, 47 is null, 35 less-than, 34–35 MEETS, 427 Microsoft Access, 49, 51 Microsoft SQL Server, 53 Oracle8 Server, 60 OVERLAPS, 35–36, 91 SQL3, 404–405 Sybase SQLServer, 56 UniSQL, 64 previous instant, 93 primary key constraints, 117, 121 on monitored table, 254 sequenced, 124 uniqueness, 121 value-equivalent, 122 violation of, 185 See also constraints primary keys, 363–367 bitemporal table, 366–367 BKP table, 365, 380 construct, entity/relationship type capturing, 364 INCUMBENTS table, 117 LOT table, 363, 364, 366 LOT CONTAINS table, 365 LOT LOC table, 367 LOT MOVE table, 366 MASS TRTMNT table, 365 monitored table, 254 PRIMARY KEY construct, 13, 364 Prop Owner table, 280 sequenced, 110, 118, 475 specifying, at any point in time, 118 SQL3, 440 temporal, 110 temporally partitioned transaction-time state table, 266–268 transaction-time table, 365 UIS, 112 projections change history for, 260 changing type of, 230, 258–259 currently present, 270 deleting, 229, 258 history of, 426 inserting, 229, 257–258 time sequence of, 231 PROJECTIONS table, 220 code modifying, 221 contents, 223 conversion to instant-stamped table, 423 495 dening, as view on P Log, 239 reconstruction, 223, 225, 226, 231, 422 spurious changes in, 253 transactions, 222–223 transaction-time support, 421 proleptic Gregorian calendar. See Gregorian calendar property owner relationship, 278, 279 Prop Owner table, 278, 313 contiguous valid-time history, 282, 434 creation, 279, 427 current update change in, 285 evolving information content of, 284 foreign key, 428 number of rows in, 299 primary key, 280 retroactive changes made to, 324 P TT table, 268 contents, 256 as replacement for PROJECTIONS table, 259 triggers for maintaining, 255–256, 264 P TT CURRENT table, 263 contents, 265 mirroring changes to monitored table, 268 P TT PAST table, 263, 265 puncta, 349 queries auditing, 261, 426 on bitemporal table, 276, 307–323, 339 current, 142, 145, 226 on current state, 265 current/current, 320, 321, 332 current/nonsequenced, 322 feed yard case study, 13–14, 15, 443–444 future, 226 integrity constraint connection to, 323 on isolated temporal columns, 113 multiple temporal table, 145 nested, 414 nonsequenced, 156–158, 174, 229 nonsequenced, results of, 15 nonsequenced/nonsequenced, 323 queries (continued) nontemporal, 12, 13, 313 496 SUBJECT INDEX past, 226 sequenced, 145–156, 174, 229 sequenced/current, 321 sequenced/nonsequenced, 322 SQL3, 411–416, 422–425 SQL3 bitemporal table, 428–434 temporal database design and, 383–387 temporal partitioning and, 206–208 temporally partitioned transaction-time state table, 265–266 temporally upward compatible, 174 time-slice, 142, 145, 173, 259, 307–312 on tracking log, 222–229 on transaction-time state table, 19, 259–262 on valid-time state table, 12–13 reconstruction, 474 after-image and, 236, 237 process, 225 queries, 259 on state table, 259 transactions, 243 reconstruction algorithms, 218, 232, 234–235 commit time approximation, 244 with serialization isolation level, 243 states inconsistent with serializability, 242 reconstruction table, 218, 220 transaction semantics, 244 See also tracking logs rectangles alternate splitting into, 297 encoding bitemporal regions, 311 history store, 332 splitting into, 292, 296 referenced table, 127 contiguous histories in, 130 lling gap in, 180 foreign key constraints and, 368 update on, 187 referencing table, 126 insertions in, 179 instant timestamps, 373 nontemporal, 131 referential integrity, 126–131, 368–374 code fragments, 140 ensuring, with current insertion, 180 preserving, 188 in restricted case, 179 sequenced insertion ensuring, 189 sequenced/current, 328 SQL3, 409–411, 440 on valid-time table, 368 violation of, 179, 180 referential integrity constraints, 110, 126 on bitemporal table, 329 current, 127–128, 130 expression of, 140 nonsequenced, 128, 131 nontemporal, 128 sequenced, 129–130 types of, 127 See also constraints relationship types, 347–348 classifying, 379 fully general, 379, 473 instantaneous and valid-time instant is recorded, 364 instantaneous events, 349 nontemporal, 349, 474 postactive, 380 primary keys, 364 retroactive, 379 transaction time of, 354 valid time, list of, 350 valid-time extent, which is recorded, 365 See also entity types relationship valid time, 349–350, 438 representations of periods, 88, 108 closed-closed, 89, 119 closed-open, 89–90, 92, 358 open-closed, 90 open-open, 90 preferred, 91 See also periods resonator, 281 See also clocks retroactive modications, 295, 474 Prop Owner table, 324 See also modications retroactive relationship type, 379 retroactive specialization, 379, 474 See also temporal specialization rows archival, 338 current-duplicate, 121 future, 289 minimizing number of, 162 nonsequenced-duplicate, 122 sequenced-duplicate, 121 started in future, end in future, 181 started in past, end in future, 181 value-equivalent, 121, 122 SAL HISTORY table, 151, 207 current state, 144 excerpt, 152 seconds, 321 atomic (TAI), 78, 402, 471 barycentric coordinate (TCB), 78 barycentric dynamical (TDB), 78 ephemeris, 78, 472 geocentric coordinate (TCG), 78 sidereal, 78, 402, 475 terrestrial time (TT), 78 universal (UT0, UT1), 78 sequenced deletions, 190–193, 474 on bitemporal table, 299–302 converting to, 190 gaps, 193 implementation statements, 193 nonsequenced uniqueness violation, 193 on partitioned table, 209 period of applicability, 193 physical modications, 390 results, 302 valid-time, 300 See also deletions; sequenced modications sequenced duplicates, 121, 474 assuming only current modications, 124–125 removing, 160 removing (SQL3), 416 retaining, 160 See also duplicates sequenced extensions, 450–453 sequenced foreign keys, 128, 134 sequenced insertions, 188–190 on bitemporal table, 295–299 cases, 297 ensuring uniqueness and referential integrity, 189 on partitioned table, 209 SUBJECT INDEX period of applicability, 390 results of, 296, 299 See also insertions; sequenced modications sequenced integrity constraints, 474 sequenced joins, 148–153, 384, 475 applied to INCUMBENTS, 151 with CASE, 385–386 duplicates, eliminating, 158–169 rst case of, 150 inequality predicates, 150 second case of, 150 SELECT statements, 150, 174 SQL3, 413 See also joins; sequenced query sequenced modications, 18, 188–197, 445 on bitemporal table, 294–305 complex, 200–205 on partitioned table, 209–212 period of applicability, 417 SQL3, 417 tracking logs and, 230 See also modications; sequenced deletions; sequenced insertions; sequenced update sequenced primary key, 110, 475 constraint violation, 185 in DB2 UDB, 133 expressed as SQL assertion, 118 maintaining, 178 in Microsoft Access, 133 in Microsoft SQL Server, 135–136 in Oracle8 Server, 137 in restricted case, 179 in Sybase SQLServer, 136 in UniSQL, 138 valid-time, 281 See also primary keys sequenced projection, 146 sequenced query, 145–156, 174 bitemporal, 314–320 SQL3, 412–414 temporal partitioning and, 208 on tracking logs, 229, 250 on transaction-time state table, 238, 260 WHERE clause and, 320 See also queries sequenced referential integrity constraints, 129–130 sequenced semantics, 450 satisfying, 451 SQL/Temporal and, 450 sequenced sort, 148 sequenced update, 17, 194–197, 475 base cases, 202 on bitemporal table, 302–305 case analysis requirement, 211 cases, 194, 196 effecting result of, 197 implementation statements, 194 mentioning another temporal table, 202 partitioned table, 211–212 period of applicability, 194, 196, 304 period of validity, 196 results of, 196, 303 two-stage transformation process, 305 See also sequenced modications; updates sequenced/current constraint, 325, 326 foreign key, 327 referential integrity, 328 sequenced/current query, 321 sequenced/nonsequenced constraint, 326 sequenced/nonsequenced query, 322 serialization order, 250, 475 SET clause, 198 mentioning another table, 200 for period of validity, 201 set date C function, 247 sidereal day, 95, 475 sidereal hour, 402 sidereal second, 78, 402, 475 See also seconds SMALLDATETIME type, 72, 475 snapshot equivalence, 161, 475 snapshot reducibility, 174 snapshot table, 114–115, 311, 475 with additional timestamp columns, 318 empty, 319 equivalent, 161, 475 solar day, 95, 475 solar time, 95 mean, 149 true, 95, 149 Sothic cycle, 231, 475 specialization. See temporal specialization SQL3, 5, 9, 400, 402–403 ANSI committee, 466 CD-ROM materials, 459–460 datetime constructors, 405 draft standard, 466 497 EXPAND operator, 455, 456, 457 EXPANDING clause, 456–457 ISO committee, 466 NORMALIZE operator, 455, 456, 457 period data types, 403 period literals, 404 period operations, 407 period support, 108 SQL-92, 87 application development in, 461–464 bitemporal state table, 462–463 Capstone case, 463–464 expressions involving temporal values, 42 instants/intervals support, 3, 24 interval type, 31 limitations, 401–402 operations in IBM DB2 UDB, 45–46 operations in Informix– Universal Server, 47–48 operations in Microsoft Access 2000, 51–52 operations in Microsoft SQL Server, 53–55 operations in Oracle8 Server, 60–62 operations in Sybase SQLServer, 56–58 operations in UniSQL, 64–65 support, at Full SQL level, 42 temporal data types, 5 temporal predicates, 33 time-varying data problems, 401 transaction-time table, 462 valid-time state table, 461–462 year 2000 problem and, 67–68 SQL Entry level, 85 Full level, 85 Intermediate level, 85 SQL-86, 4, 8, 87 SQL-89, 4–5, 87 standard, 4–5 temporal types, 26 See also SQL3; SQL-92 SQL/Foundation, 447, 448 query evaluation, 447, 448 query requirements, 465 SQL/Temporal and, 450 temporal upward compatibility and, 449 498 SUBJECT INDEX SQL/Temporal, 450 constructs, 449, 450 modication evaluation, 452 query requirements, 450 requirements, 465 START DATE, 25, 159 state table converting to, 226–229 converting, to backlog, 262 dening, 110–141 dening, as a view, 268 modifying, 177–217, 416–421 organizations for, 252 querying, 143–175, 411–416 See also transaction-time state table; valid-time state table strong entity types, 345 See also entity types sundials, 31 Babylonian, 179 early, design of, 181 hemispherium, 7, 473 hemicyclium, 7, 473 See also heliochronometer Swatch Beat, 475 Sybase SQLServer, 8, 55, 56–58 assertions and, 136 CD-ROM materials, 84, 108, 138, 173, 215, 247 datetime constructors, 56–57 interval constructors, 57 literals, 56 other operators, 57–58 period operations, 101, 105 predicates, 56 sequenced primary key in, 136 SQL-92 operations in, 56–58 tracking logs, 246 types, 56 user-dened functions and, 173 year 2000 compliance denition, 73 year 2000 problem and, 73 Synchrony, 459 CD-ROM materials, 460 information on, 467 tables. See backlogs; bitemporal table; temporal table; tracking logs; transaction-time state table; valid-time state table Technical Corrigendum 3, 80 temporal annotations, 348–355 additional, 377–380 entity lifespans, 348–349, 360–361 primary keys, 363–367 referential integrity, 368–374 relationship valid time, 349–350 temporal specialization, 379–380 time-invariant keys, 378 time-invariant participation constraints, 378–379 time-invariant uniqueness constraints, 378 transaction time, 353–355, 361–363 transaction time-invariant constraints, 379 uniqueness constraints, 375 user-dened time attributes, 358–360 valid time of attributes, 350–353, 361 See also feed yard case study temporal constructors, 36, 475 temporal data types, 3, 42 IBM DB2 UDB, 45 Informix–Universal Server, 47 instant, 3 interval, 3 Microsoft Access, 48, 51 Microsoft SQL Server, 50, 53 Oracle8 Server, 55, 60 period, 3 SQL-92, 5 Sybase SQLServer, 56 UniSQL, 62, 64 temporal database design, 343–398 advanced aspects, 377–382 application development, 383–396 benets, 382–383 conceptual, 345–355 ve-step methodology, 397 implementation considerations, 396–397 logical, 355–375 modications and, 387–396 physical, 375–377 properly sequenced, 343–344 queries and, 383–387 temporal upward compatibility and, 449 temporal extensions, 470 temporal granularity, 12 temporal keys, 117–119 uniqueness and, 408–409 See also primary keys temporal partitioning, 206–212, 216 of bitemporal table, 329–337, 340 current, 331 current deletions and, 209 current query and, 206–207 current update and, 209 disadvantage of, 207 nonsequenced modications and, 212 nonsequenced query and, 208 as physical design, 419 sequenced deletions and, 209–210 sequenced insertions and, 209 sequenced modications and, 209–212 sequenced query and, 208 sequenced update and, 211–212 SQL3, 419–421, 427, 436 of transaction-time state table, 262–268 using, 206 temporal relational schema, 437–442 entity lifespans, 438 primary keys, 440 referential integrity, 440 relationship valid time, 438 SQL3, 441–442 transaction time, 439 uniqueness constraints, 440 user-dened time attributes, 438 valid time of attributes, 438 temporal semicompleteness, 466 temporal specialization, 379– 380, 475 applying, 382 degenerate entity type, 380 fully general relationship type, 379 postactive, 380, 474 retroactive, 379, 474 See also specic types temporal support attributes, 361 decomposition, 362, 475 integration, 469 requirements, 464–465 SQL3, 403 standard, 469 temporal table, 23, 475 modications mentioning, 198–205 multiple, 145 sequenced selection on, 146 UNION ALL over, 148 See also table SUBJECT INDEX temporal upward compatibility (TUC), 408, 411, 447–450, 475 application, 411 ensuring, 464 illustrated, 448 modication interpretation, 449 query semantics and, 448 SQL/Foundation statements, 449 state contents, 448 system design and, 449 See also migration temporal vacuuming, 269, 475 archival store, 270 old unused entities from archival store, 270–271 See also vacuuming temporally partitioned transaction-time state table, 206, 262–268, 475 archival stores, 263–265 current stores, 263–265 maintaining, 264 queries, 265–266 utilizing primary key, 266–268 See also transaction-time state table temporally upward compatible query, 174 terrestrial time (TT) second, 78 See also seconds tidal rhythms, 224 TIGER, 458–459 ATSQL and, 458–459 CD-ROM materials, 460 development, 459, 467 source, 458 time as-of, 232, 242 digital perception of, 217 equation of, 149, 473 Internet, 437, 473 interval, 340 kinds of, 3 local, 78 mean, 149, 473 solar, 95, 149 transaction occurs, 340 true, 95, 476 user-dened, 4, 476 See also transaction time; valid time time diagram, 283, 472 corresponding bitemporal table, 330 horizontal slice, 309 illustrated, 284 regions in, 287 update impact on, 284, 285 variation, 340 vertical slice, 307 See also bitemporal table time duration, 43 Time Extended EER Model, 398 TIME type, 28–29, 401, 470, 475 converted to datetime value, 38 length, 28–29 TIME WITH TIME ZONE type, 29 using, 80 value safety, 80 time zones, 78, 80 displacement, 78 extraction of, 95 of periods, 90 using, 80 variants, 29 TIMEDB, 458 development, 467 TIMEDB 1, 458, 460 TIMEDB 2, 458, 460 versions, 458 time-dependent assumptions, 66, 475 time-invariant constraints, 379 applying, 381 participation, 378–379, 476 transaction, 379 uniqueness, 378 See also constraints time-invariant data, 126 time-invariant keys, 378, 476 applying, 380–381 ensuring, 380 time-invariant unique, 378, 476 transaction, 476 valid, 381 time-sequence object, 231, 476 time-slice, 147, 476 bitemporal, 311–312, 429, 472 horizontal, 309, 310 rows resulting from, 310 transaction, 307, 308, 309, 476 valid, 309, 310, 429, 476 vertical, 308, 309 time-slice query, 142, 173, 259, 476 on bitemporal table, 307–312 current, 145, 472 current-valid, 145, 472 over previous state, 145 transaction, 428 valid, 309 timestamp columns, 114, 116, 476 499 appending, to end of composite sort key, 148 in a bitemporal table, 279 history store, 332 instant, 360 nonsequenced modications and, 197, 393 nonsequenced query and, 158 snapshot table and, 318 timestamp duration, 43 TIMESTAMP type, 28, 401, 470, 476 converted to datetime value, 39 IBM DB2 UDB, 68 length, 28 year digits, 67 TIMESTAMP WITH TIME ZONE type, 29, 79 timestamps, 116, 476 delimiting, 108 feed yard case study, 20–21 granularity, 427 instant, 373 literal, 28 period, 373 SQL, 77 of the table, 116 transaction, 429 See also timestamp columns time-varying keys, 351 tracking logs, 218–251, 476 after-image, 218, 235 automatic maintenance of, 222 auxiliary columns, 221 backlogs, 233–235 before-image, 218, 235 CD-ROM materials, 247–248 IBM DB2 UDB, 244–245 implementation considerations, 244–248 Microsoft SQL Server, 245–246 Oracle8 Server, 246 organizations, 218 reconstruction algorithms, 218 schema, 218, 221 SQL3, 421–425 Sybase SQLServer, 246 transaction semantics, 240–243 transaction time support, 249 as transaction-time state table, 227 UniSQL, 247 transaction time, 4, 353–355, 361–363, 476 application of, 20 of attributes, 355 500 SUBJECT INDEX transaction time (continued) nonsequenced in, 319 of relationship types, 354 sequenced in, 316, 317 SQL3, 439 support implementation, 274 valid time interactions, 21 See also valid time transaction time-invariant constraints, 379, 476 transaction time-slice, 307, 308, 309, 476 OVERLAPS predicate and, 428 transaction-stop time, 334 transaction-time current query SQL3, 430 valid-time current and, 314, 430 valid-time nonsequenced and, 315–316, 430 valid-time sequenced and, 315, 430 See also bitemporal query transaction-time nonsequenced query SQL3, 424, 431–432 valid-time current and, 318–319, 431 valid-time nonsequenced and, 319–320, 432 valid-time sequenced and, 319, 432 See also bitemporal query TRANSACTIONTIME reserved word, 423, 427, 451, 465 transaction-time sequenced query SQL3, 423, 431 valid-time current and, 316, 431 valid-time nonsequenced and, 318, 431 valid-time sequenced and, 316–318, 431 See also bitemporal query transaction-time splitting, 296, 476 transaction-time state table, 252–274, 309, 476 after-image from, 261, 424 append-only, 249 backlog extraction from, 262, 424–425 before-image from, 261, 424 CD-ROM materials, 272 converting backlogs to, 237–238 converting tracking logs to, 226–229, 253 creating, 254 dened as views, 266 dening in SQL3, 421–422 feed yard case study, 18–20 implementation considerations, 272 implemented as backlogs, 367 Microsoft SQL Server, 272 reconstructed state, 250 represented with two table, 264 schema, 254 SQL3, 426–427 tracking log as, 227 See also temporal table; valid-time state table transaction-time support, 421 current query and, 422 in SQL3, 421 triggers, 469 assertions implemented as, 135–136 dening, on current store, 265 DELETE, 235 IBM DB2 UDB, 244 INSERT, 138, 235 for maintaining P Log in IBM DB2 UDB, 244–245 for maintaining P Log in Microsoft SQL Server, 245–246 for maintaining P Log in Sybase SQLServer, 246 for maintaining P Log table, 221, 230, 235 for maintaining PO Archive table, 333 for maintaining P TT table, 255–256, 264 maintaining tracking log with, 218 for maintaining tripartitioned state table, 267 monitored table, 256 UniSQL, 138 UPDATE, 138, 235 tripartitioned state table current store, 266 triggers for maintaining, 267 tripartitioned store, 273 tropical year, 18, 476 true day, 95, 476 true time, 95, 476 TSQL2 committee, 466 temporal query language, 217 two-phase row-level locking, 240 UNION ALL clause, 148, 152 UNIQUE constraint, 124, 139 IBM DB2 UDB support, 132–133 nonsequenced duplicate prevention, 122 uniqueness in restricted case, 179 sequenced, 375 sequenced insertion ensuring, 189 temporal keys and, 408–409 time-invariant, 381 uniqueness constraints, 122, 124, 139, 375 sequenced/current, 375 SQL3, 440 time-invariant, 378 UniSQL, 8, 62–63, 64–65 assertions and, 138 CD-ROM materials, 84, 108, 138, 173, 215, 247 CURRENT DATE and, 173 datetime constructors, 64 insert trigger on tracking log, 247 interval constructors, 64–65 literals, 64 modifying state table and, 215 other operators, 65 period operations, 101, 107–108 predicates, 64 sequenced primary key in, 138 SQL-92 operations in, 64–65 tracking logs, 247 trigger support, 247 types, 62, 64 universal time (UT0, UT1) second, 78 See also seconds University Information System (UIS), 111 client-server architecture, 112 EMPLOYEES table, 112, 116 history, adding, 113–119 INCUMBENTS.SSN, 125–126 INCUMBENTS table, 112, 113, 114, 115 initial schema, 112–113 POSITIONS table, 112 primary keys, 112 SSN, 114 timestamp columns, 114 UPDATE statement, 176, 254, 416 bitemporal table, 289, 290, 293 checking for sequenced duplicates, 198 SUBJECT INDEX in current update general case, 187 nontemporal, 185 sequenced update, 195 sequenced update mentioning other table, 205 updates, 184, 391 on bitemporal table, 284–291, 302–305 current, 176, 184–187, 258–259, 284–291 implementation of, 391 nontemporal, 201–202, 215 on referenced table, 187 sequenced, 194–197 series of, 241 SQL3, 425 on transaction-time state table, 258–259 See also modications upward compatibility, 446–447 ensuring, 464 temporal, 408, 411, 447–450, 464 See also migration user-dened time, 4, 23, 476 attributes, 358–360, 438 columns, 114, 360 UTC. See Coordinated Universal Time (UTC) vacuuming, 268–272, 476 for ameliorating space overhead, 274 archival store, 338 bitemporal table, 337–339 criteria, 476 entity vacuuming, 269 monotonic, 272, 474 operations log, 271 specications, 271 SQL3, 427, 436 temporal, 269, 270–271, 475 types of, 269 violation, 270 See also transaction-time state table valid time, 4, 476 application of, 20 of attributes, 350–353, 361, 438 bitemporal table and, 285 current in, 314 duration, 306 future, 332 granularity, 332 relationship, 349–350, 438 transaction time interactions, 21 See also transaction time valid time-slice, 309, 310, 476 valid-time current query SQL3, 430, 431 transaction-time current and, 314, 430 transaction-time nonsequenced and, 318–319, 431 transaction-time sequenced and, 316, 431 See also bitemporal query valid-time nonsequenced query SQL3, 430, 431, 432 transaction-time current and, 315–316, 430 transaction-time nonsequenced and, 319–320, 432 transaction-time sequenced and, 318, 431 See also bitemporal query VALIDTIME reserved word, 413, 427, 436, 451, 465 with NONSEQUENCED clause, 410 with TRANSACTIONTIME clause, 428 valid-time sequenced query SQL3, 430, 431, 432 transaction-time current and, 315, 430 transaction-time nonsequenced and, 319, 432 transaction-time sequenced and, 316–318, 431 See also bitemporal query valid-time splitting, 296, 476 valid-time state table, 12–18, 110, 114, 477 dening in SQL3, 406–411 See also state table; transactiontime state table valid-time support, 406, 477 value-equivalent rows, 121, 122, 477 501 merging pairs of, 162, 169 periods, 163 vertical blanking interval (VBI), 243 views bitemporal table expressed as, 333 complex, 336 dening state table as, 268 monitored table dened as, 266 transaction-time state table dened as, 266 watches Bulova Accutron, 364 H-4, 351 radio, 418 water clocks, 115 astronomical clock, 131 disadvantages, 131 early, design of, 181 See also clepsydra weak entity types, 345 Web sites, year 2000 problem, 86 Well Core Hdr table, 26 WITH TEMP construct, 213 year 2000 certication, 66–67 year 2000 compliance, 66–67 Informix denition, 69 Microsoft denition, 71 year 2000 problem, 63–74, 477 IBM DB2 UDB, 68–69 Informix–Universal Server and, 69–71 Microsoft Access and, 71–72 Microsoft SQL Server and, 72 Oracle8 Server and, 73–74 SQL-92 and, 67–68 Sybase denition, 73 Sybase SQLServer and, 73 Web sites, 86 See also time-dependent assumptions year-month intervals, 31–32, 84, 477 casts resulting in, 40 denoted styles, 31 elds, 31 lengths, 31–32 See also intervals About the Author Richard Snodgrass is a professor of computer science at the University of Arizona, where he joined the Computer Science Department in 1989. He holds a B.A. degree in physics from Carleton College, and M.S. and Ph.D. degrees in computer science from Carnegie Mellon University. He has written or edited ve books, as well as many journal articles and a column on time-oriented SQL for Database Programming & Design Online. He is an associate editor of the ACM Transactions on Database Systems, the IEEE Transactions on Knowledge and Data Engineering, and the International Journal on Very Large Databases. He is an ACM fellow. He chairs the ACM Special Interest Group on Management of Data (SIGMOD) and is the American Program Committee chair for VLDB 2001. He chaired the program committees for the 1994 SIGMOD Conference and the 1993 International Workshop on an Infrastructure for Temporal Databases. In addition, he has served as a vice chair or member of many program committees. He chaired the TSQL2 Language Design Committee and is now working closely with the ISO SQL3 committee to add temporal support to that language. He initiated the SQL/Temporal part of the SQL3 draft standard. He codirects T IME C ENTER, an international center for the support of temporal database applications on traditional and emerging DBMS technologies. About the CD-ROM SYSTEM REQUIREMENTS This CD-ROM may be read by Microsoft Windows (95/98/NT), Apple Macintosh, and Unix (including Ultrix, Solaris, Linux, and other variants). The CD-ROM is a hybrid disk in ISO 9660 format with Rock Ridge and Joliet extensions, allowing users of those operating systems to share the same directory structure and access common les. All le names are eight characters or less, with an extension having no more than three characters. A web browser, such as Netscape Explorer, Netscape Communicator, or Microsoft Explorer, should be used to view the contents of this CD-ROM. To view the PDF les, you need a version of Adobe Acrobat Reader; included on the CD-ROM are versions of Acrobat Reader for several platforms. For some documents, a PostScript version is also included. GETTING STARTED Open “cover.htm” in the top-level directory in your web browser. DESCRIPTION OF CD-ROM MATERIALS The accompanying CD-ROM contains nine directories containing web pages, documents in PDF format, and executable les as an archive (tar) le. The directories “datatype” (Chapters 3 and 4), “vtstbl” (Chapters 5–7), “audit” (Chapter 8), “transtbl” (Chapter 9), “bitmptbl” (Chapter 10), “tddesign” (Chapter 11), and “lang” (Chapter 12) contain web pages and code fragments, often for many different DBMSs. For instance, many of the code fragments in Chapter 5 are given 504 ABOUT THE CD-ROM for Microsoft Access and SQL Server, IBM DB2 Universal Database, Oracle8 Server, Sybase SQLServer, and UniSQL. The les in these directories may be accessed by following links from the top-level web page, “cover.htm.” The “images” directory contains some gif les used in the various web pages. The “doc” directory contains executable versions of Adobe Acrobat Reader for various platforms. The “lang” directory contains information on the if... Synchrony and TimeConsult T IME DB 2 products; the Tiger and T IME DB 1 prototypes; executable code for the T IME DB 1 and T IME DB 2 systems; and technical reports on temporal databases, TSQL2, and SQL3. Finally, the “misc” directory contains the Web URLs that appear in the book and a list of all the principles appearing as pull quotes in the book. The code fragments on this CD-ROM are for illustrative purposes only. They have been developed to maximize readability over performance. They have not been thoroughly tested. COPYRIGHT NOTE The software and data are provided on the accompanying CD-ROM. By opening the package you agree to be bound by the following agreement: This software is supplied to help the reader understand the principles involved in developing time-varying applications. It is provided for personal use only and may not be incorporated into any product or used for any other purpose without permission. This software is sold as is without any warranty of any kind, either expressed or implied, including but not limited to the implied warranty of merchantability and tness for a particular purpose. Neither the author, nor Morgan Kaufmann, nor its dealers or distributors, nor the copyright holders of material contained on this CDROM, assume any liability for any alleged or actual damages arising from the use, or the inability to use, this software. The entire and exclusive remedy for any defect in materials or workmanship in construction of the CD-ROM shall be limited to replacement of the defective CD-ROM.