AD JB Toolbox 01 EN

MariaDB Tutorial / Define Input Rules with NULL, DEFAULT, NOT NULL, and CHECK

NULL represents missing or unknown information and differs from zero or an empty string. DEFAULT supplies a value when an input is omitted, NOT NULL rejects NULL, and CHECK tests a value against a condition; combine them because each solves a different validation problem.

Separate NULL, an empty string, zero, and omission

Input state Meaning Example
NULL Missing, unknown, or not yet determined No note has been collected
Empty string '' A known string of length zero A note was submitted without text
0 The numeric value zero No units in stock
Column omitted Not listed in the INSERT column list The stock default supplies zero

A business may choose to treat an uncollected note and an empty note alike, but that is a data policy. Automatically replacing every NULL with an empty string removes the ability to distinguish those states. This exercise uses ordinary string handling and does not enable compatibility modes such as EMPTY_STRING_IS_NULL. Distinguish these rules from uniqueness in Identify Rows with PRIMARY KEY, AUTO_INCREMENT, and UNIQUE and from querying stored NULL values in Compare NULL Correctly with IS NULL and COALESCE.

Most ordinary comparisons with NULL produce an unknown result, represented by NULL, rather than true or false. Use IS NULL to test for it, not = NULL. The NULL-value reference explains the operators and exceptions.

Use each constraint for its own responsibility

Definition What it does What it does not guarantee
DEFAULT 0 Provides zero when the column is omitted or DEFAULT is requested Does not generally replace every explicitly supplied NULL
NOT NULL Rejects a missing-value marker Does not prohibit an empty string, zero, or every negative value
CHECK (stock >= 0) Rejects a false nonnegative-stock condition Does not itself reject NULL on a nullable column
NOT NULL with CHECK Requires a value and checks its condition Does not replace application feedback or review of existing data

Do not use a default to invent unknown information. If stock has not been counted, zero may incorrectly mean sold out. This example deliberately defines a new item’s initial stock as zero; another business may need NULL or an independent verification status.

Application checks can provide useful messages, while database constraints protect the storage boundary when another application, client, or SQL file writes data. Both layers have a purpose; validating only the visible form does not constrain every writer.

Run a complete example of defaults and nullable values

Connect as course_user to the practice server prepared in the installation guides, with the shopcourse database available. The command-line client and SQL-file guide explains the connection and SOURCE command. Run these checks inside that connection, not in the operating-system shell:

SELECT VERSION() AS server_version, DATABASE() AS selected_database;
USE shopcourse;
SELECT DATABASE() AS selected_database;

The selected database should be shopcourse. Save a complete normal example as a UTF-8 .sql file and run it with SOURCE and its actual local path. Keep the intentionally failing statements separate: an error can stop a source file. Use a learning instance, not a connection containing production data.

The normal file inserts only valid rows. It saves the session mode and CHECK setting, then explicitly enables strict mode and CHECK evaluation. Check the actual server version when working with old installations rather than assuming that accepting CHECK syntax always proves enforcement.

