Batch 3: SQL Databases LDAP YAML JSON ← Full TOC

← SQL Index

📋 Core SQL — SELECT, INSERT, UPDATE, DELETE, JOINs, GROUP BY

Standard SQL (Structured Query Language) works across MySQL, PostgreSQL, Oracle, SQL Server, and SQLite. Master these statements and you can work with any relational database. SQL is case-insensitive for keywords — UPPERCASE by convention.

📋 SQL Reference

Statement / FeatureSyntaxDescription
SELECTSELECT col1, col2 FROM table WHERE cond ORDER BY col LIMIT nRetrieve rows from one or more tables
SELECT *SELECT * FROM tableSelect all columns — avoid in production
SELECT DISTINCTSELECT DISTINCT col FROM tableReturn unique values only
WHEREWHERE col = val AND col2 > val2Filter rows by condition
AND / OR / NOTWHERE a = 1 AND b = 2 OR NOT c = 3Combine conditions
BETWEENWHERE age BETWEEN 18 AND 65Inclusive range filter
INWHERE status IN ('active','pending')Match any value in list
NOT INWHERE id NOT IN (1,2,3)Exclude values in list
LIKEWHERE name LIKE 'A%' / '%son' / '_ob'Pattern match: % = any chars, _ = one char
IS NULLWHERE notes IS NULL / IS NOT NULLTest for null values
ORDER BYORDER BY score DESC, name ASCSort results — ASC default
LIMIT / TOPLIMIT 10 OFFSET 20 / TOP 10Paginate results (MySQL/PG: LIMIT; SQL Server: TOP)
INSERT INTOINSERT INTO table (col1,col2) VALUES (v1,v2)Add one row
INSERT multipleINSERT INTO table (col1,col2) VALUES (v1,v2),(v3,v4)Add multiple rows
UPDATEUPDATE table SET col=val WHERE conditionModify existing rows — ALWAYS use WHERE!
DELETEDELETE FROM table WHERE conditionRemove rows — ALWAYS use WHERE!
TRUNCATETRUNCATE TABLE tablenameDelete all rows fast (no WHERE, no rollback)
JOIN (INNER)SELECT * FROM a JOIN b ON a.id = b.a_idReturn rows matching in both tables
LEFT JOINSELECT * FROM a LEFT JOIN b ON a.id = b.a_idAll rows from left + matching from right
RIGHT JOINSELECT * FROM a RIGHT JOIN b ON a.id = b.a_idAll rows from right + matching from left
FULL OUTER JOINSELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_idAll rows from both tables
SELF JOINSELECT a.name, b.name FROM emp a JOIN emp b ON a.mgr_id = b.idJoin table to itself
CROSS JOINSELECT * FROM a CROSS JOIN bCartesian product — every combination
GROUP BYGROUP BY colGroup rows for aggregate functions
HAVINGHAVING COUNT(*) > 5Filter groups (like WHERE but for aggregates)
UNIONSELECT ... UNION SELECT ...Combine result sets (removes duplicates)
UNION ALLSELECT ... UNION ALL SELECT ...Combine result sets (keeps duplicates)
INTERSECTSELECT ... INTERSECT SELECT ...Rows in both result sets
EXCEPT / MINUSSELECT ... EXCEPT SELECT ...Rows in first but not second
SubquerySELECT * FROM t WHERE id IN (SELECT id FROM t2)Nested query
Correlated subqueryWHERE salary > (SELECT AVG(salary) FROM emp e2 WHERE e2.dept=e1.dept)Subquery referencing outer query
WITH (CTE)WITH cte AS (SELECT ...) SELECT * FROM cteCommon Table Expression — named subquery
Recursive CTEWITH RECURSIVE cte AS (base UNION ALL recursive_step)Hierarchical/recursive queries
CASECASE WHEN score>=90 THEN 'A' WHEN score>=80 THEN 'B' ELSE 'C' ENDConditional expression
COALESCECOALESCE(col1, col2, 'default')Return first non-null value
NULLIFNULLIF(a, b)Return NULL if a=b, else return a
CASTCAST(col AS INTEGER) / CAST(col AS VARCHAR(50))Convert data type
CONCATCONCAT(first,' ',last) / first || ' ' || lastConcatenate strings
ALIASSELECT col AS alias, table AS tRename column or table in output

