SQL CREATE TABLE: Creating Tables and Changing Data

Learn to build your own database tables and change the data in them safely. Write CREATE TABLE statements with sensible data types, protect the data with NOT NULL, UNIQUE, CHECK, primary keys and foreign keys, and add, change and remove rows with INSERT, UPDATE and DELETE. Practice targeting exactly the right rows, group related changes in transactions you can commit or roll back, and change or remove tables with ALTER TABLE and DROP TABLE. Examples use standard SQL that runs on SQLite and PostgreSQL, with differences in MySQL, SQL Server and Oracle pointed out where they matter.

BeginnerLesson 6 of 6 in SQL Basics Course

What you will learn

  1. Write CREATE TABLE statements that define a table and its columns, and choose a data type for each column that fits the values it will hold.
    • Write a CREATE TABLE statement
      Define a new table with named columns, check its structure, and avoid the syntax errors beginners make most often.
    • Choose a data type for each column
      Pick integer, exact decimal, floating-point, text, date and true/false types for the values a column holds, and know how SQLite's flexible typing differs from stricter databases.
  2. Use constraints so that the database itself rejects missing, duplicate, out-of-range and unmatched values, and give every row a reliable key.
    • Require, default and limit values with NOT NULL, DEFAULT, UNIQUE and CHECK
      Declare the column and table rules that keep values present, distinct and within range, and predict which inserts a rule will reject.
    • Identify rows with primary keys and generated IDs
      Declare single-column and composite primary keys, let the database number new rows, and know what generated IDs do and do not promise in each database system.
    • Link tables with foreign keys
      Declare foreign keys that keep references between tables valid, choose what happens when a referenced row is deleted, and switch on enforcement where it is off.
  3. Add new rows with INSERT, one at a time, several at once or copied from a query, and handle generated keys and duplicates.
    • Insert rows with VALUES
      Write INSERT ... VALUES statements with a column list and correctly written text, numbers, dates and NULL, and read the errors that stop an insert.
    • Insert from queries, return new keys and handle duplicates
      Copy rows with INSERT ... SELECT, read back generated values with RETURNING, and decide what happens when an inserted row collides with an existing one.
  4. Change values with UPDATE and remove rows with DELETE, and make sure each statement affects exactly the rows intended.
    • Change values with UPDATE
      Write UPDATE statements that set one or more columns, calculate new values from old ones, and stay within the table's constraints.
    • Remove rows with DELETE
      Remove chosen rows with DELETE, tell DELETE, TRUNCATE and DROP TABLE apart, and decide when marking a row as deleted is better than removing it.
    • Target exactly the rows you mean
      Build WHERE conditions for changes that match the intended rows and no others, and check the result before keeping it.
  5. Use transactions so that a group of related changes is kept as a whole or undone as a whole, and recover cleanly when a statement fails.
    • Commit or roll back a group of changes
      Start a transaction, keep its changes with COMMIT or undo them with ROLLBACK, and understand autocommit.
    • Handle errors, savepoints and structure changes in a transaction
      Respond correctly when a statement fails inside a transaction, undo part of a transaction with a savepoint, and know which databases can roll back CREATE, ALTER and DROP.
  6. Change the structure of existing tables without losing their rows, and remove tables safely when they are no longer needed.
    • Add, rename and remove columns with ALTER TABLE
      Use ALTER TABLE to add, rename and drop columns and to change types and constraints, and work around the limits of SQLite.
    • Remove tables with DROP TABLE
      Remove tables with DROP TABLE, respect the dependencies between tables, and choose between dropping, emptying and deleting.

SQL CREATE TABLE study guide

6 chapters

1

Create tables with suitable column types

A table needs a clear structure before it can hold useful data. Start with the facts one row records, give each fact a name, and choose how the database will store it. You will build an empty table, inspect what was actually created, and distinguish a number used for calculation from text that merely looks numeric. SQLite and PostgreSQL share much of the syntax, but their type rules can produce very different results.

1.1 Write a CREATE TABLE statement

A table definition describes what each row can hold. It does not add any rows. In an online shop, each product needs separate fields for its identifier, name, price and stock count.

Build the definition
CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  price NUMERIC(8, 2) NOT NULL,
  in_stock INTEGER DEFAULT 0
);

Read from the outside in. CREATE TABLE products names the new table. Parentheses contain its column definitions. Each line gives a column name, a type and any rules for that column. Commas separate definitions; the last definition has no comma. The semicolon ends the statement. After it succeeds, SELECT * FROM products; returns zero rows.

This key declaration generates IDs in SQLite. In PostgreSQL, use id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY to generate them. The decimal declaration also behaves differently across these systems; choosing exact storage is part of choosing a type.

Give each fact its own column

A customer row could contain id, first_name, last_name, email and signup_date. Packing "Ana Ruiz, ana@example.com" into one field makes the name and email difficult to search or check separately. Name the fields for what they contain. Short lowercase names joined with underscores, such as unit_price, are easy to reuse.

Avoid keywords as names: orders works, while unquoted order conflicts with SQL's ORDER keyword. A name containing spaces needs double quotes, as in "order date", each time you use it. PostgreSQL folds unquoted names to lowercase, so unquoted Products and products refer to the same name.

Single quotes have another job: they enclose text values such as 'Desk lamp'. Double quotes identify names. PostgreSQL reads "Desk lamp" as a column name, not as product text.

Check what was created

A trailing comma before ) causes a syntax error. A missing comma often does too, but SQLite can read several words as one type name. CREATE TABLE t (a INTEGER b TEXT); creates one column called a, not two columns. Inspect the definition:

  • SQLite shell: .schema products prints the creation statement.
  • SQLite SQL: PRAGMA table_info(products); lists columns and types.
  • PostgreSQL psql: \d products shows columns, types and constraints.

CREATE TABLE IF NOT EXISTS products (...) avoids an error when the name is already present. It does not compare or update the old definition. A table missing a needed column stays that way.

Create a one-time copy
CREATE TABLE cheap_products AS
SELECT name, price FROM products WHERE price < 10;

This creates columns and copies the query's rows. Later product changes do not refresh the copy. In SQLite and PostgreSQL, the new table does not inherit the source's primary key, NOT NULL or CHECK rules.

CREATE, ALTER and DROP belong to data definition language, or DDL: they change structure. INSERT, UPDATE and DELETE are data manipulation language, or DML: they change rows. SELECT reads data; books differ on whether they include it in DML or give queries their own family.

Key Takeaways

  • Column definitions contain a name, type and optional rules.
  • Use commas between definitions, with no trailing comma.
  • Single quotes enclose text; double quotes enclose identifiers.
  • Inspect the resulting structure, including after an IF NOT EXISTS statement.
  • CREATE TABLE AS copies query data without copying the source constraints.

1.2 Choose a data type for each column

Choose a type from the job the value must do. A quantity must support arithmetic. A ZIP code must preserve its characters, including leading zeros. Both can contain digits, but they need different storage.

Choose number and text types
ValuesUseful typeReason
Whole countsINTEGERCounts have no fractional part.
Exact money in PostgreSQLNUMERIC(p, s)Decimal arithmetic preserves exact amounts.
Exact money in SQLiteINTEGER centsWhole cents avoid floating-point storage.
MeasurementsREAL or DOUBLE PRECISIONApproximate values suit measured quantities.
Names and codesTEXT or VARCHAR(n)Characters and leading zeros are preserved.

In PostgreSQL, NUMERIC(8, 2) has eight total digits, two after the decimal point. Its largest positive value is 999999.99. Inserting 12.345 stores 12.35; 1234567.00 overflows because it needs seven digits before the point. DECIMAL is another name for this type family.

SQLite accepts NUMERIC(8, 2) but does not enforce that precision or scale. It stores 19.99 as floating point and keeps 12.345 unrounded. Store 1999 whole cents for an exact amount of 19.99. Floating point approximates binary fractions: SQLite's SELECT 0.1 + 0.2 = 0.3; returns 0. PostgreSQL treats those bare decimal literals as exact numeric values; cast them to DOUBLE PRECISION to see the approximate result.

Text numbers sort by characters: '100', '25', '9' appear in that order. Numeric quantities need numeric columns. ZIP code '02139' belongs in text; integer storage loses its initial zero.

PostgreSQL's VARCHAR(20) rejects text longer than 20 characters. Its CHAR(n) pads shorter text with spaces to a fixed length. TEXT has no declared character limit. SQLite treats both VARCHAR(n) and CHAR(n) as text, without enforcing the length or adding padding.

Store dates and yes/no values

PostgreSQL has DATE, TIME, TIMESTAMP and BOOLEAN. It rejects an impossible DATE such as '2026-02-30'. SQLite has no dedicated date storage type. Use ISO text such as '2026-03-15', whose character order matches date order. US-style text misorders dates across years: '12/01/2025' sorts after '03/15/2026'.

A timestamp adds a time, such as '2026-03-15 14:30:00'. PostgreSQL uses TRUE and FALSE for Booleans; SQLite stores 1 and 0 and accepts those keywords. MySQL treats BOOLEAN as a small integer; SQL Server uses BIT.

Know what the system enforces

Ordinary SQLite tables use type affinity, a storage preference. An INTEGER column converts '5' to 5 but accepts 'abc' as text. PostgreSQL rejects text that cannot become an integer. SQLite 3.37.0 and later support STRICT tables, whose permitted types are INT, INTEGER, REAL, TEXT, BLOB and ANY.

For orders, choose an integer id, text email, a PostgreSQL DATE or SQLite ISO text date, PostgreSQL NUMERIC(10, 2) or SQLite integer cents for the total, and a Boolean or 0/1 flag for payment. NULL means missing or unknown; it is neither a type nor the same as zero or empty text. A column accepts it unless a rule forbids it.

Key Takeaways

  • Choose types by use: arithmetic, text, time or yes/no.
  • NUMERIC precision counts all digits; scale counts decimal places.
  • Use PostgreSQL NUMERIC or SQLite integer cents for exact money.
  • ISO date text sorts by date when written consistently.
  • SQLite affinity permits mixed storage; STRICT strengthens type checks.
  • NULL marks a missing or unknown value.
2

Protect data with constraints

A database can check rules at the moment data changes, whichever program sends the change. Column rules control missing values, duplicates and ranges; keys identify rows and keep links between tables valid. You will follow accepted and rejected inserts, choose generated IDs, and predict what happens to orders when a customer is removed. These rules work together: a check on price does a different job from a requirement that price be present.

2.1 Require, default and limit values with NOT NULL, DEFAULT, UNIQUE and CHECK

A constraint makes the database reject data that breaks a declared rule. The check runs when rows are inserted or updated, no matter which application sends the statement. Different rules protect different parts of a product record.

Combine rules in a table

This SQLite definition generates the key and checks the other fields. For PostgreSQL, replace the key line with an identity primary key.

