Master SQL Fundamentals: Complete Guide to CREATE, INSERT, SELECT, UPDATE, DELETE Operations

10 minute read

Introduction

Structured Query Language (SQL) is the foundation of database management and manipulation. Whether you’re building web applications, analyzing data, or managing enterprise systems, mastering these fundamental SQL operations is essential for any developer or data professional.

This comprehensive guide covers the six core SQL operations that form the backbone of database interactions: CREATE, INSERT, SELECT, UPDATE, DELETE, and DROP. These operations are often referred to as CRUD (Create, Read, Update, Delete) operations, plus schema management.

Understanding SQL Operations

What You’ll Learn

  • Data Definition Language (DDL): CREATE and DROP statements for managing database structure
  • Data Manipulation Language (DML): INSERT, SELECT, UPDATE, and DELETE for working with data
  • Best Practices: Modern SQL techniques and optimization strategies
  • Real-world Examples: Practical scenarios and common use cases
  • Error Handling: Common mistakes and how to avoid them

Prerequisites

  • Basic understanding of databases and tables
  • Access to SQL Server Management Studio or similar database tool
  • Familiarity with data types and database concepts

1. CREATE - Building Your Database Structure

The CREATE statement is used to create database objects like tables, indexes, views, and stored procedures. Let’s start with creating a table.

Basic Table Creation

-- Create a comprehensive employee table
CREATE TABLE employees (
    employee_id INT PRIMARY KEY IDENTITY(1,1),
    first_name NVARCHAR(50) NOT NULL,
    last_name NVARCHAR(50) NOT NULL,
    email NVARCHAR(100) UNIQUE NOT NULL,
    phone NVARCHAR(15),
    hire_date DATE NOT NULL DEFAULT GETDATE(),
    job_title NVARCHAR(100),
    salary DECIMAL(10,2),
    department_id INT,
    is_active BIT DEFAULT 1,
    created_at DATETIME2 DEFAULT GETDATE(),
    updated_at DATETIME2
);

Advanced Table Creation with Constraints

-- Create departments table with relationships
CREATE TABLE departments (
    department_id INT PRIMARY KEY IDENTITY(1,1),
    department_name NVARCHAR(100) NOT NULL UNIQUE,
    manager_id INT,
    budget DECIMAL(15,2) CHECK (budget > 0),
    location NVARCHAR(100),
    created_at DATETIME2 DEFAULT GETDATE()
);

-- Add foreign key constraint
ALTER TABLE employees
ADD CONSTRAINT FK_employees_department 
    FOREIGN KEY (department_id) 
    REFERENCES departments(department_id);

-- Add check constraints for data validation
ALTER TABLE employees
ADD CONSTRAINT CHK_employees_salary 
    CHECK (salary >= 0 AND salary <= 1000000);

ALTER TABLE employees
ADD CONSTRAINT CHK_employees_email_format 
    CHECK (email LIKE '%@%.%');

Creating Indexes for Performance

-- Create indexes for better query performance
CREATE INDEX IX_employees_email ON employees(email);
CREATE INDEX IX_employees_department_id ON employees(department_id);
CREATE INDEX IX_employees_hire_date ON employees(hire_date);

-- Create composite index for common queries
CREATE INDEX IX_employees_name_department 
    ON employees(last_name, first_name, department_id);

2. INSERT - Adding Data to Your Tables

The INSERT statement adds new records to your tables. Let’s explore different methods and best practices.

Basic INSERT Operations

-- Insert a single employee record
INSERT INTO employees (
    first_name, 
    last_name, 
    email, 
    phone, 
    hire_date, 
    job_title, 
    salary, 
    department_id
)
VALUES (
    'John', 
    'Smith', 
    'john.smith@company.com', 
    '+1-555-0123', 
    '2024-01-15', 
    'Software Engineer', 
    75000.00, 
    1
);

Multiple Row INSERT (SQL Server 2008+)

-- Insert multiple employees in a single statement
INSERT INTO employees (
    first_name, last_name, email, job_title, salary, department_id, hire_date
)
VALUES 
    ('Sarah', 'Johnson', 'sarah.johnson@company.com', 'Senior Developer', 85000, 1, '2024-01-10'),
    ('Mike', 'Wilson', 'mike.wilson@company.com', 'Project Manager', 90000, 2, '2024-01-12'),
    ('Emily', 'Brown', 'emily.brown@company.com', 'Data Analyst', 65000, 3, '2024-01-14'),
    ('David', 'Davis', 'david.davis@company.com', 'UX Designer', 70000, 4, '2024-01-16'),
    ('Lisa', 'Garcia', 'lisa.garcia@company.com', 'Marketing Specialist', 60000, 5, '2024-01-18');