💡 Example

-- Core SQL Examples — works on MySQL, PostgreSQL, SQLite

-- ── Schema ───────────────────────────────────────────────────
CREATE TABLE departments (
    dept_id   INTEGER PRIMARY KEY,
    dept_name VARCHAR(100) NOT NULL,
    budget    DECIMAL(12,2) DEFAULT 0.00
);

CREATE TABLE employees (
    emp_id    INTEGER PRIMARY KEY,
    name      VARCHAR(100) NOT NULL,
    email     VARCHAR(150) UNIQUE NOT NULL,
    dept_id   INTEGER REFERENCES departments(dept_id),
    salary    DECIMAL(10,2) NOT NULL,
    hire_date DATE NOT NULL,
    status    VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active','inactive','terminated')),
    manager_id INTEGER REFERENCES employees(emp_id)
);

-- ── INSERT ───────────────────────────────────────────────────
INSERT INTO departments VALUES (1,'Engineering',500000),(2,'Marketing',200000),(3,'HR',150000);
INSERT INTO employees (emp_id,name,email,dept_id,salary,hire_date) VALUES
    (1,'Alice Smith',  'alice@mwu.com',1,95000,'2020-03-01'),
    (2,'Bob Jones',    'bob@mwu.com',  1,87000,'2021-06-15'),
    (3,'Carol Davis',  'carol@mwu.com',2,72000,'2019-11-01'),
    (4,'Dave Wilson',  'dave@mwu.com', 3,68000,'2022-01-10'),
    (5,'Eve Martinez', 'eve@mwu.com',  1,102000,'2018-07-20');

-- ── SELECT with filters ──────────────────────────────────────
SELECT name, salary, hire_date
FROM employees
WHERE salary > 80000
  AND status = 'active'
ORDER BY salary DESC;

-- ── JOINs ───────────────────────────────────────────────────
SELECT e.name, e.salary, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
WHERE e.status = 'active'
ORDER BY d.dept_name, e.salary DESC;

-- ── GROUP BY with HAVING ─────────────────────────────────────
SELECT d.dept_name,
       COUNT(e.emp_id)    AS headcount,
       AVG(e.salary)      AS avg_salary,
       MAX(e.salary)      AS max_salary,
       MIN(e.hire_date)   AS oldest_hire
FROM departments d
LEFT JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id, d.dept_name
HAVING COUNT(e.emp_id) > 0
ORDER BY avg_salary DESC;

-- ── CASE expression ──────────────────────────────────────────
SELECT name, salary,
    CASE
        WHEN salary >= 100000 THEN 'Senior'
        WHEN salary >= 80000  THEN 'Mid-level'
        ELSE 'Junior'
    END AS level
FROM employees ORDER BY salary DESC;

-- ── Subquery ─────────────────────────────────────────────────
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees)
ORDER BY salary DESC;

-- ── CTE ──────────────────────────────────────────────────────
WITH dept_stats AS (
    SELECT dept_id, AVG(salary) AS avg_sal
    FROM employees GROUP BY dept_id
)
SELECT e.name, e.salary, ds.avg_sal,
       ROUND((e.salary - ds.avg_sal) / ds.avg_sal * 100, 1) AS pct_above_avg
FROM employees e
JOIN dept_stats ds ON e.dept_id = ds.dept_id
ORDER BY pct_above_avg DESC;

-- ── UPDATE / DELETE ──────────────────────────────────────────
UPDATE employees SET salary = salary * 1.05 WHERE dept_id = 1;
DELETE FROM employees WHERE status = 'terminated' AND hire_date < '2020-01-01';

🏠 Index  |  DDL & Schema →