This schema uses Microsoft SQL Server 2017.
- All date and time values use
DATETIMEOFFSET
to maintain time-zone awareness. - No data type in SQL Server 2017 is daylight-saving-time aware on its own, and
AT TIME ZONE
relies on an operating-system-specific mechanism. Specifically,AT TIME ZONE
could behave differently on Linux than on Windows. For these reasons and others, handle time-zone conversions—carefully—in client code, not SQL. - SQL Server 2017 has no suitable timespan data type, so durations use appropriate integer types.
- The 32-bit signed
INT
value is reasonable forIDENTITY
columns. - Money amounts use
DECIMAL(9,2)
, providing seven digits before and two digits after the decimal point. The precision of 9 is the largest that can remain within five bytes of storage. MONEY
historically has issues, so do not use it.
- Nonclustered index fields for one row cannot exceed 1,700 bytes, so unique text columns like
dbo.Show.Title
cannot exceedNVARCHAR(850)
.NVARCHAR
types use UTF-16 encoding, so they use two bytes per character.
- Specify the default schema
dbo
explicitly. - All constraints must have defined names.
- Table names are singular unless that name would be a reserved keyword.
- References to tables with plural names treat the table name as singular. For example, use
OrderId
to refer to thedbo.Orders
primary-key columnId
. - Name standalone
IDENTITY
columnsId
without including the table name.
- This schema represents only one multiplex facility. That is, the schema does not yet support multiple theater locations. However, details such as time zones are part of the schema now, so adding locations should not be too much extra work should the need arise.
- The schema does not consider different seating types, such as "balcony" or "box" seating.
- For simpler database design, the schema assumes continental seating. No information about aisles is part of the schema.
- The default constraint for
OrderDate
arguably contradicts the earlier advice about not manipulating time zones in SQL. But, creation-date defaults are typical, and developers may expect one. - Random.org chose the identity seed of 24696. Because an order ID may be user-visible, starting from 1 may be undesirable.
- It may be convenient to know when a reservation was canceled, so
CancelDate
is aDATETIMEOFFSET
rather than a bit flag. - The unique index is filtered to include only non-canceled reservations. Any number of canceled reservations may refer to the same screening and seat. The filter does not allow this unique index to be the clustered index, so the table still has an
Id
column as its primary key.
- The unique key on
Id
andAuditoriumId
is for referential integrity fromdbo.Reservation
. AsId
is already unique, adding this unique key is redundant; however, SQL Server requires foreign keys to refer to either a primary key or a unique key. - It is not possible to use SQL Server's constraints to ensure that shows do not overlap in the same auditorium. Ensuring different start times is the best we can do without resorting to triggers. Adding the end time would not help, and we can compute the end time using
dbo.Show.MinutesLong
, so we should not store an end time in this table.
- This table will rarely change, and references to
dbo.Seat
may want to ensure the correct auditorium. So, instead of anIDENTITY
column, the seat's "coordinates" (AuditoriumId
,Row
, andNumber
) serve as the primary key. The extra safety justifies the additional few bytes in each row ofdbo.Reservation
. Number
is, in fact, a number rather than a string. Using a number eases determining which seats are adjacent, though the schema does not contain any logic to determine adjacency.- The schema does not account for modifying a row or number, which would be rare. Reconfiguring an auditorium's seating might involve creating a new row in
dbo.Auditorium
, in which case a new set ofdbo.Seat
rows is required.
Title
is unique to avoid user-interface confusion later. A title might include a year to disambiguate, like Aladdin (2019).- 32,767 minutes is plenty of length for a movie, so
SMALLINT
is appropriate. - Although
Title
is unique, I includedId
so that foreign-key references may use four bytes instead of up to 1,700.
PasswordHashString
accommodates a bcrypt hash string, as OWASP currently suggests.Email
servers as the login ID. However, a user's email can change, soEmail
is not the primary key.
This ordering works for a new database.
dbo.Users
dbo.Orders
dbo.Show
dbo.Auditorium
dbo.Seat
dbo.Screening
dbo.Reservation
Installing dbatools in PowerShell allows running CreateDatabase.ps1
to create the database and those tables. Modify the Connect-DbaInstance
statement for your environment. The script is not idempotent.