Create Database Scripts in T-SQL
Turn a design into a script that builds it - CREATE DATABASE, CREATE TABLE with types, NOT NULL, IDENTITY and DEFAULT, and constraints for primary keys, foreign keys, UNIQUE and CHECK.
Journeyman · T-SQL · SQL · Updated
After this lesson you can
- Write a script that creates a database and its tables, with types, NOT NULL, IDENTITY and DEFAULT
- Add primary key, foreign key, UNIQUE and CHECK constraints
Key takeaways
- A create script builds the database from nothing, and
DROP DATABASE IF EXISTSat the top lets you run it again to start fresh. - Give every column a type that fits its data, and make it
NOT NULLunless a value may be missing. - An
IDENTITY(1, 1)column is numbered by SQL Server, and aDEFAULTgives a value when anINSERTleaves the column out. - Named
PRIMARY KEY,FOREIGN KEY,UNIQUEandCHECKconstraints make the database itself refuse bad data, whatever app sends it. - Create tables parents first, such as
OwnersbeforePets, and drop them children first.
A design becomes real through a script: a .sql file that builds the database from nothing. Keeping it as a script, not clicks in SSMS, means you can run it again on another computer, or start fresh whenever you want. (That's what Northwind.sql does.)
This lesson builds PetClinic, a small database for a vet's office: owners, their pets, the vets, and each visit.
Commands that build things
| Command | Does |
|---|---|
CREATE |
Makes a new database, table, view... |
ALTER |
Changes one that exists: adds a column, adds a constraint |
DROP |
Deletes it, with everything in it |
These are DDL, the data definition language: they change the structure, where INSERT, UPDATE and DELETE change the data.
The database
USE master;
GO
DROP DATABASE IF EXISTS PetClinic;
GO
CREATE DATABASE PetClinic;
GO
USE PetClinic;
GO
USE master comes first, because SQL Server can't drop the database your window is using. DROP DATABASE IF EXISTS deletes any old copy, so the script can run again and start fresh. USE switches to the new database, so the tables are made there and not wherever SSMS happened to be pointing. Each GO ends a batch; CREATE DATABASE must finish before the database can be used.
Tables
CREATE TABLE lists each column with its type, and whether it may be empty:
CREATE TABLE Owners
(
OwnerId int IDENTITY(1, 1) NOT NULL,
FirstName nvarchar(30) NOT NULL,
LastName nvarchar(30) NOT NULL,
Phone nvarchar(20) NULL,
Email nvarchar(100) NULL,
CONSTRAINT PK_Owners PRIMARY KEY (OwnerId)
);
CREATE TABLE Pets
(
PetId int IDENTITY(1, 1) NOT NULL,
OwnerId int NOT NULL,
Name nvarchar(30) NOT NULL,
Species nvarchar(20) NOT NULL,
BirthDate date NULL,
CONSTRAINT PK_Pets PRIMARY KEY (PetId),
CONSTRAINT FK_Pets_Owners FOREIGN KEY (OwnerId) REFERENCES Owners (OwnerId)
);
CREATE TABLE Vets
(
VetId int IDENTITY(1, 1) NOT NULL,
Name nvarchar(60) NOT NULL,
CONSTRAINT PK_Vets PRIMARY KEY (VetId)
);
CREATE TABLE Visits
(
VisitId int IDENTITY(1, 1) NOT NULL,
PetId int NOT NULL,
VetId int NOT NULL,
VisitDate datetime2 NOT NULL CONSTRAINT DF_Visits_VisitDate DEFAULT SYSDATETIME(),
Reason nvarchar(200) NOT NULL,
Fee decimal(8, 2) NOT NULL,
CONSTRAINT PK_Visits PRIMARY KEY (VisitId),
CONSTRAINT FK_Visits_Pets FOREIGN KEY (PetId) REFERENCES Pets (PetId),
CONSTRAINT FK_Visits_Vets FOREIGN KEY (VetId) REFERENCES Vets (VetId),
CONSTRAINT CK_Visits_Fee CHECK (Fee >= 0)
);
Types
| Type | Holds | Example |
|---|---|---|
int |
Whole numbers | PetId, quantities |
nvarchar(n) |
Text of up to n characters, in any language |
Names, emails |
decimal(p, s) |
Exact decimals: p digits in all, s after the point |
Fee decimal(8, 2), up to 999999.99 |
money |
Amounts of money, as Northwind uses | Prices |
bit |
1 or 0, true or false | Discontinued |
date |
A date | BirthDate |
datetime2 |
A date and time | VisitDate |
Choose the type that fits the data: a date column can't hold "next Tuesday", and a decimal column can't hold "about ten dollars".
NOT NULL, IDENTITY and DEFAULT
NOT NULLmeans every row must have a value.NULLallows a missing one: a pet's birth date may be unknown.IDENTITY(1, 1)makes SQL Server number the rows itself, starting at 1 and going up by 1. You never insert a value into an identity column.DEFAULTgives a value when anINSERTleaves the column out: a visit is dated now, bySYSDATETIME(), unless another date is given.
Constraints
Constraints are rules the database enforces on every insert and update. Each has a name, so its error messages say which rule was broken.
| Constraint | Rule | In PetClinic |
|---|---|---|
PRIMARY KEY |
The column (or columns) is unique and never NULL |
PK_Pets on PetId |
FOREIGN KEY ... REFERENCES |
The value must exist in the other table's key | FK_Pets_Owners: a pet's OwnerId must be a real owner |
UNIQUE |
No two rows have the same value | Two owners can't share an email |
CHECK |
A condition every row must meet | CK_Visits_Fee: no negative fees |
Constraints can also be added after the tables exist, with ALTER TABLE:
ALTER TABLE Owners
ADD CONSTRAINT UQ_Owners_Email UNIQUE (Email);
Now the database itself refuses bad data, whatever app sends it. A pet for an owner who doesn't exist:
INSERT INTO Pets (OwnerId, Name, Species)
VALUES (99, 'Ghost', 'Cat');
Msg 547, Level 16, State 1
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Pets_Owners". The conflict occurred in database "PetClinic", table "dbo.Owners", column 'OwnerId'.
A negative fee breaks CK_Visits_Fee, and a second owner with the same email breaks UQ_Owners_Email, each with its own message.
Order matters
Tables must be created parents first: Owners before Pets, because Pets refers to it. They must be dropped children first: SQL Server won't drop Owners while Pets still refers to it.
Msg 3726, Level 16, State 1
Could not drop object 'Owners' because it is referenced by a FOREIGN KEY constraint.
Try it
Put the database, the tables and a few INSERTs in one file, PetClinic.sql, and run it in SSMS. Then join the tables to see every visit with its owner, pet and vet. Run it again: DROP DATABASE IF EXISTS starts it fresh each time.
Check yourself
2 questions to try on the lesson page.
So what
A create script is the design, written so a computer can build it: tables with the right types, keys that link them, and constraints that keep bad data out for every app that ever connects.