CREATE TABLE products (
  id INTEGER PRIMARY KEY,
  sku TEXT NOT NULL UNIQUE,
  name TEXT NOT NULL,
  price NUMERIC(8, 2) NOT NULL CHECK (price > 0),
  in_stock INTEGER NOT NULL DEFAULT 0 CHECK (in_stock >= 0)
);

NOT NULL requires a value. UNIQUE prevents a repeated SKU. CHECK (price > 0) rejects zero or negative prices. The stock count has a default of 0 and must stay nonnegative. SQLite's numeric declaration does not give it exact decimal arithmetic, so use integer cents when exactness matters.

Distinguish omission from NULL

Insert a desk lamp with SKU 'LAMP-01', name 'Desk lamp' and price 24.99, leaving stock out of the column list. It succeeds and gets stock 0. A supplied NULL stock does not request the default: it fails NOT NULL.

A coffee mug priced at -3.50 fails the price check. A second product with SKU 'LAMP-01' fails UNIQUE, even if its name and price differ. A pen with no name fails NOT NULL. Read the named rule or column in the error and correct the input.

Empty text is a real value. name TEXT NOT NULL accepts '' in SQLite and PostgreSQL. Add CHECK (name <> '') to reject it. Oracle treats empty text as NULL, so the same input meets a different rule there.

Check combinations and missing values

A column rule follows its type. A table rule is a separate item inside the table definition and can compare columns:

CHECK (end_date >= start_date),
UNIQUE (order_id, product_id)

The first rejects an end date before a start date. The second rejects a repeated pair: a product can occur in different orders, but cannot appear twice in the same order. A table may have several unique constraints.

A check rejects a row when its condition is false. If price is NULL, price > 0 is unknown, so the check passes. That is why the product price also needs NOT NULL. PostgreSQL, SQLite and MySQL normally allow multiple NULLs under UNIQUE; SQL Server allows one in a single-column unique constraint. PostgreSQL 15 and later offer UNIQUE NULLS NOT DISTINCT when missing values must conflict too. MySQL versions before 8.0.16 ignored CHECK rules.

Give a rule a useful name with CONSTRAINT price_positive CHECK (price > 0). The name helps identify it in an error and remove it later. A constraint checks exactly its expression: CHECK (email LIKE '%@%') catches a missing at sign but cannot catch a typo in an otherwise matching address.

Key Takeaways

  • NOT NULL rejects missing values but does not reject empty text in SQLite or PostgreSQL.
  • DEFAULT fills omitted columns; an explicit NULL does not request it.
  • UNIQUE can protect a column or a combination of columns.
  • CHECK rejects false conditions; add NOT NULL when unknown must also be rejected.
  • Constraint errors identify data that needs correction.

2.2 Identify rows with primary keys and generated IDs

A primary key identifies one row reliably. It can be one column or a combination, but a table has at most one primary key. The key must be unique and present, so other statements can name a row without depending on its description.

Choose a stable identifier

A natural key is an existing real-world identifier, such as a book's ISBN. A surrogate key is an artificial identifier, often a generated integer. A customer's email can change; a generated customer ID can stay the same while that happens.

A composite key identifies a combination:

PRIMARY KEY (order_id, product_id)

An order can contain several products, and a product can occur in several orders. The pair identifies one order item. Neither column needs to be unique by itself.

PostgreSQL, MySQL and SQL Server enforce nonmissing primary keys. Ordinary SQLite tables retain a historical exception: a primary key other than INTEGER PRIMARY KEY can contain NULL. Use code TEXT PRIMARY KEY NOT NULL for a text key. SQLite STRICT tables close this gap too.

Let the database generate the number
DatabaseGenerated primary key declaration
SQLiteid INTEGER PRIMARY KEY
PostgreSQLid INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
MySQLid INT AUTO_INCREMENT PRIMARY KEY
SQL Serverid INT IDENTITY(1, 1) PRIMARY KEY

Leave id out of the insert's column list to request a generated value. A plain PostgreSQL INTEGER PRIMARY KEY does not generate one. Older PostgreSQL code often uses SERIAL.

In SQLite, INTEGER PRIMARY KEY aliases the internal row number. Start with generated IDs 1, 2 and 3, then delete 3. The next normal generated ID is 3 again, one above the current maximum. With INTEGER PRIMARY KEY AUTOINCREMENT, it is 4: a number held by a committed row is not reused. A number from a rolled-back insert can still be reused. This stronger guarantee costs extra work, so choose it when the no-reuse requirement matters.

Read IDs without treating them as counts

Gaps are normal. Deletions leave them, and PostgreSQL does not return sequence numbers after failed or rolled-back inserts. Use COUNT(*) for a row count and a timestamp for event time. The largest ID answers neither question reliably.

PostgreSQL's GENERATED ALWAYS form normally rejects an explicit ID such as 50. GENERATED BY DEFAULT and SERIAL accept explicit values, but supplying 50 does not move the generator past 50. A later generated value can collide with it.

To use a new row's key in a related row, read the key back:

INSERT INTO customers (first_name, last_name, email)
VALUES ('Dev', 'Patel', 'dev@example.com')
RETURNING id;

RETURNING works in PostgreSQL and SQLite 3.35.0 and later. SQLite also offers last_insert_rowid(), MySQL offers LAST_INSERT_ID(), and SQL Server uses OUTPUT. Read the result of the insert instead of guessing the next ID.

Key Takeaways

  • A primary key identifies a row; a composite key identifies a combination.
  • Generated keys use different declarations in different databases.
  • SQLite AUTOINCREMENT prevents reuse of committed IDs, with extra cost.
  • ID gaps are normal; use COUNT(*) to count rows.
  • RETURNING reads the actual generated key.

An order's customer_id should point to a customer who exists. A foreign key makes the database check that link. The table holding the reference is the child; the table it points to is the parent.

Declare and enforce the link
CREATE TABLE orders (
  id INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL REFERENCES customers(id)
);

Here customers must exist first, and its id must be a primary key or unique key. Match the types on both sides. The table form, FOREIGN KEY (customer_id) REFERENCES customers(id), declares the same link separately from the column.

With enforcement on, an order for customer 99 fails when no customer 99 exists. Updating an order to that missing customer also fails. A nullable foreign key can hold NULL, meaning no linked row; NOT NULL makes the link required.

In SQLite, run PRAGMA foreign_keys = ON; on each new connection before starting a transaction. A setting change inside a transaction has no effect. PostgreSQL and SQL Server enforce foreign keys normally, and MySQL's default InnoDB engine does too.

Predict a parent deletion

Use customers 1, Ana, and 2, Ben. Orders 101 and 102 belong to Ana; 103 belongs to Ben. Consider deleting customer 1 under different declarations:

ON DELETE actionResult
NO ACTION or RESTRICTThe delete fails while 101 and 102 refer to Ana.
CASCADEAna, 101 and 102 are removed; Ben and 103 remain.
SET NULLAna is removed; all orders remain, with 101 and 102 unlinked.
SET DEFAULTThe referencing values become their declared default.

SET NULL needs a nullable column. SET DEFAULT still has to satisfy the foreign key: a nonmissing default must identify an existing parent. A NULL default works when missing links are allowed.

Choose by the meaning of the data. Order items often belong entirely to their order, so cascading can fit. Orders that must be retained call for a blocking action when someone tries to remove their customer. An optional supplier link can be set to NULL. Applying cascades everywhere lets one delete remove more records than its table name suggests.

Work in dependency order

Create parents before children and insert parent rows before rows that refer to them. When removing related data or tables, work from children to parents. An ON UPDATE action offers the same choices when the parent's key changes; ON UPDATE CASCADE copies the new key to the children.

RESTRICT checks immediately. NO ACTION, the default, can wait until the statement ends, or until transaction end for a deferrable constraint. Both block an ordinary delete that would leave unmatched references. Keep generated IDs stable so that changing a customer's details does not require changing every reference to that customer.

Key Takeaways

  • A foreign key links child values to an existing primary or unique parent key.
  • NULL permits an optional link unless NOT NULL forbids it.
  • CASCADE deletes children; SET NULL keeps them without their link.
  • Enable SQLite foreign keys before BEGIN on each connection.
  • Create and insert parents first; delete and drop children first.
  • Choose actions from the records that must be kept.
3

Add rows with INSERT

Adding rows means matching each value to the right column and letting the database check the result. A product can be entered directly, several customers can be added together, and older orders can be copied from a query. You will also read back a generated key and choose how to handle an existing SKU. The same input can mean a replacement stock count or an extra delivery, so an upsert must express the intended change precisely.

3.1 Insert rows with VALUES

INSERT adds rows to an existing table. Its column list is the map between the values you supply and the fields that receive them. Write the map explicitly so that a later table change does not silently change your input's meaning.

Match values by position
INSERT INTO products (sku, name, price, in_stock)
VALUES ('LAMP-01', 'Desk lamp', 24.99, 12);

Read the pairs in order: SKU gets 'LAMP-01', name gets 'Desk lamp', price gets 24.99 and stock gets 12. There must be four values for these four columns. A mismatch such as two values for three columns fails.

Without the list, values follow the table's declared column order. SQLite requires all columns to be supplied; PostgreSQL allows fewer and defaults the trailing columns. An explicit list avoids relying on either behavior. It also lets you put columns in an order that is clear for the input.

A swapped pair can be worse than a syntax error. Supplying 9.99 as the name and 'Desk lamp' as price makes PostgreSQL reject the nonnumeric price. Ordinary SQLite affinity can store name text "9.99" and price text "Desk lamp" without an error. Read the inserted row back with SELECT to check the mapping.

Write literal values correctly
KindSQL example
Text'Desk lamp'
Text containing an apostrophe'O''Brien'
Number1250.50
ISO date'2026-03-15'
Missing valueNULL

The doubled apostrophe stores one apostrophe. Numbers have no currency sign or thousands separator; a comma separates values, so a comma inside an unquoted amount changes the value count. 'NULL' is the four-letter text "NULL", not a missing value.

Let omitted fields fill themselves

A column left out receives its default, or NULL if it has none. A generated key receives a generated value. That last behavior depends on the declaration: SQLite's INTEGER PRIMARY KEY generates IDs; PostgreSQL requires an identity declaration for this purpose. A plain PostgreSQL integer primary key left out of an insert fails because its value would be NULL.

PostgreSQL, MySQL and SQL Server allow DEFAULT as a value placeholder. SQLite does not accept it inside a VALUES list; leave that column out instead. An explicit NULL never requests the default.

Add several rows together
INSERT INTO customers (first_name, last_name, email) VALUES
  ('Ana', 'Ruiz', 'ana@example.com'),
  ('Ben', 'Okafor', 'ben@example.com'),
  ('Chloe', 'Nguyen', 'chloe@example.com');