INSERT with Subquery

-- Insert data from another table or query
INSERT INTO employee_archive (
    employee_id, full_name, job_title, final_salary, termination_date
)
SELECT 
    employee_id,
    CONCAT(first_name, ' ', last_name) AS full_name,
    job_title,
    salary,
    GETDATE()
FROM employees 
WHERE is_active = 0;

INSERT with Error Handling

-- Safe INSERT with transaction and error handling
BEGIN TRANSACTION;

BEGIN TRY
    INSERT INTO employees (
        first_name, last_name, email, job_title, salary, department_id
    )
    VALUES (
        'Alice', 'Cooper', 'alice.cooper@company.com', 
        'Senior Analyst', 80000, 3
    );
    
    COMMIT TRANSACTION;
    PRINT 'Employee added successfully.';
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    PRINT 'Error occurred: ' + ERROR_MESSAGE();
END CATCH;

3. SELECT - Retrieving and Querying Data

The SELECT statement is the most frequently used SQL operation for retrieving data from your database.

Basic SELECT Operations

-- Select all columns (avoid in production)
SELECT * FROM employees;

-- Select specific columns (recommended)
SELECT 
    employee_id,
    first_name,
    last_name,
    email,
    job_title,
    salary
FROM employees;

SELECT with Filtering and Conditions

-- Filter employees by department and salary
SELECT 
    first_name,
    last_name,
    job_title,
    salary,
    hire_date
FROM employees
WHERE department_id = 1 
    AND salary >= 70000
    AND is_active = 1
ORDER BY salary DESC;

-- Using LIKE for pattern matching
SELECT 
    employee_id,
    CONCAT(first_name, ' ', last_name) AS full_name,
    email,
    job_title
FROM employees
WHERE job_title LIKE '%Engineer%'
   OR email LIKE '%@company.com'
ORDER BY last_name, first_name;

Advanced SELECT with JOINs

-- Join employees with departments
SELECT 
    e.employee_id,
    e.first_name,
    e.last_name,
    e.job_title,
    e.salary,
    d.department_name,
    d.location
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
WHERE e.is_active = 1
ORDER BY d.department_name, e.last_name;

-- Left join to include employees without departments
SELECT 
    e.first_name,
    e.last_name,
    e.job_title,
    ISNULL(d.department_name, 'Unassigned') AS department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
ORDER BY e.employee_id;

Aggregate Functions and Grouping

-- Calculate statistics by department
SELECT 
    d.department_name,
    COUNT(e.employee_id) AS employee_count,
    AVG(e.salary) AS average_salary,
    MIN(e.salary) AS min_salary,
    MAX(e.salary) AS max_salary,
    SUM(e.salary) AS total_salary_cost
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id 
    AND e.is_active = 1
GROUP BY d.department_id, d.department_name
HAVING COUNT(e.employee_id) > 0
ORDER BY average_salary DESC;

Window Functions (SQL Server 2005+)

-- Advanced analytics with window functions
SELECT 
    employee_id,
    first_name,
    last_name,
    job_title,
    salary,
    -- Ranking within department
    RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS salary_rank,
    -- Running total
    SUM(salary) OVER (PARTITION BY department_id ORDER BY hire_date) AS running_total,
    -- Percentage of department total
    FORMAT(
        salary * 100.0 / SUM(salary) OVER (PARTITION BY department_id), 
        'N2'
    ) + '%' AS salary_percentage
FROM employees
WHERE is_active = 1
ORDER BY department_id, salary_rank;

4. UPDATE - Modifying Existing Data

The UPDATE statement modifies existing records in your tables.

Basic UPDATE Operations

-- Update a single employee's information
UPDATE employees
SET 
    job_title = 'Senior Software Engineer',
    salary = 85000,
    updated_at = GETDATE()
WHERE employee_id = 1;

Conditional Updates

-- Give salary increases based on performance and tenure
UPDATE employees
SET 
    salary = 
        CASE 
            WHEN DATEDIFF(YEAR, hire_date, GETDATE()) >= 5 THEN salary * 1.10  -- 10% for 5+ years
            WHEN DATEDIFF(YEAR, hire_date, GETDATE()) >= 2 THEN salary * 1.07  -- 7% for 2-4 years
            WHEN DATEDIFF(YEAR, hire_date, GETDATE()) >= 1 THEN salary * 1.05  -- 5% for 1+ years
            ELSE salary
        END,
    updated_at = GETDATE()
