-- Natural key: ISO country code is stable, short, and genuinely unique
-- by international standard -- a reasonable case for using it directly
-- as the primary key rather than adding a surrogate.
CREATE TABLE countries (
iso_code CHAR(2) NOT NULL PRIMARY KEY, -- e.g. 'US', 'SG'
name VARCHAR(80) NOT NULL
) ENGINE=InnoDB;
-- Surrogate key (AUTO_INCREMENT) as PRIMARY KEY, natural key (sku) kept
-- as a UNIQUE constraint -- the common hybrid approach.
CREATE TABLE products (
product_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sku CHAR(10) NOT NULL, -- business/natural key
name VARCHAR(120) NOT NULL,
UNIQUE KEY uq_products_sku (sku)
) ENGINE=InnoDB;
-- Foreign keys elsewhere reference the narrow surrogate, not the sku:
CREATE TABLE order_items (
order_id INT UNSIGNED NOT NULL,
product_id INT UNSIGNED NOT NULL,
quantity INT UNSIGNED NOT NULL,
PRIMARY KEY (order_id, product_id),
CONSTRAINT fk_order_items_product
FOREIGN KEY (product_id) REFERENCES products (product_id)
) ENGINE=InnoDB;
-- Surrogate key (UUID), stored compactly as BINARY(16). Useful when IDs
-- must be generated client-side, before any row exists in the database
-- (e.g. offline mobile clients, multi-service systems).
CREATE TABLE sessions (
session_id BINARY(16) NOT NULL PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO sessions (session_id, user_id)
VALUES (UUID_TO_BIN(UUID(), 1), 42); -- swap flag=1: time-ordered bytes first
SELECT BIN_TO_UUID(session_id, 1) AS session_id, user_id
FROM sessions
WHERE user_id = 42;
-- GIPK: table created with no explicit primary key.
SET sql_generate_invisible_primary_key = ON;
CREATE TABLE audit_log (
event_name VARCHAR(80) NOT NULL,
logged_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- MySQL silently added an invisible my_row_id BIGINT UNSIGNED AUTO_INCREMENT
-- primary key; SHOW CREATE TABLE audit_log; reveals it. Make it visible:
ALTER TABLE audit_log ALTER COLUMN my_row_id SET VISIBLE;
-- Natural key: ISO country code is stable, short, and genuinely unique
-- by international standard -- a reasonable case for using it directly
-- as the primary key rather than adding a surrogate.
CREATE TABLE countries (
iso_code CHAR(2) NOT NULL PRIMARY KEY, -- e.g. 'US', 'SG'
name VARCHAR(80) NOT NULL
) ENGINE=InnoDB;
-- Surrogate key (AUTO_INCREMENT) as PRIMARY KEY, natural key (sku) kept
-- as a UNIQUE constraint -- the common hybrid approach.
CREATE TABLE products (
product_id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
sku CHAR(10) NOT NULL, -- business/natural key
name VARCHAR(120) NOT NULL,
UNIQUE KEY uq_products_sku (sku)
) ENGINE=InnoDB;
-- Foreign keys elsewhere reference the narrow surrogate, not the sku:
CREATE TABLE order_items (
order_id INT UNSIGNED NOT NULL,
product_id INT UNSIGNED NOT NULL,
quantity INT UNSIGNED NOT NULL,
PRIMARY KEY (order_id, product_id),
CONSTRAINT fk_order_items_product
FOREIGN KEY (product_id) REFERENCES products (product_id)
) ENGINE=InnoDB;
-- Surrogate key (UUID), stored compactly as BINARY(16). Useful when IDs
-- must be generated client-side, before any row exists in the database
-- (e.g. offline mobile clients, multi-service systems).
CREATE TABLE sessions (
session_id BINARY(16) NOT NULL PRIMARY KEY,
user_id INT UNSIGNED NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
INSERT INTO sessions (session_id, user_id)
VALUES (UUID_TO_BIN(UUID(), 1), 42); -- swap flag=1: time-ordered bytes first
SELECT BIN_TO_UUID(session_id, 1) AS session_id, user_id
FROM sessions
WHERE user_id = 42;
-- GIPK: table created with no explicit primary key.
SET sql_generate_invisible_primary_key = ON;
CREATE TABLE audit_log (
event_name VARCHAR(80) NOT NULL,
logged_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
-- MySQL silently added an invisible my_row_id BIGINT UNSIGNED AUTO_INCREMENT
-- primary key; SHOW CREATE TABLE audit_log; reveals it. Make it visible:
ALTER TABLE audit_log ALTER COLUMN my_row_id SET VISIBLE;