In an empty table with its generated key starting at 1, these receive IDs 1, 2 and 3. Under ordinary constraint handling, the multi-row statement succeeds as a whole or fails as a whole. If one row violates a rule, none of this statement's rows are inserted.

A UNIQUE error points to a duplicate key or value; NOT NULL points to missing data; CHECK points to a failed condition; and a foreign key error points to an invalid link. Fix the value or its intended mapping before trying again.

Key Takeaways

  • List columns and match each value to them by position.
  • Omitted fields receive defaults or NULL; generated IDs require a generator.
  • Use single quotes for text and double an embedded apostrophe.
  • NULL and the text NULL are different.
  • A normal multi-row insert fails as a whole if a row violates a constraint.

3.2 Insert from queries, return new keys and handle duplicates

Rows do not have to be typed one at a time. A query can supply the rows for an insert, and a conflict rule can say what should happen when a unique value already exists. Both features depend on matching the intended data precisely.

Copy a query result
INSERT INTO archived_orders (id, customer_id, order_date, total)
SELECT id, customer_id, order_date, total
FROM orders
WHERE order_date < '2026-01-01';

There is no VALUES clause: the query supplies the values. Match its selected columns to the target list by position. The target table must already exist, and its rules still apply.

Preview the SELECT alone. Orders 201, 202 and 204 have dates 2025-11-03, 2025-12-19 and 2025-10-30 and totals 45.00, 120.50 and 60.00. Orders 203 and 205 are dated in 2026. The query returns three rows totaling 225.50, and the insert copies those three. It can also copy zero rows when the filter finds nothing.

A second run tries to copy them again. A target primary key makes that fail instead of silently storing duplicates. INSERT ... SELECT is a copy operation; it does not remove the source rows or keep the two tables synchronized.

File imports often go through a staging table first. SQLite's shell uses .import --csv file.csv staging; psql uses \copy. In a later query, TRIM(email) removes surrounding spaces and NULLIF(TRIM(email), '') turns a blank email into NULL. The destination constraints then check the cleaned rows.

Read the result of a write
INSERT INTO customers (first_name, last_name, email)
VALUES ('Dev', 'Patel', 'dev@example.com')
RETURNING id;

The result gives the generated customer ID to use in a related row. PostgreSQL and SQLite 3.35.0 and later support RETURNING on inserts, updates and deletes. MySQL uses LAST_INSERT_ID() for a generated ID; SQL Server uses OUTPUT.

Decide how duplicates should behave

With stock (sku TEXT PRIMARY KEY, qty INTEGER NOT NULL), suppose 'LAMP-01' has quantity 12. A plain insert proposing the same SKU and quantity 20 fails. In SQLite and PostgreSQL:

INSERT INTO stock (sku, qty) VALUES ('LAMP-01', 20)
ON CONFLICT (sku) DO UPDATE
SET qty = stock.qty + excluded.qty;

stock.qty is the existing 12. excluded.qty is the proposed 20. This form stores 32, which fits an extra delivery. SET qty = excluded.qty stores 20, which fits a replacement count. DO NOTHING keeps 12 and skips the conflicting row. Each variation starts from the same original quantity 12.

An upsert combines inserting a new row with updating on a conflict. The conflict target must have suitable uniqueness protection. MySQL's equivalent family is ON DUPLICATE KEY UPDATE. A plain INSERT does not correct an existing customer: it either creates another row or hits a uniqueness error. Use UPDATE for a known existing row, and an upsert when the row might already exist.

Key Takeaways

  • INSERT ... SELECT copies the query results into an existing table.
  • Re-running a copy needs a deliberate duplicate policy.
  • RETURNING reports values from the rows actually written.
  • excluded names the proposed row in an upsert.
  • Replace stock with excluded.qty; add a delivery with stock.qty + excluded.qty.
  • DO NOTHING skips a unique conflict without updating the existing row.
4

Change and remove rows with UPDATE and DELETE

A valid data-changing statement can still affect the wrong rows. Updating a price, removing an order and selecting the records to change are separate decisions. You will calculate new values from stored ones, distinguish clearing a field from deleting a row, and build conditions with dates, missing values and grouped alternatives. A preview and a checked result make the effect visible before a transaction makes the change permanent.

4.1 Change values with UPDATE

UPDATE changes values in rows that already exist. It names a table, assigns new values with SET, then chooses the target rows with WHERE. The table's constraints check the resulting values.

Set one or several fields
UPDATE products
SET price = 22.50, in_stock = 30
WHERE id = 3;

The product with key 3 receives both values; other rows keep theirs. Assignments use commas. Writing SET price = 22.50 AND in_stock = 30 does not mean two assignments. PostgreSQL rejects it; SQLite treats the right side as a Boolean expression and can store 0 or 1 in price.

A missing WHERE is valid SQL and applies to every row. UPDATE products SET price = 0; sets every product's price to zero if the table's rules allow it. A preview with the intended condition shows whether the target is one row, several rows or none.

Calculate from the stored value
UPDATE products
SET price = price * 1.10;

A price of 20.00 becomes 22.00 after a 10% increase. A price of 19.99 gives an unrounded result of 21.989. PostgreSQL stores 21.99 in a NUMERIC(8, 2) column. SQLite does not enforce the scale, so SET price = ROUND(price * 1.10, 2) requests two decimal places. For exact SQLite money storage, keep whole cents and make the cents rounding decision explicit.

The expression must include the old value when the change is relative. SET in_stock = in_stock - 1 removes one unit; SET in_stock = 1 replaces the count with one.

In SQLite and PostgreSQL, all right-hand expressions read the row before the update. UPDATE t SET a = b, b = a; swaps a row's values from 1 and 2 to 2 and 1. MySQL's single-table update evaluates assignments left to right, so the same form makes both 2. Do not transfer this assumption between systems.

Keep rules and missing values in view

Use SET phone = NULL to clear a phone field. To find missing phone values, use WHERE phone IS NULL. Equality with NULL does not find them.

Consider prices 12.00, 3.00 and 8.50 protected by CHECK (price > 0). Subtracting 5 from every price would make the second -2.00. With ordinary constraint handling, that failure undoes the whole statement, so even the otherwise valid prices stay unchanged.

A primary key update also has to satisfy related foreign keys. A blocked key change fails while children point to the old key; ON UPDATE CASCADE transfers the new value to them. Keeping generated IDs stable avoids this extra work when descriptive details change.

Interpret the affected-row count

psql reports a result such as UPDATE 3; SQLite's changes() reports the count for the last change statement. Both include rows matched and updated even when the assigned value equals the old value. A count of three does not promise three visibly different values. Compare the count with the preview and inspect the relevant fields afterward, or use RETURNING to see affected rows directly.

Key Takeaways

  • SET assigns values; WHERE chooses rows.
  • Separate assignments with commas, not AND.
  • Use the old column value in a relative calculation.
  • An ordinary constraint failure undoes the whole UPDATE statement.
  • Affected-row counts can include rows whose values stayed equal.

4.2 Remove rows with DELETE

DELETE removes whole rows. It leaves the table ready to hold rows again. Clearing one field uses UPDATE ... SET column = NULL; DELETE email FROM customers is not valid SQL.

Follow a filtered delete

The shop has these orders:

IDStatusOrder date
201cancelled2025-11-03
202shipped2025-12-19
203cancelled2026-01-08
204cancelled2025-10-30
205expired2026-02-14
DELETE FROM orders
WHERE status = 'cancelled'
  AND order_date < '2026-01-01';

Order 201 meets both tests, as does 204. Order 203 is cancelled but too recent; 202 is old enough but shipped. The statement removes two rows and leaves 202, 203 and 205. DELETE FROM orders; without the condition would remove all five.

Use related data to choose rows
DELETE FROM order_items
WHERE order_id IN (
  SELECT id FROM orders WHERE status = 'cancelled'
);

The inner query produces cancelled order IDs. IN checks each item's order_id against that list. Run the inner query alone to inspect the keys, then preview the item rows with the same condition.

Foreign keys also affect deletion. A parent with referring children can be protected by NO ACTION or RESTRICT; a cascade removes children; SET NULL keeps children but clears the link. Check those actions when judging the effect of deleting a parent, because the directly named table may not be the only table changed.

Choose what should remain
StatementRows removedWhat remains
DELETE ... WHERE ...Matching rowsTable and other rows
DELETE FROM orders;All rowsEmpty table
TRUNCATE TABLE orders;All rows, with no WHEREEmpty table
DROP TABLE orders;All rows with the tableNo orders table

PostgreSQL, MySQL, SQL Server and Oracle support TRUNCATE; SQLite does not. Its transaction and dependency rules vary by database. A statement that sounds like a quick emptying operation must still fit those rules.

Keep history with a soft delete
UPDATE customers
SET deleted_at = '2026-03-15'
WHERE id = 7;

A soft delete marks the row without removing it. It can preserve history and allow restoration by clearing the mark. Queries for active customers must include WHERE deleted_at IS NULL; otherwise the marked customers still appear. Marking data does not erase it.

A committed delete cannot be undone by a later ROLLBACK. Restoration needs a saved copy or backup. Within an open transaction, rollback can still restore deleted rows. Check the selected IDs and affected count before making the result permanent.

Key Takeaways

  • DELETE removes rows; UPDATE can clear a single field.
  • A missing WHERE empties the table while retaining its structure.
  • IN can select rows using keys from another table.
  • Foreign key actions can extend or block a delete.
  • A soft delete requires active-row filters and does not erase the stored data.
  • ROLLBACK restores a delete only while its transaction remains uncommitted.

4.3 Target exactly the rows you mean

Choosing rows is often the hardest part of a change. The same filter that is harmless in a query can delete or update too much when reused in a write. Turn the intended rule into a condition, then inspect what it actually matches.

Preview the exact condition
SELECT id, status, order_date FROM orders
WHERE status = 'cancelled'
  AND order_date < '2026-01-01';

This preview returns orders 201 and 204 in the five-order shop example. Reuse exactly that condition in the delete. Rewriting it while changing the command creates a new, unchecked selection.

For one specific row, use its primary key: WHERE id = 42 matches at most one row. A descriptive name such as 'Desk lamp' may be shared by several products.

Group alternatives explicitly

AND binds more tightly than OR. Compare:

WHERE status = 'cancelled'
   OR status = 'expired' AND order_date < '2026-01-01'

with:

WHERE (status = 'cancelled' OR status = 'expired')
  AND order_date < '2026-01-01'

The first accepts every cancelled order, regardless of date, plus expired orders before 2026. It matches 201, 203 and 204. The second applies the date test to both statuses and matches 201 and 204. Order 203 exposes the difference because it is cancelled in 2026.

Include missing values deliberately

WHERE customer_id = NULL matches no rows. Missing values need IS NULL or IS NOT NULL. A negative test also has a gap: status <> 'shipped' does not include a missing status, because its comparison is unknown.

If missing status belongs in the intended group, write:

WHERE status <> 'shipped' OR status IS NULL

