SQL, or Structured Query Language, is the standard language for querying and manipulating relational data. At its core, every data-retrieval query begins with the SELECT statement, which pulls rows from one or more tables. The supporting clauses give you precise control over which rows appear and how they are ordered. WHERE filters individual rows before any grouping occurs, while the related HAVING clause filters aggregated groups after GROUP BY has done its work, making it the right choice for conditions on totals, averages, or counts. The DISTINCT keyword removes duplicate rows so the result set contains only unique values, and ORDER BY sorts the output; by default this is ascending, but you can reverse it with the DESC keyword. To paginate through results, LIMIT sets the maximum number of rows returned while OFFSET specifies how many rows to skip before output begins — for example, LIMIT 10 OFFSET 20 yields rows 21 through 30.
Aliases give temporary names to columns or tables, making queries easier to read and letting you reference computed expressions elsewhere in the same query. You can write either SELECT column AS alias_name or simply SELECT column alias_name, and the same applies to tables in the FROM clause. A critical concept for understanding why some references work and others do not is the order of execution of a SQL query: the engine processes FROM and JOIN first, then WHERE, GROUP BY, HAVING, SELECT, DISTINCT, ORDER BY, and finally LIMIT/OFFSET. Because SELECT runs after WHERE and GROUP BY but before ORDER BY, a column alias declared in SELECT is unavailable in WHERE or GROUP BY but perfectly legal in ORDER BY.
No treatment of SELECT is complete without addressing NULL, the special marker representing the absence of any value, distinct from zero and from the empty string. To test for NULL, use IS NULL or IS NOT NULL; equality comparisons such as = NULL are never true because NULL is not comparable to anything, including itself. The COALESCE function returns the first non-NULL argument from its list, giving you a clean way to substitute a default value for missing data, and aggregate functions like SUM silently ignore NULLs by default. COUNT behaves specially: COUNT(*) counts every row including those with NULL values, while COUNT(column) counts only rows where that specific column is non-NULL.