DEV Community

CodeWithDhanian
CodeWithDhanian

Posted on

Day 5: Inserting Data – INSERT INTO, Multiple Rows, and RETURNING

Introduction: Why Data Insertion Matters in Real-World Development

In any production database system, inserting data is the primary way information enters your application. Whether you are building a user registration flow, logging e-commerce orders, importing CSV analytics data, or syncing IoT sensor readings, the INSERT statement is the gateway between your application code and persistent storage.

Mastering insertion is not just about syntax — it directly impacts:

  • Application performance (single-row vs. bulk operations)
  • Data integrity (handling defaults, constraints, and generated values)
  • User experience (returning fresh IDs or computed fields instantly)
  • Scalability (avoiding costly round-trips between app and database)

By the end of this tutorial you will confidently insert single records, bulk-load hundreds or thousands of rows efficiently, retrieve auto-generated values in one atomic operation using the RETURNING clause (PostgreSQL), and apply production-grade best practices that senior engineers use daily.

We will use PostgreSQL for the main examples because the RETURNING clause is native and extremely powerful here. MySQL equivalents and differences are clearly noted so you can apply the same concepts regardless of your stack.

1. The INSERT INTO Statement – Core Concepts

The INSERT statement tells the database: “Here is new data — please store it according to the table’s structure.”

Basic Syntax

INSERT INTO table_name (column1, column2, ..., columnN)
VALUES (value1, value2, ..., valueN);
Enter fullscreen mode Exit fullscreen mode
  • You explicitly list the columns you want to populate.
  • The database fills any omitted columns with their DEFAULT value or NULL (if allowed).
  • Order of values must match the order of columns in the parentheses.

Why list columns explicitly?

It makes your code resilient to future schema changes (new columns added later) and improves readability/maintainability.

2. Inserting a Single Row – Step-by-Step

Assume we have this table (created in Day 4):

CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,        -- Auto-incrementing ID (PostgreSQL)
    name TEXT NOT NULL,
    price NUMERIC(10,2) DEFAULT 0.00,
    stock INTEGER DEFAULT 0,
    created_at TIMESTAMPTZ DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Single-row insertion example

-- Example 1: Full column list (most explicit and safest)
INSERT INTO products (name, price, stock)
VALUES ('Wireless Bluetooth Headphones', 89.99, 150);

-- Example 2: Omit columns that have defaults or are auto-generated
INSERT INTO products (name, price)
VALUES ('USB-C Cable', 12.50);
Enter fullscreen mode Exit fullscreen mode

What happens behind the scenes

  1. Database validates constraints (NOT NULL, data types, CHECK constraints).
  2. Generates default values where needed.
  3. Writes the row to disk (within a transaction).
  4. Returns success or raises an error.

MySQL note: Use the same syntax. The SERIAL type becomes AUTO_INCREMENT and the primary key.

3. Inserting Multiple Rows Efficiently

Inserting rows one by one in a loop is a performance anti-pattern. Databases are optimized for set-based operations.

Multi-row INSERT syntax

INSERT INTO products (name, price, stock)
VALUES 
    ('Smart Watch', 249.99, 75),
    ('Laptop Stand', 34.50, 200),
    ('Wireless Mouse', 29.99, 120);
Enter fullscreen mode Exit fullscreen mode

Benefits

  • One network round-trip instead of dozens.
  • Single transaction → atomicity.
  • Database can optimize batch writing and indexing.

Production tip: For thousands of rows, use PostgreSQL’s COPY command or prepared statements with batching in your application language (e.g., pg driver in Node.js with multi-row mode).

4. Handling NULL, DEFAULT, and Constraints

-- Explicitly set NULL (only if column allows it)
INSERT INTO products (name, price, stock)
VALUES ('Test Product', NULL, NULL);

-- Let DEFAULT kick in
INSERT INTO products (name)
VALUES ('Free Sample Item');
Enter fullscreen mode Exit fullscreen mode

Warning: Never rely on implicit column order for critical applications. Always name columns.