When adding another condition, group this whole alternative with parentheses so that both branches meet that condition.

Pattern matching can reach beyond the intended description. LIKE '%lamp%' matches "Desk lamp" and "Clamp". SQLite's default LIKE also ignores case for English letters, so it finds "Lamp shade". A pattern is useful for finding possible matches, but inspect those matches before changing them.

Choose a list comparison for a list
UPDATE orders SET status = 'on hold'
WHERE customer_id IN (
  SELECT id FROM customers WHERE state = 'CA'
);

The subquery can supply several customer IDs; IN checks membership. Replacing IN with = asks for one scalar result. PostgreSQL rejects multiple rows there, while SQLite silently uses the first row returned and misses other customers.

After the change, compare the affected count with the preview. PostgreSQL and SQLite can also append RETURNING * to show the affected rows. For a risky write, start a transaction before changing data, inspect the result, then choose COMMIT or ROLLBACK.

Key Takeaways

  • Preview exactly the WHERE condition the write will use.
  • A primary key filter identifies at most one row.
  • Parentheses make OR alternatives share an AND condition.
  • IS NULL handles missing values; ordinary comparisons skip them.
  • IN accepts a subquery list; scalar equality does not.
  • Check the count and result before committing.
5

Group changes into transactions

Some changes belong together: a transfer needs both a withdrawal and a deposit. Transactions give those statements one decision to keep or undo, while savepoints let you return to an intermediate point. You will track balances through successful changes and errors, then compare how SQLite and PostgreSQL handle a failed statement. The database and client settings matter, especially when a structure change can commit earlier work.

5.1 Commit or roll back a group of changes

A transaction groups related statements into one unit of work. You decide to keep its changes together with COMMIT or undo them together with ROLLBACK. The all-or-nothing property is called atomicity, the A in ACID.

Keep both sides of a transfer

Maya's account, ID 1, holds 500.00. Leo's account, ID 2, holds 120.00. Moving 75.00 requires two changes:

BEGIN;
UPDATE accounts SET balance = balance - 75.00 WHERE id = 1;
UPDATE accounts SET balance = balance + 75.00 WHERE id = 2;
SELECT id, balance FROM accounts WHERE id IN (1, 2);
COMMIT;

The first update leaves Maya with 425.00. The second leaves Leo with 195.00. The check shows both balances before the commit, and the total stays 620.00. For these exact decimal balances use PostgreSQL NUMERIC; in SQLite an exact-money version stores 50000 and 12000 cents and transfers 7500 cents.

Without an explicit transaction under autocommit, the first update could become permanent before the second runs. A crash between them would keep the withdrawal without the deposit. A transaction gives the two updates one final keep-or-undo decision. If a statement fails, handle the error before deciding that the transfer is complete.

Understand the default boundary

Under database autocommit, each successful standalone statement commits as its own transaction. This is the usual starting behavior for SQLite, PostgreSQL, MySQL and SQL Server. A programming library or client can choose different settings and start a transaction for you.

BEGIN; starts an explicit transaction in SQLite and PostgreSQL. SQLite and SQL Server also use BEGIN TRANSACTION; PostgreSQL and MySQL accept START TRANSACTION. Oracle starts a transaction with a data change and ordinarily waits for COMMIT in tools such as SQL*Plus unless autocommit is enabled.

COMMIT ends the transaction and keeps its changes. ROLLBACK ends it and undoes its uncommitted changes. A later rollback cannot cross an earlier commit.

Inspect and undo
BEGIN;
DELETE FROM orders;
SELECT * FROM orders;
ROLLBACK;

Your connection sees an empty table at the SELECT, then sees the five orders again after rollback. The empty result was real within the transaction, but was not yet permanent. Other connections normally do not see the uncommitted changes.

A transaction can protect a wrong row selection only if you inspect and choose to undo it. SQL can successfully update an unintended row: no database rule knows which account you meant to name. Compare returned IDs, values and counts with the intended result before committing.

Keep transactions short and end them. Open transactions can hold locks that make other connections wait; SQLite permits only one writer at a time. Closing a connection with an unfinished transaction rolls back its pending changes. When a library starts a transaction automatically, the program must call its commit method to keep the work.

Key Takeaways

  • Atomicity lets related changes be kept or undone together.
  • Autocommit makes a standalone successful statement permanent.
  • Your connection can inspect its own pending changes.
  • COMMIT and ROLLBACK both end the transaction.
  • ROLLBACK cannot undo work from an earlier committed transaction.

5.2 Handle errors, savepoints and structure changes in a transaction

A failed statement does not have the same effect in every database. You need to know what is still pending before deciding how to recover. A savepoint can provide a smaller place to return to inside an open transaction.

Trace an error

After the transfer, Maya has 425.00 and Leo has 195.00. The table has CHECK (balance >= 0). Start a transaction and subtract 30.00 from Maya: her pending balance is 395.00. Then try to subtract 300.00 from Leo. That would make his balance -105.00, so the second statement fails.

DatabaseState after the ordinary constraint error
SQLiteThe failed statement is undone; Maya's earlier change is still pending.
PostgreSQLThe transaction is failed, and further ordinary commands are refused.

In SQLite, committing at this point would keep Maya's deduction alone. In PostgreSQL, COMMIT on the failed transaction ends it with a rollback. A clear recovery routine is to issue ROLLBACK, correct the cause, and rerun the related statements. Both balances then return to 425.00 and 195.00 before the corrected attempt.

Undo a later part with a savepoint
BEGIN;
UPDATE accounts SET balance = balance + 10 WHERE id = 1;
SAVEPOINT after_first;
UPDATE accounts SET balance = balance + 10 WHERE id = 2;
ROLLBACK TO after_first;
COMMIT;

The savepoint comes after Maya's increase. ROLLBACK TO undoes Leo's later increase but preserves Maya's. The final balances are 435.00 and 195.00. It does not end the outer transaction; COMMIT does that.

RELEASE after_first removes the savepoint without undoing the changes after it. It is not an independent permanent commit inside the outer transaction. PostgreSQL also lets ROLLBACK TO a savepoint established before an error clear the failed state and continue from that point.

Check whether structure changes can roll back

SQLite and PostgreSQL allow CREATE TABLE, ALTER TABLE and DROP TABLE inside transactions. For example, BEGIN; DROP TABLE orders; ROLLBACK; restores the table and its rows.

Ordinary permanent-table DDL in MySQL and Oracle causes implicit commits. A CREATE TABLE, ALTER TABLE, DROP TABLE or TRUNCATE TABLE can commit earlier pending changes as well as perform its own structural operation. A later rollback cannot undo that earlier work. Do not assume that a transaction around a script makes all database dialects behave alike.

For a risky data change, begin the transaction, run the write, inspect its values and count, and then commit or roll back. For example, inspect lighting prices after UPDATE products SET price = ROUND(price * 1.10, 2) WHERE category = 'lighting';. Complete the decision promptly so the transaction does not keep other work waiting.

Key Takeaways

  • A normal SQLite constraint error leaves earlier transaction changes pending.
  • A PostgreSQL error leaves the transaction failed until rollback or recovery to a savepoint.
  • ROLLBACK TO undoes later work without ending the transaction.
  • RELEASE removes a savepoint without committing the outer transaction.
  • DDL rollback support depends on the database.
6

Change table structure with ALTER TABLE and DROP TABLE

Tables sometimes need a new field, a clearer name or a stronger rule after they already contain data. Changing that structure requires checking the existing rows and the objects that depend on the table. You will add and fill columns, recognize when SQLite needs a rebuild, and distinguish removing records from removing their container. Dependencies also set the order of work when related tables are retired.

6.1 Add, rename and remove columns with ALTER TABLE

ALTER TABLE changes an existing table's structure while preserving its rows. UPDATE changes the values those rows hold. Adding a discount field needs ALTER TABLE; raising the discounts already stored needs UPDATE.

Add and rename fields
ALTER TABLE customers ADD COLUMN phone TEXT;
ALTER TABLE customers RENAME COLUMN phone TO mobile;
ALTER TABLE customers RENAME TO clients;

SQLite and PostgreSQL share these forms. A new column gives existing rows its default, or NULL when there is none. ADD COLUMN active INTEGER NOT NULL DEFAULT 1 gives each current row an active value of 1. Adding email TEXT NOT NULL with no default fails on a populated table because the existing rows would lack a required value.

SQLite supports RENAME COLUMN from 3.25.0 and DROP COLUMN from 3.35.0. When renaming, update application code and saved queries that refer to the old name. SQL outside the database cannot discover the new name automatically.

Fill data before requiring it

In PostgreSQL, add a nullable column, fill the existing rows with suitable values, and only then require it:

ALTER TABLE customers ADD COLUMN email TEXT;
UPDATE customers SET email = 'unknown@example.com'
WHERE email IS NULL;
ALTER TABLE customers ALTER COLUMN email SET NOT NULL;

This illustrates filling a required field; it does not declare email unique. A real unique email column needs distinct valid values. SET NOT NULL fails if any missing values remain. PostgreSQL also supports changing a type with ALTER COLUMN price TYPE NUMERIC(10, 2), setting a default and adding a named check. Existing rows must satisfy a newly added rule.

Remove a field or rebuild a table

ALTER TABLE customers DROP COLUMN mobile; removes the field and all its stored values. Dependencies can block the operation. SQLite rejects dropping a primary-key, unique, indexed or foreign-key column, or one used by another schema object. PostgreSQL can remove dependent objects with CASCADE, including a view that uses the column.

SQLite cannot change an existing column's type or add primary-key, unique, foreign-key or check constraints to existing columns with a simple ALTER. Version 3.53.0 adds ALTER COLUMN ... SET NOT NULL and DROP NOT NULL, not general constraint editing. A newly added column can have a check or permitted reference, but cannot have PRIMARY KEY or UNIQUE; with foreign keys on, an added reference needs a NULL default.

For a broader SQLite change:

  1. Record the indexes, triggers and views that must be recreated. If foreign keys are on, switch them off before the transaction.
  2. Start a transaction and create a new table with the desired rules.
  3. Copy rows using explicit columns in INSERT INTO new_products (...) SELECT ... FROM products;.
  4. Drop the old table and rename the new one to products.
  5. Recreate dependent objects and run PRAGMA foreign_key_check;. Resolve any reported problems before committing.
  6. Commit and restore foreign key enforcement afterward if it was on before.

MySQL changes definitions with MODIFY COLUMN; SQL Server uses ALTER COLUMN. Translate a structural change into the target database's supported syntax before running it.

Key Takeaways

  • ALTER TABLE changes structure; UPDATE changes stored values.
  • Added columns give existing rows a default or NULL.
  • Fill a required new column before adding NOT NULL.
  • Dropping a column removes its values and can be blocked by dependencies.
  • SQLite needs a rebuild for many type and constraint changes.
  • Rebuilds must preserve dependent objects and check foreign keys.