WHERE is_active = 1
    AND salary <= 100000;  -- Cap increases

UPDATE with JOINs

-- Update employees based on department information
UPDATE e
SET 
    e.salary = e.salary * 1.08,  -- 8% increase for high-budget departments
    e.updated_at = GETDATE()
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
WHERE d.budget > 500000
    AND e.is_active = 1
    AND e.salary < 90000;

Safe UPDATE with Transaction

-- Safe update with rollback capability
BEGIN TRANSACTION;

-- Show records that will be affected
SELECT 
    employee_id, 
    first_name + ' ' + last_name AS name,
    job_title,
    salary AS current_salary,
    salary * 1.05 AS new_salary
FROM employees
WHERE department_id = 1 AND is_active = 1;

-- Perform the update
UPDATE employees
SET 
    salary = salary * 1.05,
    updated_at = GETDATE()
WHERE department_id = 1 
    AND is_active = 1;

-- Check the results
SELECT @@ROWCOUNT AS rows_affected;

-- Uncomment to commit or rollback
-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

5. DELETE - Removing Data

The DELETE statement removes records from your tables. Always use with caution!

Basic DELETE Operations

-- Delete a specific employee
DELETE FROM employees
WHERE employee_id = 10;

-- Delete employees from a specific department
DELETE FROM employees
WHERE department_id = 5 
    AND is_active = 0;

Conditional DELETE

-- Delete old inactive records
DELETE FROM employees
WHERE is_active = 0 
    AND updated_at < DATEADD(YEAR, -2, GETDATE());
-- Instead of hard delete, use soft delete for data preservation
UPDATE employees
SET 
    is_active = 0,
    termination_date = GETDATE(),
    updated_at = GETDATE()
WHERE employee_id = 15;

-- Create a view for active employees
CREATE VIEW active_employees AS
SELECT 
    employee_id,
    first_name,
    last_name,
    email,
    job_title,
    salary,
    department_id,
    hire_date
FROM employees
WHERE is_active = 1;

DELETE with JOINs

-- Delete employees from departments that are being closed
DELETE e
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name IN ('Legacy Systems', 'Discontinued Products');

Safe DELETE with Backup

-- Create backup before deletion
SELECT *
INTO employees_backup_before_delete
FROM employees
WHERE department_id = 3;

-- Perform the deletion
BEGIN TRANSACTION;

DELETE FROM employees
WHERE department_id = 3 
    AND is_active = 0;

SELECT @@ROWCOUNT AS deleted_rows;

-- Review and commit/rollback
-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

6. DROP - Removing Database Objects

The DROP statement permanently removes database objects. Use with extreme caution!

DROP TABLE

-- Drop a single table
DROP TABLE IF EXISTS temp_employees;  -- SQL Server 2016+

-- For older versions
IF OBJECT_ID('temp_employees', 'U') IS NOT NULL
    DROP TABLE temp_employees;

DROP with Dependencies

-- Remove constraints before dropping tables
ALTER TABLE employees 
DROP CONSTRAINT IF EXISTS FK_employees_department;

-- Drop indexes
DROP INDEX IF EXISTS IX_employees_email ON employees;

-- Drop the table
DROP TABLE IF EXISTS employees;

DROP Other Objects

-- Drop view
DROP VIEW IF EXISTS active_employees;

-- Drop stored procedure
DROP PROCEDURE IF EXISTS sp_get_employee_by_id;

-- Drop function
DROP FUNCTION IF EXISTS fn_calculate_bonus;

-- Drop entire database (EXTREME CAUTION!)
-- DROP DATABASE test_database;

Modern SQL Best Practices

1. Use Transactions for Data Integrity

BEGIN TRANSACTION;

BEGIN TRY
    -- Multiple related operations
    INSERT INTO departments (department_name, budget) 
    VALUES ('New Department', 100000);
    
    DECLARE @new_dept_id INT = SCOPE_IDENTITY();
    
    UPDATE employees 
    SET department_id = @new_dept_id 
    WHERE employee_id IN (1, 2, 3);
    
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW;  -- Re-throw the error
END CATCH;

2. Parameterized Queries (Prevent SQL Injection)