5. The RETURNING Clause – The Magic of Getting Data Back Instantly (PostgreSQL)

One of the most powerful features in PostgreSQL. After inserting, you can immediately retrieve any columns — especially auto-generated IDs, timestamps, or computed values — without a second SELECT.

Syntax

INSERT INTO products (name, price, stock)
VALUES ('4K Webcam', 129.99, 40)
RETURNING *;                    -- Return every column
Enter fullscreen mode Exit fullscreen mode

Practical examples

-- Return only the new ID and creation timestamp
INSERT INTO products (name, price, stock)
VALUES ('Mechanical Keyboard', 79.99, 60)
RETURNING product_id, created_at;

-- Return multiple rows when inserting many
INSERT INTO products (name, price, stock)
VALUES 
    ('HDMI Cable', 8.99, 300),
    ('Monitor Arm', 45.00, 25)
RETURNING product_id, name, created_at;
Enter fullscreen mode Exit fullscreen mode

Real-world use case: In a REST API, when a user creates a new order, you can return the full order object (including the generated order_id) in the same HTTP response. No extra query needed.

MySQL equivalent (versions 8.0.21+): MySQL now supports RETURNING in INSERT, but older versions require LAST_INSERT_ID() after the insert:

-- MySQL alternative
INSERT INTO products (name, price, stock) VALUES ('Example', 19.99, 10);
SELECT LAST_INSERT_ID() AS product_id;
Enter fullscreen mode Exit fullscreen mode

6. Best Practices & Production Techniques

  • Always name columns — never use INSERT INTO table VALUES (...) in production code.
  • Use parameterized queries / prepared statements to prevent SQL injection.
  • Batch inserts for bulk data (100–10,000 rows).
  • Wrap in transactions when inserting related data across multiple tables.
  • Validate data in the application layer before hitting the database.
  • Monitor insert performance with EXPLAIN ANALYZE on large operations.
  • Consider ON CONFLICT (PostgreSQL) or INSERT ... ON DUPLICATE KEY UPDATE (MySQL) for upsert patterns.

Example of safe, parameterized insert (conceptual — shown in SQL for clarity)

-- In application code you would use placeholders
PREPARE insert_product AS
INSERT INTO products (name, price, stock)
VALUES ($1, $2, $3)
RETURNING product_id;
Enter fullscreen mode Exit fullscreen mode

7. Common Pitfalls & Troubleshooting

Pitfall Symptom Fix
Forgetting column names Data goes into wrong columns Always list columns
Violating NOT NULL Error: null value in column Provide value or DEFAULT
Type mismatch Error: invalid input syntax Cast or format correctly
Forgetting RETURNING Extra SELECT query needed Add RETURNING when possible
Inserting in loop Slow performance, high latency Use multi-row or COPY

8. Real-World Project Example: E-Commerce Product Import

Imagine you receive a CSV file from your supplier with 5,000 new products.

Instead of looping 5,000 times:

-- PostgreSQL efficient bulk import (Day 5 level)
COPY products (name, price, stock)
FROM '/path/to/products.csv'
DELIMITER ','
CSV HEADER;
Enter fullscreen mode Exit fullscreen mode

Then query the newly imported rows using RETURNING or a timestamp filter.

This pattern is used by Shopify, Amazon, and every serious e-commerce platform.

Conclusion

You now understand not just how to insert data, but why certain patterns matter in production systems. The combination of explicit column lists, multi-row inserts, and the RETURNING clause gives you both safety and speed — the hallmarks of professional database engineering.

Key Takeaways

  • Always specify column names in INSERT statements.
  • Prefer multi-row VALUES for performance.
  • Use RETURNING (PostgreSQL) to eliminate extra queries.
  • Validate early, insert atomically, and monitor with EXPLAIN.
  • Master these fundamentals before moving to advanced topics like triggers or stored procedures.

You have completed Day 5. Your database now has data — the foundation for every query, join, and report you will build in the coming days.

SQL insert and returning cheat sheet

Top comments (0)