6.2 Remove tables with DROP TABLE

DROP TABLE removes the container as well as its contents. After DROP TABLE archived_orders;, queries cannot read that table because it no longer exists. Its constraints, indexes and triggers are removed with it.

Choose the level of removal
Intended resultStatement
Keep the table and remove selected rowsDELETE FROM orders WHERE ...;
Keep an empty tableDELETE FROM orders;
Quickly empty a table where supportedTRUNCATE TABLE orders;
Remove the table itselfDROP TABLE orders;

DROP TABLE IF EXISTS archived_orders; avoids an error if the table is absent. It still removes an existing table and its data. A setup script that drops and recreates tables is destructive when run on a database containing records you want to keep.

Respect links between tables

Drop children before parents, reversing the usual creation order. In PostgreSQL, dropping customers while an order foreign key depends on it fails. DROP TABLE customers CASCADE; also removes the dependent foreign key and any dependent views. The order table and its rows remain, but the customer relationship is no longer enforced.

This PostgreSQL CASCADE is different from a foreign key's ON DELETE CASCADE. The first removes dependent database objects during a structure change. The second removes child rows when a parent row is deleted. Knowing which action is in use prevents an incorrect prediction about the remaining data.

With SQLite foreign key enforcement on, dropping a table first performs an implicit deletion of its rows. Referring children can block it. If the relationship declares ON DELETE CASCADE, those child rows can be deleted; SET NULL can clear their links. A drop therefore needs the same attention to references as a delete, as well as attention to the table structure being removed.

Preserve a recovery path

Before removing or rebuilding a table with real data, preserve a usable copy. A quick internal data copy is:

CREATE TABLE products_backup AS
SELECT * FROM products;

In SQLite and PostgreSQL, this preserves the selected data but not the original constraints. It does not serve as a full reconstruction of the table definition. An export or database backup keeps recovery data outside the table being changed.

SQLite and PostgreSQL also allow a drop to be tested inside a transaction:

BEGIN;
DROP TABLE archived_orders;
ROLLBACK;

The rollback restores the table and its rows because the drop was not committed. Once committed, the drop cannot be reversed by issuing ROLLBACK later. In databases with implicit DDL commits, wrapping the drop in transaction syntax does not supply this undo opportunity. Inspect the target database and the tables involved before running a rebuilding script.

Key Takeaways

  • DROP TABLE removes the table and its rows, constraints, indexes and triggers.
  • IF EXISTS suppresses an absence error, not an existing table deletion.
  • Drop child tables before their parents.
  • PostgreSQL DROP CASCADE removes dependent objects, while child tables can remain.
  • A data-only copy does not preserve the original constraints.

SQL CREATE TABLE examples

6 Walkthroughs

1

Build and inspect a product table

11 steps
Define an empty table, check its columns and choose storage that matches each value.
  1. 1
    IntroductionStart with one product

    A shop needs to record a product's ID, name, price and stock count. A table definition gives each fact its own field before any product rows are added.

    We will build the structure, inspect it and then check whether the types preserve what the values mean. The examples use SQLite and name the PostgreSQL changes where they affect the result.

  2. 2
    ExplanationRead a column definition

    In name TEXT NOT NULL, name is the field's identifier, TEXT describes its storage and NOT NULL requires a value.

    The table lists these definitions inside parentheses, separated by commas. The semicolon ends the creation statement. Creating the structure is DDL; it does not add any product rows. A later INSERT supplies those rows.

  3. 3
    ExampleCreate four fields
    CREATE TABLE products (
      id INTEGER PRIMARY KEY,
      name TEXT NOT NULL,
      price NUMERIC(8, 2) NOT NULL,
      in_stock INTEGER DEFAULT 0
    );
    

    There are four column definitions and three separating commas. SQLite generates this integer primary key. PostgreSQL needs an identity declaration if an omitted ID should be generated.

  4. 4
    TipInspect the actual definition

    Use PRAGMA table_info(products); in SQLite SQL or .schema products in its command-line shell. In PostgreSQL psql, use \d products.

    Inspection catches more than syntax errors. SQLite can read a missing comma as part of a multiword type name, leaving one column where you expected two. SELECT * FROM products; shows an empty table, but its zero rows do not verify every rule.

  5. 5
    ChallengeWill this repair an old table?

    An older products table has only id and name. A script runs CREATE TABLE IF NOT EXISTS products (...) with four desired columns. How many columns does the existing table have afterward?

    ---reveal---

    It still has two. IF NOT EXISTS skips creation when the name is present. It does not compare the definitions or add the missing fields. A structural change needs ALTER TABLE or a deliberate rebuild.

  6. 6
    ExplanationSeparate quantities from codes

    Store quantities as numbers so that arithmetic and numeric sorting work. Store codes as text when their characters carry meaning.

    ZIP code '02139' loses its leading zero as an integer. Text values '100', '25' and '9' sort in that character order, which is wrong for numerical quantities. The decision follows how the field will be used, not whether its examples contain digits.

  7. 7
    ExampleRead precision and scale

    PostgreSQL NUMERIC(8, 2) allows eight total digits, with two after the point. That leaves six before it, up to 999999.99.

    A value of 12.345 is stored as 12.35. A value of 1234567.00 fails because it needs seven digits before the point. SQLite accepts the same declaration but does not enforce this precision or scale, so that prediction does not transfer to SQLite.

  8. 8
    Key InsightKeep exact money exact

    Binary floating point can introduce tiny differences into decimal arithmetic. SQLite's SELECT 0.1 + 0.2 = 0.3; returns false.

    Use PostgreSQL NUMERIC for exact decimal amounts. In SQLite, store whole cents as integers: 1999 represents 19.99. Writing NUMERIC(8, 2) in SQLite does not create fixed-scale exact decimal storage. Approximate types still suit measurements such as temperatures.

  9. 9
    ChallengeKeep dates in order

    A SQLite table stores dates as text. Why does changing '12/01/2025' and '03/15/2026' to ISO dates help an ascending date sort?

    ---reveal---

    The ISO forms are '2025-12-01' and '2026-03-15'. Text comparison then checks year, month and day in that order, putting the earlier date first. Month-first text compares the month before it reaches the year and puts these two in the wrong date order.

  10. 10
    ChallengeCheck the table and the type

    A SQLite script creates a missing table with CREATE TABLE IF NOT EXISTS readings (qty INTEGER);. An insert supplies 'abc' as qty and succeeds. What should you check before assuming qty always holds numbers?

    ---reveal---

    Inspect the actual definition, because IF NOT EXISTS could have skipped an older table. Also account for ordinary SQLite affinity: an integer declaration can still store nonnumeric text. A suitable STRICT table strengthens type enforcement.

  11. 11
    RecapMatch structure to use

    A creation statement defines fields, types and rules; an insert supplies the records. Inspect the structure that exists instead of assuming a successful script created the definition you intended.

    For each field, ask what must be preserved: numeric arithmetic, exact cents, identifier characters or chronological order. Apply the target database's type behavior when predicting the stored result.

2

Protect products and customer links

13 steps
Follow constraint checks, choose generated keys and predict foreign key actions.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionCheck data at the database
  2. 2
    ExplanationGive each rule one job
  3. 3
    ExampleFollow one accepted row
  4. 4
    ChallengeDoes a default fix explicit NULL?
  5. 5
    Key InsightAn unknown check result passes
  6. 6
    ExplanationIdentify the whole row
  7. 7
    ExampleLet the system choose the ID
  8. 8
    ChallengeIs the next ID a row count?
  9. 9
    ExplanationMake each order find its customer
  10. 10
    ExampleTrace a cascade
  11. 11
    ChallengeKeep the orders after removal
  12. 12
    ChallengeCombine the required rules
  13. 13
    RecapCheck values, identity and links
3

Insert products and copy orders

11 steps
Match values to columns, inspect copied rows and distinguish replacement from added stock.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionChoose where new rows come from
  2. 2
    ExampleMap one product
  3. 3
    TipKeep literal values intact
  4. 4
    ChallengeRead the explicit list
  5. 5
    ExplanationAdd a group as one statement
  6. 6
    ExamplePreview the archive query
  7. 7
    ExampleUse the query as input
  8. 8
    ExplanationName the proposed row
  9. 9
    ChallengeKeep or replace?
  10. 10
    ChallengeCopy and link without guessing
  11. 11
    RecapFollow the input through the write
4

Change exactly the intended rows

14 steps
Apply calculated updates, trace deletes and test filters before keeping a change.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionSeparate what changes from which rows
  2. 2
    ExampleAssign two new values
  3. 3
    ExampleRaise a price from its old value
  4. 4
    ChallengeWill the other prices change?
  5. 5
    ExplanationRemove a row or clear a field
  6. 6
    ExampleTrace the old cancelled orders
  7. 7
    ChallengeKeep a deleted customer's history
  8. 8
    TipReuse the preview condition
  9. 9
    ExampleApply AND before OR
  10. 10
    ChallengeApply one date rule to both statuses
  11. 11
    Key InsightA negative comparison misses NULL
  12. 12
    ChallengeUse a list of customer keys
  13. 13
    ChallengeInspect an all-row update
  14. 14
    RecapCheck meaning and effect
5

Keep or undo a complete change

12 steps
Track a transfer, recover from errors and use a savepoint without losing the outer transaction.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionOne transfer needs two changes
  2. 2
    ExplanationOpen a shared boundary
  3. 3
    ExampleSubtract the transfer amount
  4. 4
    ExampleAdd and inspect the deposit
  5. 5
    ChallengeUndo the whole pending transfer
  6. 6
    ExampleTrack a failed balance change
  7. 7
    ExplanationRecover according to the database
  8. 8
    ChallengeAvoid keeping an incomplete operation
  9. 9
    ExampleMark an intermediate point
  10. 10
    Key InsightReleasing is not an outer commit
  11. 11
    ChallengeCan this drop be undone?
  12. 12
    RecapEnd at a deliberate decision
6

Change or remove a populated table

13 steps
Add required data in steps, rebuild SQLite tables where needed and follow dependencies during drops.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionWork with records already present
  2. 2
    ExampleAdd a nullable field
  3. 3
    ChallengeRequire a field after filling it
  4. 4
    TipRename every external use
  5. 5
    ExplanationRecognize a limited ALTER
  6. 6
    ExamplePrepare the replacement
  7. 7
    ExampleCopy, replace and check
  8. 8
    ExplanationDecide whether the table should stay
  9. 9
    ExampleTrace PostgreSQL dependencies
  10. 10
    ChallengeSeparate the two cascade meanings
  11. 11
    TipKeep data and definition recoverable
  12. 12
    ChallengeKeep rules through a rebuild
  13. 13
    RecapFollow the structure and its dependencies

SQL CREATE TABLE practice questions

50 Practice Questions in 5 sets