-- Using parameters in stored procedures
CREATE PROCEDURE sp_get_employees_by_department
    @department_id INT,
    @min_salary DECIMAL(10,2) = 0
AS
BEGIN
    SELECT 
        employee_id,
        first_name,
        last_name,
        job_title,
        salary
    FROM employees
    WHERE department_id = @department_id
        AND salary >= @min_salary
        AND is_active = 1
    ORDER BY last_name, first_name;
END;

3. Data Validation and Constraints

-- Add comprehensive data validation
ALTER TABLE employees
ADD CONSTRAINT CHK_employees_hire_date 
    CHECK (hire_date >= '1900-01-01' AND hire_date <= GETDATE());

ALTER TABLE employees
ADD CONSTRAINT CHK_employees_phone_format 
    CHECK (phone LIKE '+[0-9]%' OR phone IS NULL);

4. Indexing Strategy

-- Create covering indexes for common queries
CREATE INDEX IX_employees_covering_search
ON employees (department_id, is_active)
INCLUDE (first_name, last_name, job_title, salary, email);

-- Partial index for active employees only
CREATE INDEX IX_employees_active_salary
ON employees (salary DESC)
WHERE is_active = 1;

Common Pitfalls and How to Avoid Them

1. Missing WHERE Clauses

-- DANGEROUS: Updates all records!
-- UPDATE employees SET salary = 50000;

-- CORRECT: Always use WHERE clause
UPDATE employees 
SET salary = 50000 
WHERE employee_id = 1;

2. Not Using Transactions for Multiple Operations

-- RISKY: Operations might partially fail
-- INSERT INTO departments VALUES ('IT', 1000000);
-- INSERT INTO employees VALUES ('John', 'Doe', ...);

-- SAFE: Use transactions
BEGIN TRANSACTION;
BEGIN TRY
    INSERT INTO departments VALUES ('IT', 1000000);
    INSERT INTO employees VALUES ('John', 'Doe', ...);
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW;
END CATCH;

3. Ignoring NULL Values

-- Handle NULL values properly
SELECT 
    employee_id,
    first_name,
    last_name,
    ISNULL(phone, 'No phone') AS phone_display,
    COALESCE(email, 'no-email@company.com') AS contact_email
FROM employees;

Performance Optimization Tips

1. Use Appropriate Data Types

-- Efficient data types
CREATE TABLE optimized_employees (
    employee_id INT IDENTITY(1,1),           -- Use INT instead of BIGINT if possible
    first_name NVARCHAR(50),                 -- Use appropriate length
    is_active BIT,                           -- Use BIT for boolean values
    hire_date DATE,                          -- Use DATE instead of DATETIME if time not needed
    salary DECIMAL(10,2),                    -- Precise decimal for money
    created_at DATETIME2(0)                  -- Reduce precision if seconds are enough
);

2. Efficient Querying

-- Use EXISTS instead of IN for better performance
SELECT e.employee_id, e.first_name, e.last_name
FROM employees e
WHERE EXISTS (
    SELECT 1 
    FROM departments d 
    WHERE d.department_id = e.department_id 
        AND d.budget > 500000
);

-- Use LIMIT/TOP to restrict result sets
SELECT TOP 10
    employee_id,
    first_name,
    last_name,
    salary
FROM employees
ORDER BY salary DESC;

Conclusion

Mastering these fundamental SQL operations provides the foundation for effective database management and application development. Remember these key principles:

Key Takeaways:

  1. Always use WHERE clauses with UPDATE and DELETE statements
  2. Implement transactions for data integrity in multi-step operations
  3. Use parameterized queries to prevent SQL injection
  4. Choose appropriate data types and constraints for data validation
  5. Create indexes strategically for query performance
  6. Consider soft deletes instead of hard deletes for data preservation
  7. Test operations in development environments before production

Quick Reference Summary:

-- CREATE: Define database structure
CREATE TABLE table_name (column_definitions);

-- INSERT: Add new data
INSERT INTO table_name (columns) VALUES (values);

-- SELECT: Retrieve data
SELECT columns FROM table_name WHERE conditions;

-- UPDATE: Modify existing data
UPDATE table_name SET column = value WHERE conditions;

-- DELETE: Remove data
DELETE FROM table_name WHERE conditions;

-- DROP: Remove database objects
DROP TABLE table_name;

With these fundamentals mastered, you’re well-equipped to build robust database applications and perform effective data management tasks. Continue practicing with real-world scenarios to strengthen your SQL skills.

Comments