First understand what each SQL type and key does. Then use tblEvent only as a practical example for selecting types, enforcing relationships and identifying rows.
- Data types encode process rules, not only storage size.
- Foreign keys reject equipment identifiers that do not exist.
- A binary
bitis correct only for a permanently two-state domain. - A candidate key is a business guarantee, not a guess based on sample data.
Learn SQL Data Types and Keys from Basics
This guide covers SQL data types basics, primary and foreign keys, candidate and alternate keys, SQL Server constraints and practical tblEvent examples.
1. What Is a SQL Data Type?
A SQL data type defines the kind of value a column, variable or parameter can hold. It determines valid range, storage representation, precision, supported operations, comparison behavior and conversion rules.
For automation data, select a type from the engineering meaning:
- What is the minimum and maximum possible value?
- Is the number exact or an approximate measurement?
- How many decimal places are meaningful?
- Can the value be unknown or unavailable?
- Does text require multiple languages?
- Is the timestamp UTC, local time or offset-aware?
- How many rows will be stored and how will they be queried?
INT is commonly 16-bit, while SQL Server int is 32-bit. Compare ranges, not names alone.2. Major SQL Server Data-Type Families
| Family | Common types | Automation examples |
|---|---|---|
| Exact integer | tinyint, smallint, int, bigint | Modes, counters, sequence numbers, equipment IDs |
| Exact decimal | decimal(p,s), numeric(p,s) | Setpoints, totals and values requiring fixed decimal rounding |
| Approximate numeric | real, float | Measurements where IEEE floating-point approximation is acceptable |
| Boolean | bit | On/off, enabled/disabled, acknowledged flag |
| Date and time | date, time, datetime2, datetimeoffset | Events, shifts, batches and source/receive timestamps |
| Non-Unicode text | char, varchar | Controlled ASCII codes and identifiers |
| Unicode text | nchar, nvarchar | Alarm messages, operator comments and multilingual labels |
| Binary | binary, varbinary | Hashes, documented payloads or files |
| Special | uniqueidentifier, rowversion, xml | Distributed event IDs, concurrency markers and structured documents |
3. Integer Types and Ranges
| SQL type | Range | Typical automation use |
|---|---|---|
tinyint | 0 to 255 | Unsigned byte, small state code or priority |
smallint | -32,768 to 32,767 | PLC signed 16-bit INT |
int | -2,147,483,648 to 2,147,483,647 | PLC DINT, IDs and medium counters |
bigint | Signed 64-bit range | Identity keys, high counters, durations and sequence numbers |
Choose the smallest type that safely covers the approved lifetime range, not merely today's sample values. For an identity key in a high-frequency event table, estimate row growth before choosing int or bigint.
4. Exact and Approximate Numeric Types
decimal and numeric
decimal(p,s) and numeric(p,s) are synonyms. Precision p is total digits; scale s is digits to the right of the decimal point. SQL Server supports precision up to 38.
TemperatureSetpoint decimal(8,3), -- five integral + three fractional digits
ProductionTotal decimal(18,3)real and float
These are approximate binary floating-point types. They are suitable for many sensor values, but decimal fractions may not compare exactly. Do not use floating-point equality as a business rule.
| Requirement | Preferred direction |
|---|---|
| Fixed decimal precision and repeatable rounding | decimal(p,s) |
| Scientific/engineering approximate values and wide range | real or float |
| Binary state | bit |
| Currency-like fixed decimal | Explicit decimal(p,s) chosen with finance/DBA review |
5. Character, Unicode and Length
char(n): fixed-length non-Unicode text.varchar(n): variable-length non-Unicode text.nchar(n): fixed-length Unicode text.nvarchar(n): variable-length Unicode text.
Use nvarchar for multilingual HMI messages and operator comments. Define a realistic maximum length; do not choose max by default. Length is part of the interface contract and must match application parameter definitions.
ChargeNo varchar(50) NOT NULL,
AlarmText nvarchar(500) NOT NULL,
OperatorNote nvarchar(1000) NULL
6. Date and Time Types for Automation
| Type | Stores | Typical use |
|---|---|---|
date | Date only | Production date or scheduled day |
time(n) | Time of day | Recipe or shift time without a date |
datetime2(n) | Date/time with selectable fractional precision | UTC process and event timestamp |
datetimeoffset(n) | Date/time plus UTC offset | When the original offset is part of the fact |
datetime | Legacy date/time with .000/.003/.007 rounding | Backward compatibility |
timestamp is a deprecated synonym for rowversion. Use datetime2 or datetimeoffset for actual time.For SCADA events, a clear design is EventTimeUtc datetime2(3) plus a separate receive timestamp and source sequence when event ordering matters.
7. NULL and Column Constraints
NULL means missing, unknown or not applicable. It is not equal to zero, false or an empty string. Query it using IS NULL and IS NOT NULL.
Data types define representation; constraints define additional rules:
| Constraint | Purpose | tblEvent example |
|---|---|---|
NOT NULL | Value is mandatory | DT datetime2(3) NOT NULL |
DEFAULT | Supplies a value when omitted | IsActive bit DEFAULT (1) |
CHECK | Restricts valid domain/range | Temperature range or status-code list |
UNIQUE | Prevents duplicate key values | (ChargeNo, DT) after business approval |
PRIMARY KEY | Chosen row identity | ID |
FOREIGN KEY | Enforces parent relationship | SQF_No to Equipment |
8. What Is a Database Key?
A key is one column or a combination of columns used to identify rows or relate tables. Key theory separates possible identities from the one selected for implementation.
| Key term | Meaning | Example |
|---|---|---|
| Super key | Any column set that uniquely identifies a row, including unnecessary columns | (ID, DT) when ID alone is unique |
| Candidate key | Minimal super key; no column can be removed and retain uniqueness | ID, or approved (ChargeNo, DT) |
| Primary key | Candidate key selected as the main row identity | tblEvent.ID |
| Alternate key | Candidate key not selected as primary | Approved unique (ChargeNo, DT) |
| Composite key | Key containing two or more columns | (ChargeNo, DT) |
| Natural key | Identity derived from business data | Charge/timestamp when guaranteed by process |
| Surrogate key | Artificial identity without business meaning | Identity column ID |
| Foreign key | Child column(s) referencing a parent candidate/primary key | SQF_No references EquipmentID |
9. Primary, Candidate and Alternate Keys
A primary key must be unique and NOT NULL. SQL Server creates a unique index to enforce it. A table has one primary-key constraint, although that key can contain multiple columns.
Candidate keys are a logical design concept. To enforce alternate keys in SQL Server, use UNIQUE constraints after confirming minimality, mandatory columns and the real business rule. Existing sample uniqueness alone does not prove a candidate key.
CONSTRAINT PK_tblEvent PRIMARY KEY (ID),
CONSTRAINT UQ_tblEvent_Charge_DT UNIQUE (ChargeNo, DT)
10. Foreign Keys and Referential Integrity
A foreign key prevents a child row from referencing a parent that does not exist. It does not automatically create an index on the child column, and it does not decide what should happen on delete/update; those behaviors must be designed explicitly.
For production history, avoid cascade delete unless the retention and audit policy explicitly permits deleting dependent events.
11. Use tblEvent as the Running Example
The reference table demonstrates how data types, constraints and keys work together:
| Column | Concept | Design question |
|---|---|---|
ID | Surrogate primary key | Will int or bigint cover lifetime row volume? |
DT | Date/time type | What precision and UTC convention are required? |
SQF_No | Foreign key | Does every event reference valid equipment? |
ChargeNo | Natural identity component | Is it mandatory and stable? |
Fan_Status | Domain/type tradeoff | Binary forever, or future multi-state? |
USE [SQF_DB];
GO
SELECT
c.name AS ColumnName,
t.name AS DataType,
c.max_length,
c.precision,
c.scale,
c.is_nullable
FROM sys.columns AS c
JOIN sys.types AS t ON t.user_type_id = c.user_type_id
WHERE c.object_id = OBJECT_ID(N'dbo.tblEvent')
ORDER BY c.column_id;12. Practice 1: Change DT from DATETIME to DATETIME2(3)
USE [SQF_DB];
GO
ALTER TABLE [dbo].[tblEvent]
ALTER COLUMN [DT] DATETIME2(3) NOT NULL;
GO| Reason | datetime | datetime2(3) |
|---|---|---|
| Fractional seconds | Rounded to .000, .003 or .007 increments | True millisecond precision |
| Date range | 1753 through 9999 | 0001 through 9999 |
| Storage | 8 bytes | 7 bytes |
| New development | Legacy compatibility | Modern recommended type |
Existing datetime values can be represented by datetime2(3). The operational risk is the table alteration itself: a large history table can be locked and generate substantial log activity. Benchmark the migration on a restored copy and schedule an approved maintenance window.
sys.columns reports DT as datetime2 with scale 3 and is_nullable = 0.13. Practice 2: Add an Equipment Foreign Key
Create a small equipment master table, then relate tblEvent.SQF_No to its primary key.
CREATE TABLE [dbo].[Equipment]
(
EquipmentID int IDENTITY(1,1) PRIMARY KEY,
EquipmentName varchar(100) NOT NULL,
IsActive bit NOT NULL
CONSTRAINT DF_Equipment_IsActive DEFAULT (1)
);
GO
INSERT INTO dbo.Equipment (EquipmentName)
VALUES ('SQF-1'), ('SQF-2'), ('SQF-3');
GOBefore adding the foreign key, find orphaned values already present:
SELECT DISTINCT e.SQF_No
FROM dbo.tblEvent AS e
LEFT JOIN dbo.Equipment AS q
ON q.EquipmentID = e.SQF_No
WHERE e.SQF_No IS NOT NULL
AND q.EquipmentID IS NULL;The result must be empty, or the orphan rows must be corrected through an approved data-cleaning rule.
ALTER TABLE [dbo].[tblEvent]
ADD CONSTRAINT FK_tblEvent_Equipment
FOREIGN KEY (SQF_No)
REFERENCES dbo.Equipment(EquipmentID);
GOProve the constraint without retaining test data
BEGIN TRANSACTION;
BEGIN TRY
INSERT INTO dbo.tblEvent (DT, SQF_No, ChargeNo, Fan_Status)
VALUES ('2026-08-04T12:00:00.000', 999, 'CHG-3001', 'ON');
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
ROLLBACK TRANSACTION;SQL Server should return error 547 because equipment 999 does not exist. Repeat in a rolled-back transaction with SQF_No = 1; it should pass the foreign-key check if all other required columns and constraints are satisfied.
14. Practice 3: Decide Between VARCHAR(10) and BIT for Fan_Status
| Decision factor | varchar(10) | bit |
|---|---|---|
| Storage | Up to ten bytes plus row overhead | Several bit columns can share one byte |
| Raw readability | ON/OFF is self-explanatory | Reader must know 1=ON and 0=OFF |
| Integrity | Needs check/reference rule to prevent typos | Only 0, 1 or NULL |
| Future states | Can support FAULT/MAINTENANCE | Restricted to binary |
First inventory the real data:
SELECT Fan_Status, COUNT(*) AS RowCount
FROM dbo.tblEvent
GROUP BY Fan_Status
ORDER BY Fan_Status;If the approved domain is strictly ON/OFF, migrate through a new column:
ALTER TABLE dbo.tblEvent
ADD FanStatusBit bit NULL;
GO
UPDATE dbo.tblEvent
SET FanStatusBit = CASE
WHEN UPPER(LTRIM(RTRIM(Fan_Status))) = 'ON' THEN 1
WHEN UPPER(LTRIM(RTRIM(Fan_Status))) = 'OFF' THEN 0
ELSE NULL
END;
GO
-- Stop if any non-NULL source value failed conversion
IF EXISTS
(
SELECT 1
FROM dbo.tblEvent
WHERE Fan_Status IS NOT NULL
AND FanStatusBit IS NULL
)
THROW 50001, 'Unexpected Fan_Status value; migration stopped.', 1;
GO
ALTER TABLE dbo.tblEvent DROP COLUMN Fan_Status;
EXEC sys.sp_rename
'dbo.tblEvent.FanStatusBit',
'Fan_Status',
'COLUMN';
GO15. Practice 4: Primary, Candidate and Alternate Keys
The reference identifies ID as the chosen surrogate primary key and proposes two natural combinations:
(ChargeNo, DT): one event per charge per timestamp.(SQF_No, DT): one event per furnace per timestamp.
First prove that the current data is unique:
SELECT ChargeNo, DT, COUNT(*) AS DuplicateCount
FROM dbo.tblEvent
GROUP BY ChargeNo, DT
HAVING COUNT(*) > 1;
SELECT SQF_No, DT, COUNT(*) AS DuplicateCount
FROM dbo.tblEvent
GROUP BY SQF_No, DT
HAVING COUNT(*) > 1;An empty result proves only that today's data has no duplicates. The process owner must confirm the future business rule. With millisecond timestamps, two legitimate events can still share the same instant.
ALTER TABLE dbo.tblEvent
ADD CONSTRAINT UQ_tblEvent_Charge_DT
UNIQUE (ChargeNo, DT);
GO
-- Optional only when the plant rule is confirmed
ALTER TABLE dbo.tblEvent
ADD CONSTRAINT UQ_tblEvent_SQFNo_DT
UNIQUE (SQF_No, DT);
GO(ChargeNo, DT) is a true candidate key, define both columns as NOT NULL after cleaning existing NULLs. Otherwise it is not a complete business identity.16. Review the Remaining tblEvent Data Types
| Columns | Current pattern | Review question |
|---|---|---|
TM | varchar(10) | Is it redundant once DT contains date and time? |
Event_From, Event_To | varchar(100) | Should these reference a controlled process-stage table? |
Temp_Set, Temp_Act | float | Is approximate binary floating point acceptable, or is fixed decimal required? |
Cp_Set, Cp_Act | float | What precision/scale matches instrument and report resolution? |
Oil_Set/Act, Jacket_Set/Act | float | What are validated engineering ranges and NULL meanings? |
ChargeNo | varchar(50) | Is it non-Unicode by contract, unique per plant, and mandatory? |
Do not change these columns merely for uniformity. Capture actual values, client parameter types, report calculations and process rules before selecting new types.
17. Use a Safe Migration Sequence
- Back up and prove restore on a non-production copy.
- Record row count, table size, constraints, indexes and dependent objects.
- Profile NULLs, duplicates, orphan equipment and status values.
- Create/reference master data before the foreign key.
- Run alterations in a tested maintenance window.
- Validate row counts, constraints, query results and application writes.
- Retain a reviewed rollback or restore decision point.
Large table alterations can be fully logged and blocking. Measure duration and log growth using a production-sized restored copy.
18. Verify the Final Data Types and Keys
SELECT
c.name AS ColumnName,
t.name AS DataType,
c.max_length,
c.precision,
c.scale,
c.is_nullable
FROM sys.columns AS c
JOIN sys.types AS t ON t.user_type_id = c.user_type_id
WHERE c.object_id = OBJECT_ID(N'dbo.tblEvent')
AND c.name IN (N'ID', N'DT', N'SQF_No', N'ChargeNo', N'Fan_Status');
SELECT
kc.name AS KeyName,
kc.type_desc
FROM sys.key_constraints AS kc
WHERE kc.parent_object_id = OBJECT_ID(N'dbo.tblEvent');
SELECT fk.name AS ForeignKeyName
FROM sys.foreign_keys AS fk
WHERE fk.parent_object_id = OBJECT_ID(N'dbo.tblEvent');19. Migration Troubleshooting
| Problem | Cause | Correction |
|---|---|---|
| ALTER COLUMN blocks | Large table or long concurrent transactions | Test duration, stop conflicting workload and use an approved window |
| Foreign key creation fails | Orphan SQF_No values | Run the orphan query and correct/map rows before adding the FK |
| BIT migration produces NULL | Unexpected text or spaces/case variants | Profile all values; do not drop the source until every row is resolved |
| UNIQUE constraint fails | Duplicate ChargeNo/DT or SQF_No/DT | Investigate business meaning; do not delete duplicates blindly |
| Valid events are rejected later | Natural key rule was too strict for millisecond events | Revise business identity, perhaps using source event ID or sequence |
| Application insert fails | Client still sends old text/type or invalid equipment | Update parameters and deploy database/application changes together |
Complete Practice Checklist: tblEvent
Reference lab- Use a disposable restored database.
- Capture starting schema and row counts.
- Do not run the migration against a live WinCC history database.
Modernize DT
Change DT to datetime2(3) NOT NULL and verify scale.
Enforce equipment identity
Create Equipment, clean orphans, add the FK and run rolled-back good/bad inserts.
Migrate Fan_Status
Profile states, confirm binary behavior and migrate through a new bit column.
Prove candidate keys
Run duplicate queries and obtain process-owner approval before adding uniqueness.
Reference Exercise Summary
| Exercise | Concept reinforced |
|---|---|
| 1 | Choosing date/time precision and a modern SQL type |
| 2 | Foreign keys and referential integrity |
| 3 | Storage, readability, integrity and extensibility tradeoffs |
| 4 | Primary, candidate and alternate keys |
Frequently Asked Questions
Why change DT to datetime2(3)?
It provides true millisecond precision, a wider range and seven-byte storage while avoiding legacy datetime rounding increments.
Can I add the foreign key when data already exists?
Only after every non-NULL SQF_No matches Equipment. Find and resolve orphaned rows first.
Should Fan_Status be bit or varchar?
Use bit only for a permanently binary ON/OFF state. Use a constrained status code/reference table if more states are valid.
Is ChargeNo plus DT always a candidate key?
No. The plant must guarantee one event per charge at the timestamp precision and both columns should be mandatory.
Can ALTER COLUMN lock the table?
Yes. Test on production-sized data and schedule backup, log capacity, downtime and rollback appropriately.