Set 1: Trace the stored results10 Practice Questions

Question 1 of 10

A PostgreSQL field is NUMERIC(5, 2). What happens to an inserted value of 48.726?
  1. It is stored as 48.73.
  2. It is stored as 48.72.
  3. It is stored as 48.726.
  4. It fails for exceeding five total digits.
Show answerHide answer
Answer: A
PostgreSQL rounds to the two declared decimal places, so 48.726 becomes 48.73. There is enough space for the two digits before the point, and the extra fractional digit is rounded away. Keeping all three decimal places would describe SQLite's flexible numeric declaration, not this PostgreSQL field.

Question 2 of 10

A table has UNIQUE (room_id, start_time). It contains (4, '09:00') and (5, '09:00'). What happens when (4, '10:00') is inserted?
  1. It fails because room 4 is repeated.
  2. It fails because two rooms share 09:00.
  3. It replaces the room 4 record.
  4. It succeeds because the pair is new.
Show answerHide answer
Answer: D
The constraint checks the full pair, and room 4 at 10:00 is not already present. The existing pairs show that either component may repeat as long as the combination differs. Treating the rule as separate uniqueness requirements on each column would incorrectly reject the insert.

Question 3 of 10

In an ordinary SQLite table, a required text primary key is declared code TEXT PRIMARY KEY. What extra rule closes SQLite's historical missing-key exception?
  1. Add DEFAULT NULL.
  2. Add CHECK (code = code).
  3. Add NOT NULL.
  4. Add another UNIQUE.
Show answerHide answer
Answer: C
Ordinary SQLite tables can allow missing values in a non-integer primary key for historical compatibility. Explicit NOT NULL prevents those missing keys. Another uniqueness rule does not solve missingness, and comparing a missing value with itself produces an unknown result that a check can accept.

Question 4 of 10

An ordinary PostgreSQL multi-row insert proposes three records. The last repeats an existing unique code. What happens to the first two proposed records?
  1. Both are inserted before the error.
  2. Neither is inserted by that statement.
  3. Only the first record is inserted.
  4. Both are inserted with missing codes.
Show answerHide answer
Answer: B
The ordinary insert is one statement, so the unique violation makes all three proposed inserts fail together. Processing a value group earlier does not make it independently committed. ON CONFLICT would be a deliberate different policy, but this statement has no such action.

Question 5 of 10

A SQLite table has generated id, required name, and qty INTEGER NOT NULL DEFAULT 6. What insert adds a brush using that default?
  1. INSERT INTO tools (name, qty) VALUES ('Brush', NULL);
  2. INSERT INTO tools (name, qty) VALUES ('Brush', DEFAULT);
  3. INSERT INTO tools (id, name) VALUES ('Brush', 6);
  4. INSERT INTO tools (name) VALUES ('Brush');
Show answerHide answer
Answer: D
Omitting qty requests its default 6, and omitting the generated id lets SQLite assign a key. Explicit NULL would violate the presence rule. Although some databases allow DEFAULT in a value list, SQLite does not, so omission is the supported form here.

Question 6 of 10

A customer row must remain, but its optional phone value must become missing. What statement does that?
  1. DELETE FROM clients WHERE id = 28;
  2. UPDATE clients SET phone = NULL WHERE id = 28;
  3. UPDATE clients SET phone = 'NULL' WHERE id = 28;
  4. ALTER TABLE clients DROP COLUMN phone;
Show answerHide answer
Answer: B
Assigning the keyword NULL clears only the matched customer's phone field. Quoting it would store the four-letter text "NULL" instead of a missing value. Deleting the row loses the customer, and dropping the column removes phone values for every customer.

Question 7 of 10

Cases are 71 (closed, 2025-08-01), 72 (open, 2026-02-02), 73 (closed, 2026-03-01), and 74 (expired, 2025-09-01). What IDs match state = 'closed' OR state = 'expired' AND opened < '2026-01-01'?
  1. 71, 73 and 74.
  2. 71 and 74 only.
  3. 71 and 73 only.
  4. 73 and 74 only.
Show answerHide answer
Answer: A
The AND groups the expired status with the date test. Every closed case qualifies regardless of date, so both 71 and 73 match, along with old expired case 74. Selecting only 71 and 74 would apply the date restriction to both statuses, which requires parentheses around the alternatives.

Question 8 of 10

An explicit transaction increases a count from 5 to 8. Before commit, the same connection queries the row. What count does it read?
  1. 5
  2. 3
  3. 8
  4. No row until commit.
Show answerHide answer
Answer: C
A connection sees its own pending writes, so its query reads 8 before the change becomes permanent. Other connections normally do not see that uncommitted value yet. Confusing those two visibility questions would make the transaction's own result impossible to inspect before deciding to keep it.

Question 9 of 10

A transaction starts with counters a = 2 and b = 7. It increases a by 3, sets savepoint s, increases b by 4, runs ROLLBACK TO s, and commits. What remains?
  1. a = 5 and b = 7.
  2. a = 2 and b = 7.
  3. a = 5 and b = 11.
  4. a = 2 and b = 11.
Show answerHide answer
Answer: A
The first increase is before the savepoint and remains pending. Rolling back to s undoes only the later increase of b, and commit then keeps a = 5 with b = 7. A full rollback would restore both starting values, but ROLLBACK TO does not cross the savepoint.

Question 10 of 10

In PostgreSQL, invoices references clients with a foreign key. DROP TABLE clients CASCADE; succeeds. What can remain of invoices?
  1. Its table, with every invoice row removed.
  2. Its rows, still linked by the old foreign key.
  3. No invoices table, because it referenced clients.
  4. Its rows and table, without that foreign key.
Show answerHide answer
Answer: D
PostgreSQL drop cascade removes dependent objects such as the referencing foreign key, without requiring the child table itself to be removed. The invoices can remain stored without that link. Confusing this DDL cascade with ON DELETE CASCADE would incorrectly predict automatic child-row deletion.
Set 2: Choose a reliable sequence10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

In SQLite, CREATE TABLE t (a INTEGER b TEXT); succeeds. Inspection shows only column a. Why?
  1. SQLite created b only after the first insert.
  2. SQLite merged equal data types into one column.
  3. SQLite treated b as a missing default value.
  4. SQLite read the remaining words as one type name.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A PostgreSQL identity-backed table currently has IDs 2, 6 and 9. How many rows does COUNT(*) return?
  1. 9
  2. 7
  3. 3
  4. 6
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

Foreign keys are enforced. Team 8 has members 81 and 82; team 9 has member 83. The member foreign key is nullable and has ON DELETE SET NULL. After deleting team 8, how many members remain linked to a team?
  1. Three members, with none unlinked.
  2. One member, with two members unlinked.
  3. One member, with the other two deleted.
  4. No members, with three members unlinked.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

With autocommit on and no explicit transaction, a source has IDs 61 and 62 before a cutoff and ID 63 after it. An empty target has a primary key on id. A filtered INSERT SELECT copies IDs before the cutoff, then the exact statement runs again without a conflict clause. What is the final target?
  1. IDs 61 and 62 once each; the second copy fails.
  2. IDs 61 and 62 twice each; both copies succeed.
  3. IDs 61, 62 and 63 once each; the second copy fails.
  4. No target rows; the second copy undoes the first.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A PostgreSQL stock row has code K8 and qty 14. A statement proposes (K8, 6) with ON CONFLICT (code) DO UPDATE SET qty = stock.qty + excluded.qty. The same statement then runs again. What qty is stored?
  1. 20
  2. 12
  3. 26
  4. 14
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A successful SQLite update matches four rows, all already having active = 1, and sets active = 1. What count does changes() report?
  1. 0
  2. 1
  3. 8
  4. 4
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Orders have flags: 91 (cancelled, 2025-04-01), 92 (NULL, 2025-05-01), 93 (cancelled, 2026-02-01), 94 (paid, 2025-06-01). What condition targets cancelled or missing-status orders only before 2026?
  1. (status = 'cancelled' OR status IS NULL) AND day < '2026-01-01'
  2. status = 'cancelled' OR status IS NULL AND day < '2026-01-01'
  3. (status = 'cancelled' OR status = NULL) AND day < '2026-01-01'
  4. (status = 'cancelled' AND status IS NULL) AND day < '2026-01-01'
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

With autocommit on, a standalone UPDATE succeeds. A second standalone UPDATE fails, and then ROLLBACK runs. What happens to the first update?
  1. It is undone as well.
  2. It remains committed.
  3. It waits for a COMMIT.
  4. It is redone afterward.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Tables depend in this order: line_items references sales, and sales references buyers. All three must be dropped without cascade. What order follows their dependencies?
  1. buyers, then sales, then line_items.
  2. sales, then line_items, then buyers.
  3. line_items, then sales, then buyers.
  4. line_items, then buyers, then sales.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A SQLite table is copied with CREATE TABLE saved AS SELECT * FROM original;. What should be checked before treating saved as a full replacement?
  1. Its constraints, which were not copied.
  2. Its rows, which are always absent.
  3. Its source link, which refreshes forever.
  4. Its name, which still must be original.
Show answerHide answer

Save this lesson to see this answer.

Set 3: Apply the rules to combined changes10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

An ordinary SQLite table declares value NUMERIC(7, 2). Inserting 6.789 succeeds. What stored value should you expect from this declaration alone?
  1. 6.79
  2. 6.789
  3. 6.78
  4. 679
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A PostgreSQL field is label TEXT NOT NULL with no other rules. What happens when the supplied value is the empty string?
  1. It is accepted as present empty text.
  2. It is rejected as a missing value.
  3. It is padded with a space before storage.
  4. It is accepted after conversion to NULL.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

In enforced SQLite, a child link is parent_id INTEGER DEFAULT 90 REFERENCES parents(id) ON DELETE SET DEFAULT. Parent 90 does not exist. Child 12 points to parent 7. What happens when parent 7 is deleted?
  1. The child remains and its link becomes 90.
  2. The child remains and its link becomes NULL.
  3. The parent and its child are both deleted.
  4. The delete fails because the default has no parent.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A stock row has quantity 9. Two delivery records each propose 4, but both run DO UPDATE SET qty = excluded.qty. What quantity is stored after both imports, and what total would correct addition have produced?
  1. Stored 4; correct delivery total 13.
  2. Stored 8; correct delivery total 17.
  3. Stored 4; correct delivery total 17.
  4. Stored 9; correct delivery total 8.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

An enforced foreign key uses the default blocking delete action. A booking is the only row that refers to customer 44. How can customer 44 be removed while keeping that booking linked to a valid existing customer 45?
  1. Update the booking to 45; delete customer 44.
  2. Delete customer 44; update the booking to 45.
  3. Clear the booking key; keep customer 44 stored.
  4. Delete customer 45; update the booking to 44.
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A PostgreSQL query for eligible customers returns IDs 31 and 34. Their orders must both be updated. The code uses customer_id = (SELECT id FROM customers WHERE eligible = TRUE). What happens, and what comparison fixes it?
  1. It updates both customers; keep equality.
  2. It updates the first customer; use IN.
  3. It errors on multiple rows; use IN.
  4. It updates no customers; use IS NULL.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