USE shopcourse;
SET @saved_sql_mode = @@SESSION.sql_mode;
SET @saved_check_constraints = @@SESSION.check_constraint_checks;
SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
SET SESSION check_constraint_checks = ON;
CREATE TABLE validation_lab (
  item_id INT PRIMARY KEY,
  item_name VARCHAR(100) NOT NULL,
  note VARCHAR(100) NULL DEFAULT NULL,
  stock INT NOT NULL DEFAULT 0,
  CONSTRAINT ck_validation_stock CHECK (stock >= 0)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO validation_lab (item_id, item_name, note) VALUES
  (1, 'Notebook', NULL),
  (2, 'Mug', '');
SELECT item_id, note IS NULL AS note_is_null,
       note = '' AS note_is_empty, stock
FROM validation_lab ORDER BY item_id;
CREATE TABLE nullable_check_lab (
  item_id INT PRIMARY KEY,
  stock INT NULL,
  CONSTRAINT ck_nullable_stock CHECK (stock >= 0)
) ENGINE=InnoDB;
INSERT INTO nullable_check_lab VALUES (1, NULL);
SELECT item_id, stock IS NULL AS stock_is_null FROM nullable_check_lab;
Row note_is_null note_is_empty stock
1 1 NULL 0
2 0 1 0

The first note is NULL, so its comparison with an empty string is also NULL. The second note is an empty string, making IS NULL false and the empty-string comparison true. Both inserts omit stock, so both receive the default zero.

The separate nullable_check_lab accepts a NULL stock value. Its CHECK expression does not evaluate to false for NULL. If stock must always be known and nonnegative, specify NOT NULL as well as CHECK; a nonnegative comparison alone is insufficient.

Test NOT NULL and CHECK failures separately

After the valid example, execute these statements one at a time. The first supplies NULL for a required name; the second supplies a name but violates the nonnegative-stock constraint:

INSERT INTO validation_lab (item_id, item_name) VALUES (3, NULL);
INSERT INTO validation_lab (item_id, item_name, stock) VALUES (3, 'Desk lamp', -1);

Expect a cannot-be-null error for the first and a constraint failure identifying the stock rule for the second. After each, SELECT COUNT(*) FROM validation_lab; should remain two. The failed item identifier 3 was not saved, so it can be reused in the second failure test. Exact error wording can vary by version and output language; identify the column or constraint that failed.

A default, the input form, and the type’s rules determine whether an explicit NULL is allowed, rejected, or handled specially. AUTO_INCREMENT and TIMESTAMP have special NULL behavior in some cases, so do not generalize this ordinary note-and-stock example to every type.

Inspect blank values, named rules, and enforcement settings

A NOT NULL string may still contain an empty string, as the string-type discussion explains. A rule such as CHECK (CHAR_LENGTH(TRIM(item_name)) > 0) can additionally reject empty names and names consisting of ordinary spaces. Do not assume default TRIM behavior removes every Unicode whitespace character or invisible glyph.

SHOW CREATE TABLE validation_lab;
SELECT @@SESSION.sql_mode, @@SESSION.check_constraint_checks;

The name ck_validation_stock makes a failed rule easier to locate. Use meaningful names that identify the table, column, or condition, and check naming scope when supporting different server versions. The constraint reference documents CHECK syntax and enforcement controls.

Disabling check_constraint_checks can permit data that violates the declared checks. Fix the input or the intended rule instead of disabling validation merely to make a write succeed. Switching checks on also does not mean that every previously stored invalid row has been reviewed or repaired.

Restore settings and repeat only the disposable exercise

SET SESSION check_constraint_checks = @saved_check_constraints;
SET SESSION sql_mode = @saved_sql_mode;

Restore these session settings in the same connection that saved the variables. If you disconnected, those variables no longer contain the original values; inspect the new connection instead of applying an empty saved variable.

Before repeating the exercise, use SELECT DATABASE(); and SHOW CREATE TABLE table_name;, substituting each actual table name, to confirm that the targets are the disposable tables created here. Back up any data you need to keep. Only after verifying those targets, remove them with:

DROP TABLE shopcourse.validation_lab, shopcourse.nullable_check_lab;

This removes both the named tables and their rows. A data-definition statement such as DROP TABLE is not undone by an ordinary ROLLBACK. You can then rerun the complete normal example. The existing products table from the first product-table exercise is deliberately outside this reset.

More in This Category
MariaDB Tutorial / Schedule Database Tasks and Verify Event Results

MariaDB Tutorial / Schedule Database Tasks and Verify Event Results

Create a disabled one-time event, reschedule it into the future, and verify both execution metadata and its result row. Understand recurring-task overlap, retries, privileges, time zones, and cleanup.

MariaDB Tutorial / Create a Database with CREATE DATABASE, USE, and utf8mb4

MariaDB Tutorial / Create a Database with CREATE DATABASE, USE, and utf8mb4

Create a practice database with explicit utf8mb4 settings and verify its definition. Understand connection-local database selection, collation comparisons, and why IF NOT EXISTS preserves existing defaults.

MariaDB Tutorial / Choose String Types: CHAR, VARCHAR, and TEXT

MariaDB Tutorial / Choose String Types: CHAR, VARCHAR, and TEXT

Compare CHAR, VARCHAR, and TEXT with runnable Unicode and trailing-space examples. Check character counts versus byte counts, length errors, comparison rules, and the optional TEXT(M) syntax.

MariaDB Tutorial / Back Up an InnoDB Database with mariadb-dump

MariaDB Tutorial / Back Up an InnoDB Database with mariadb-dump

Create a scoped mariadb-dump backup with explicit consistency and file options. Check errors and hashes, inventory additional objects and define a separate-database restoration baseline.

MariaDB Tutorial / Normalize an Order Database Without Losing Historical Facts

MariaDB Tutorial / Normalize an Order Database Without Losing Historical Facts

Analyze order-data dependencies and observe an update anomaly in a flattened copy. Separate current attributes from transaction snapshots and review keys, normal forms and deliberate denormalization.

MariaDB Tutorial / Change Table Structure Safely with ALTER TABLE

MariaDB Tutorial / Change Table Structure Safely with ALTER TABLE

Practice an add-fill-constrain migration with a product SKU column, verify counts and rejected duplicates, and review metadata locks, online-change limits and recovery boundaries.

MariaDB Tutorial / Query Hierarchies and Prevent Cycles with Recursive CTEs

MariaDB Tutorial / Query Hierarchies and Prevent Cycles with Recursive CTEs

Traverse a complete category tree with WITH RECURSIVE, depth, and path tracking. Change the traversal bound, introduce a controlled cycle, and distinguish a finite result from a complete and valid hierarchy.

MariaDB Tutorial / Install MariaDB on Ubuntu and Start the Server

MariaDB Tutorial / Install MariaDB on Ubuntu and Start the Server

Install MariaDB on Ubuntu with APT, distinguish service activity from automatic startup, and understand socket authentication. Create a restricted TCP learning account and diagnose connection or service problems.

MariaDB Tutorial / Break Queries into Named Steps with WITH and CTEs

MariaDB Tutorial / Break Queries into Named Steps with WITH and CTEs

Build a readable multi-step query with WITH, verify paid orders and per-order totals independently, and understand CTE scope, naming and execution-plan limitations.

MariaDB Tutorial / Connect with the Command-Line Client and Run SQL Files

MariaDB Tutorial / Connect with the Command-Line Client and Run SQL Files

Connect to MariaDB with explicit TCP and UTF-8 settings, check account and query results, and execute a complete SQL file with SOURCE. Learn how to diagnose path, encoding, and partial-execution errors.