Balances for accounts 1 and 2 start at 300 and 90. A transaction transfers 40 from account 1 to account 2 and commits. A new transaction adds 10 to account 2, sets savepoint s, adds 5 to account 1, rolls back to s, then fully rolls back. What balances remain?
  1. 300 and 90, total 390.
  2. 260 and 140, total 400.
  3. 265 and 140, total 405.
  4. 260 and 130, total 390.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A PostgreSQL transaction updates row A, sets savepoint s, and then fails a check while updating B. What can recover the transaction while keeping A pending?
  1. Run RELEASE s, then continue.
  2. Run ROLLBACK TO s, then continue.
  3. Run COMMIT, then continue the transaction.
  4. Run another UPDATE B before any rollback.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A SQLite rebuild needs a new check and has dependent indexes plus enabled foreign keys (FKs). What sequence preserves the intended rules and checks references?
  1. Begin; disable FKs; copy without rules; replace; commit; enable FKs; check objects later.
  2. Disable FKs; begin; copy without rules; replace; check FKs; commit; leave FKs disabled.
  3. Disable FKs; begin; define and copy; replace; commit; check FKs; discard the dependent indexes.
  4. Disable FKs; begin; define and copy; replace and restore objects; check FKs; commit; enable FKs.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A PostgreSQL stock column contains 5, NULL and -2. It must become NOT NULL with CHECK (stock >= 0), keeping all rows. Missing counts should become 0, and negative counts must be corrected. What sequence establishes both rules?
  1. Set DEFAULT 0; correct -2; add both constraints.
  2. Fill NULLs with 0; correct -2; add both constraints.
  3. Fill NULLs with 0; keep -2; add both constraints.
  4. Fill NULLs with 0; correct -2; add only the check.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Diagnose common SQL mistakes10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A SQLite table labels already has only id and text columns. A script runs CREATE TABLE IF NOT EXISTS labels (id INTEGER PRIMARY KEY, text TEXT, color TEXT);. What happens to color?
  1. It is added and filled with missing values.
  2. It replaces the existing text column.
  3. It is not added to the existing table.
  4. It is added only after the next insert.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A script runs CREATE TABLE tickets (id INTEGER PRIMARY KEY, label TEXT);. No other statements run. What exists afterward?
  1. A table with one row for each column.
  2. An empty table with two columns.
  3. An empty table with only the id column.
  4. Two empty tables named id and label.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

In PostgreSQL, a nullable score has only CHECK (score BETWEEN 0 AND 100). An insert supplies NULL. What happens?
  1. It is rejected because the check is false.
  2. It is stored as the lower endpoint, zero.
  3. It is accepted after NULL becomes 100.
  4. It is accepted because the check is unknown.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A project has two tasks. Their project_id foreign key uses ON DELETE SET NULL, and project_id is also NOT NULL. Foreign keys are enforced. What happens when the project is deleted?
  1. The delete fails; the project and both tasks remain.
  2. The project is removed and both tasks become unlinked.
  3. The project and both of its tasks are removed.
  4. The delete succeeds and both tasks keep the old key.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

Stock for code R2 is 7. An incoming record reports a replacement count of 11. What upsert assignment stores the intended count?
  1. SET qty = stock.qty + excluded.qty
  2. SET qty = excluded.qty
  3. SET qty = stock.qty - excluded.qty
  4. SET qty = stock.qty
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A table has missing and nonmissing statuses. A write must target every row whose status is not paid, including missing statuses. What condition works?
  1. status <> 'paid' AND status IS NULL
  2. status <> 'paid' OR status = NULL
  3. status <> 'paid' OR status IS NULL
  4. status <> 'paid' AND status IS NOT NULL
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A write must set a row's color and quantity. How are the two assignments separated inside SET?
  1. With a comma.
  2. With AND.
  3. With WHERE.
  4. With another SET.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A SQLite transaction starts with balances 80 and 40. A first update subtracts 15 from the first balance. A second update subtracts 50 from the second and fails CHECK (balance >= 0). Under ordinary constraint handling, what would COMMIT keep?
  1. Balances 80 and 40.
  2. Balances 65 and -10.
  3. Balances 80 and -10.
  4. Balances 65 and 40.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A populated SQLite table gains active INTEGER NOT NULL DEFAULT 1. What active value do its existing rows have?
  1. NULL
  2. 1
  3. 0
  4. Their row IDs.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A temporary archive table must stop existing, including its rows and definition. What statement performs that removal?
  1. DELETE FROM archive;
  2. TRUNCATE TABLE archive;
  3. DROP TABLE archive;
  4. ALTER TABLE archive RENAME TO old_archive;
Show answerHide answer

Save this lesson to see this answer.

Set 5: Build tables and make first changes10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

A table contains 12 rows. DELETE FROM logs; succeeds. What remains?
  1. The logs definition and all 12 rows.
  2. An empty logs table with its definition.
  3. No logs table and no remaining rows.
  4. One logs row containing missing values.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

A SQLite connection runs BEGIN, changes a quantity from 8 to 11, then runs ROLLBACK. What quantity does that connection read afterward?
  1. 11
  2. 3
  3. 0
  4. 8
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

A PostgreSQL table has existing rows and no phone column. Every row must eventually have its own real phone value, and no single default is appropriate. What sequence meets that requirement?
  1. Add phone as nullable; fill valid phones; set NOT NULL.
  2. Add phone as NOT NULL; fill valid phones; remove its default.
  3. Add phone as nullable; set NOT NULL; fill valid phones.
  4. Add phone with DEFAULT NULL; set NOT NULL; fill valid phones.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

A row has qty 9. What assignment reduces the stored quantity by 3?
  1. SET qty = 3
  2. SET qty = 9 - qty
  3. SET qty = qty * 3
  4. SET qty = qty - 3
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A new SQLite field must preserve account code 00481 exactly. What storage type fits?
  1. INTEGER
  2. TEXT
  3. REAL
  4. NUMERIC(5, 0)
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A PostgreSQL column uses NUMERIC(6, 2). What is its largest positive value?
  1. 999999.99
  2. 99.9999
  3. 999999
  4. 9999.99
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

A SQLite column is qty INTEGER NOT NULL DEFAULT 4 CHECK (qty >= 0). An insert explicitly supplies NULL for qty. What happens?
  1. The insert fails the NOT NULL rule.
  2. The row is inserted with quantity 4.
  3. The row is inserted with quantity 0.
  4. The row is inserted with quantity NULL.
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A PostgreSQL table needs IDs generated when inserts omit id. What column definition supplies that behavior?
  1. id INTEGER PRIMARY KEY NOT NULL CHECK (id > 0)
  2. id INTEGER UNIQUE NOT NULL DEFAULT 1
  3. id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY
  4. id INTEGER NOT NULL CHECK (id >= 1)
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

Foreign keys are enforced. A child row uses supplier_id = 18, but supplier 18 does not exist. What must be done to insert that same non-NULL reference successfully?
  1. Add a different primary key to the child.
  2. Commit the child before adding the supplier.
  3. Create the matching supplier row first.
  4. Give supplier_id a non-NULL default value.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A table declares name before code. An insert uses (code, name) with values ('R7', 'Notebook'). What is stored in name?
  1. The text Notebook.
  2. The text R7.
  3. The text R7, Notebook.
  4. A missing value, NULL.
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

70 Key Terms, each with its definition

A

ADD COLUMN
The ADD COLUMN operation extends a table with a new field, giving existing rows its default or NULL when no default is declared.
Adding active INTEGER NOT NULL DEFAULT 1 gives existing customers the new value 1 without separate inserts.
Affected-row count
An affected-row count reports how many rows a statement updated; SQLite and PostgreSQL include matched rows assigned their current values.
An update that sets three existing active flags to their same values can still report three updated rows.
ALTER TABLE
The ALTER TABLE statement changes an existing table's definition, such as its columns or constraints, while retaining its rows.
Adding a phone field changes the structure with ALTER TABLE; filling phone values later uses UPDATE.
Atomicity
Atomicity is the all-or-nothing property that lets related changes in a transaction be kept or undone as one operation.
A completed transfer must keep both balance changes; keeping just the withdrawal would break the operation.
Autocommit
Autocommit commits each successful standalone statement as its own transaction unless the session has opened an explicit transaction.
Two balance updates under autocommit can become permanent separately, leaving a gap if the process stops.
AUTOINCREMENT
SQLite's AUTOINCREMENT keyword prevents a generated integer primary key from reusing numbers held by committed rows, at extra cost.
After committed IDs 1, 2 and 3, deleting 3 still makes the next AUTOINCREMENT-generated ID equal 4.

C

CHECK
A CHECK constraint tests a condition on a row and rejects a false result; an unknown result caused by NULL is accepted.
CHECK (price > 0) rejects a negative price but needs NOT NULL as well when a price must be supplied.
Child table
A child table holds a foreign key that points to a parent table, linking its rows to existing referenced records.
The orders table is a child of customers, while order items can themselves be children of orders.
Column list
An insert's column list names the destination fields explicitly, determining how supplied values are matched to them by position.
Listing (sku, name, price) makes the first supplied value a SKU even if price was declared earlier in the table.
COMMIT
The COMMIT command ends a transaction by making its pending changes permanent, after which a later rollback cannot undo that work.
After inspecting both transfer balances, committing keeps the withdrawal and deposit as the completed transfer.
Composite key
A composite key identifies a row through the combination of several column values, without requiring each column to be unique alone.
The pair of order ID and product ID identifies an order item while allowing both values in other pairs.
Constraint
A constraint is a declared database rule that checks inserted or updated data and rejects a change that would violate it.
A product price check rejects a negative amount regardless of which application submits the write.
CREATE TABLE
The CREATE TABLE statement creates a new table with named columns, declared types and optional rules, initially without rows.
CREATE TABLE labels (id INTEGER PRIMARY KEY, name TEXT); prepares a table before labels are inserted.
CREATE TABLE AS
The CREATE TABLE AS statement creates a table from query results, copying selected data without source constraints in SQLite and PostgreSQL.
A cheap_products copy holds the products selected when it was created, even after source prices change.

D

Data definition language
Data definition language, or DDL, is the SQL statement family that creates, changes and removes database structure.
CREATE TABLE, ALTER TABLE and DROP TABLE change the database's structure at different stages.
Data manipulation language
Data manipulation language, or DML, is the SQL statement family that adds, changes and removes rows in existing tables.
Adding an order uses INSERT; correcting its status uses UPDATE; removing its row uses DELETE.
Data type
A data type describes the kind of values a column stores and helps determine their comparison, sorting and arithmetic behavior.
A quantity uses a number type for totals, while a ZIP code uses text to preserve its leading zeros.
DEFAULT
A DEFAULT supplies a value when an insert omits a column; it does not replace an explicitly supplied missing value.
Omitting a stock column with DEFAULT 0 gives zero, while explicitly supplying NULL keeps it missing.
DELETE
The DELETE statement removes whole rows selected by a condition, or every row when no condition is supplied, while retaining the table.
Deleting cancelled old orders leaves other orders in place and keeps the table ready for future inserts.
Dependency
A dependency exists when a database object relies on another object's definition, which can block dropping or changing that object.
An orders foreign key depends on customers, so dropping customers first can fail while the link remains.
DROP CASCADE
PostgreSQL's DROP CASCADE removes dependent objects along with the named object, including referencing foreign keys and dependent views.
Dropping customers with CASCADE can leave orders stored but remove the foreign key that linked them to customers.
DROP COLUMN
The DROP COLUMN operation removes a column and its stored values from a table, and can be blocked by dependent rules or objects.
Dropping a mobile field discards every stored mobile value while leaving the customers' other fields intact.
DROP TABLE
The DROP TABLE statement removes a table together with all its rows and its own constraints, indexes and triggers from the database.
After dropping the archive table, inserting into it fails until a table with that name is created again.

E

excluded
The name excluded refers to the proposed insert row during a PostgreSQL or SQLite conflict update, making its incoming values available.
For a delivery, stock.qty + excluded.qty adds the proposed incoming amount to the quantity already stored.

F

Failed transaction
A PostgreSQL failed transaction follows a statement error and refuses ordinary commands until rollback or recovery to a prior savepoint.
After a rejected balance update, another SELECT is refused until the failed transaction state is cleared.
Floating point
Floating point represents numbers as binary approximations, allowing efficient measurements but possible small decimal rounding errors.
SQLite can evaluate 0.1 + 0.2 = 0.3 as false because its decimal literals use approximate storage.
Foreign key
A foreign key requires nonmissing child values to match a referenced primary or unique parent key when enforcement is enabled.
An order with customer ID 99 fails when no customer 99 exists and the customer relationship is enforced.
Foreign key enforcement
Foreign key enforcement is the database's active checking of references and declared actions when related rows are inserted, changed or removed.
SQLite needs PRAGMA foreign_keys = ON; on the connection before a transaction to check its declared links.

I

Identifier
An identifier is the name of a database object, such as a table or column; double quotes allow spaces or reserved words in it.
The column identifier "order date" needs quotes, while order_date avoids spaces and is easier to reuse.
Identity column
An identity column generates values from a sequence in PostgreSQL when an insert requests a generated value for that column.
INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY supplies new IDs without a manual number in each insert.
IF EXISTS
The IF EXISTS clause suppresses an absence error in a drop statement, while still removing the named object when it does exist.
DROP TABLE IF EXISTS archived_orders; succeeds when the table is absent and removes it when present.
Implicit commit
An implicit commit makes pending changes permanent as an automatic effect of another statement, such as ordinary MySQL permanent-table DDL.
A MySQL table creation can commit an earlier update, so a later rollback does not undo that update.
IN
The IN test checks whether a value matches a member of a list, including a list of keys returned by a nested SELECT query.
Orders for several California customers can be selected with customer IDs returned by one subquery.
INSERT
The INSERT statement adds rows to an existing table, using literal value groups or query results that must meet the destination's rules.
A shop inserts a new product with its SKU, name and price while letting the database generate its ID.
INSERT SELECT
An INSERT SELECT statement copies rows returned by a query into an existing table, matching selected columns to target columns by position.
The shop previews pre-2026 orders, then copies the returned records into its already defined archive table.
INTEGER
The INTEGER type represents whole numbers, making it suitable for counts and exact amounts stored as whole cents.
An exact SQLite amount of 19.99 can be stored as 1999 in an integer cents column for later arithmetic.
IS NULL
The IS NULL test selects missing values directly, unlike ordinary equality with NULL, which is never true for a missing value.
WHERE phone IS NULL finds customers without a phone number; WHERE phone = NULL finds no such rows.
ISO date
An ISO date written as YYYY-MM-DD places the year first, allowing consistently formatted date text to sort chronologically.
SQLite text dates such as '2026-03-15' sort by year, month and day when they all use the same format.

M

Multi-row insert
A multi-row insert supplies several parenthesized value groups in one statement, checked as a whole under ordinary constraint handling.
Three customer rows can be added with one statement; an ordinary constraint failure in one rejects all three.

N

Named constraint
A named constraint has a chosen identifier that helps locate the rule in error messages and refer to it during later structure changes.
CONSTRAINT price_positive CHECK (price > 0) gives the positive-price rule a name for later maintenance.
Natural key
A natural key is a real-world value that already identifies a record and is used as its key instead of an artificial number.
A book's ISBN can identify its edition, while a generated internal book ID would be a surrogate key.
NOT NULL
A NOT NULL constraint requires a column's value to be present in every row, while accepting empty text in SQLite and PostgreSQL.
A required product name left out of an insert fails when it has neither a default nor a supplied value.
NULL
NULL is SQL's marker for a missing or unknown value, distinct from both a numeric zero and an empty string of text.
An optional phone field uses NULL when no phone number is known; IS NULL finds those customers.
NUMERIC precision
NUMERIC precision is the declared total number of decimal digits, including those before and after the decimal point.
PostgreSQL NUMERIC(8, 2) allows six digits before the decimal point and two after it, up to 999999.99.

O

ON DELETE CASCADE
The ON DELETE CASCADE action deletes referring child rows automatically when their parent row is deleted under an enforced foreign key.
With a cascade, deleting customer Ana removes her orders 101 and 102, while customer Ben and his order 103 remain present.
ON DELETE SET NULL
The ON DELETE SET NULL action retains child rows after a parent deletion but clears their links, requiring nullable reference columns.
When a supplier is removed, products can remain with missing supplier IDs if that link is optional.
Operator precedence
Operator precedence determines which parts of an expression are grouped first; SQL evaluates AND before OR unless parentheses change it.
Grouping two statuses in parentheses makes a shared date limit apply to both branches of the condition.

P

Parent table
A parent table holds the referenced key in a foreign key relationship, so its matching rows must exist before dependent child rows.
The customers table is the parent when each order's customer ID refers to the customer's primary key.
Primary key
A primary key is a column or combination of columns that uniquely identifies a row and is required to have a nonmissing value.
A customer ID lets an update target one customer even when several customers have the same name.

R

RELEASE
The RELEASE command removes a savepoint without undoing its later changes or independently committing the outer transaction.
After releasing a savepoint inside BEGIN, a full rollback can still undo the transaction's pending work.
RETURNING
A RETURNING clause makes a write return chosen values from affected rows, including generated IDs in PostgreSQL and recent SQLite.
An order insert can return its new ID so that the next insert can link order items to the actual order.
ROLLBACK
The ROLLBACK command undoes pending changes in the current transaction and ends it, without undoing previously committed transactions.
An uncommitted delete that empties the orders table can be rolled back to restore its original rows.
ROLLBACK TO
The ROLLBACK TO command undoes changes made after a named savepoint, leaving the outer transaction open for more work or a final decision.
Rolling back to a savepoint named after_first, set between two balance increases, removes the later increase but keeps the earlier one pending.
ROUND
The ROUND function requests rounding to a chosen number of decimal places, useful where storage does not enforce a decimal scale.
ROUND(price * 1.10, 2) requests a two-place result for a SQLite price calculation that would produce 21.989.

S

Savepoint
A savepoint is a named intermediate point in a transaction that allows later work to be undone while earlier pending changes are retained.
Placing a savepoint after the first update lets the second update be undone without losing the first.
Scale
The scale of a decimal type is the number of digits after the decimal point; PostgreSQL rounds stored values to that scale.
A PostgreSQL NUMERIC(8, 2) column stores 12.345 as 12.35 because the declared scale is two.
SET assignment
A SET assignment names a column and its new value or expression inside UPDATE; commas separate assignments to several columns.
SET in_stock = in_stock - 1 decreases the stored count, while SET in_stock = 1 replaces it with one.
Soft delete
A soft delete marks a stored row as removed through a value such as a deletion timestamp, requiring active-row queries to exclude it.
Setting a customer's deleted_at retains the row, so active customer queries add deleted_at IS NULL.
Staging table
A staging table temporarily holds imported data so it can be inspected and cleaned before it is copied into its final constrained destination.
Blank imported email strings can become NULL through NULLIF(TRIM(email), '') during the copy query.
String literal
A string literal is text written as a value in SQL using single quotes, with internal apostrophes doubled to keep them inside the text.
The SQL literal 'O''Brien' stores the name "O'Brien" with one apostrophe instead of ending the value early.
Subquery
A subquery is a SELECT nested within another statement, supplying values or rows that the surrounding statement can use.
A delete can use order_id IN (SELECT id FROM orders WHERE status = 'cancelled') to choose related items.
Surrogate key
A surrogate key is an artificial identifier with no descriptive meaning, often generated so that real-world details can change independently.
A customer's generated ID stays the same after an email change, preserving references from orders.

T

Table rebuild
A table rebuild creates a replacement definition, copies the existing data, replaces the old table and restores dependent objects.
SQLite can gain a new existing-column check through a transaction that rebuilds the table and checks the copied rows.
Transaction
A transaction groups statements into one unit of work whose pending changes can be kept together with COMMIT or undone with ROLLBACK.
A transfer places its withdrawal and deposit inside one transaction so that an incomplete transfer can be undone.
TRUNCATE
The TRUNCATE statement empties an entire table without a WHERE filter in databases that support it; SQLite does not provide it.
A PostgreSQL table can be emptied with TRUNCATE TABLE, but its dependency and transaction rules still matter.
Type affinity
Type affinity is SQLite's preference for a column's storage type, which can convert suitable input without rejecting every other kind.
An ordinary SQLite integer column converts '5' to 5 but can keep 'abc' as text without an error.

U

UNIQUE
A UNIQUE constraint prevents repeated nonmissing values or value combinations, with missing-value behavior depending on the database.
UNIQUE (order_id, product_id) allows the same product in different orders but rejects a repeated pair.
UPDATE
The UPDATE statement assigns new values to columns in existing rows, choosing its target rows with an optional WHERE condition.
UPDATE products SET price = 22.50 WHERE id = 3; changes one product without inserting a new product row.
Upsert
An upsert tries to insert a row and can update an existing row when a key or unique value conflicts with the proposed new data.
A stock import can add a new SKU or update its count with ON CONFLICT (sku) DO UPDATE when it exists.

W

WHERE condition
A WHERE condition tests each row to choose it for a query or write; only rows for which the condition is true are selected.
An update filtered by the product's primary key reaches at most one row, even if product names repeat.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started