July 7, 2026
tsql tutorial beginners — T-SQL Tutorial for Beginners: SELECT, JOINs, and Aggregates

T-SQL Tutorial for Beginners: SELECT, JOINs, and Aggregates (2026)

Updated July 4, 2026: Expanded with SSMS setup, JOIN types, aggregate patterns, and SQL Server 2022 examples.

Transact-SQL (T-SQL) is Microsoft's extension of SQL used in SQL Server and Azure SQL. In this tutorial you will write your first queries, filter rows, combine tables with JOINs, and summarize data with GROUP BY — the core skills every developer and DBA needs.

Prerequisites: Install SQL Server 2022 Developer Edition or use Azure SQL. Read SQL Server Introduction for context. Estimated time: 45–60 minutes.

Developer writing SQL queries in SQL Server Management Studio
Photo by Christopher Gower on Unsplash

1. What is T-SQL?

SQL (Structured Query Language) is the standard language for relational databases. T-SQL adds procedural features — variables, control flow, error handling, and rich functions — on top of ANSI SQL inside SQL Server.

Why learn T-SQL specifically?

  • Every SQL Server app, report, and ETL job reads or writes T-SQL.
  • SSMS, SSRS, SSIS, and Power BI all consume T-SQL or generate it.
  • Job postings for "SQL developer" and "DBA" assume T-SQL fluency.
  • Concepts transfer to Azure SQL, Azure Synapse, and Fabric warehouses.
Concept T-SQL keyword Purpose
Read data SELECT Return rows from one or more tables
Filter WHERE Keep rows matching a condition
Combine tables JOIN Match related rows across tables
Summarize GROUP BY Aggregate values per group
Filter groups HAVING Condition on aggregated results
Relational database tables connected by keys for JOIN queries
Photo by Shubham Dhage on Unsplash

2. Open SSMS and pick a sample database

Launch SQL Server Management Studio (SSMS) and connect to your instance (e.g. localhost\SQL2022DEV or (localdb)\MSSQLLocalDB). Click New Query to open a query window.

For practice data you can:

  1. Restore AdventureWorks2022 from Microsoft's sample downloads, or
  2. Create a tiny database for this lesson:
CREATE DATABASE TSqlDemo;
GO
USE TSqlDemo;
GO

CREATE TABLE dbo.Category (
    CategoryID   INT PRIMARY KEY,
    CategoryName NVARCHAR(50) NOT NULL
);

CREATE TABLE dbo.Product (
    ProductID   INT PRIMARY KEY,
    ProductName NVARCHAR(100) NOT NULL,
    CategoryID  INT NOT NULL REFERENCES dbo.Category(CategoryID),
    ListPrice   DECIMAL(10,2) NOT NULL
);

INSERT INTO dbo.Category VALUES (1, N'Bikes'), (2, N'Components'), (3, N'Accessories');
INSERT INTO dbo.Product VALUES
 (1, N'Road Bike', 1, 1200.00),
 (2, N'Mountain Bike', 1, 950.00),
 (3, N'Brake Pad', 2, 15.50),
 (4, N'Helmet', 3, 45.00),
 (5, N'Water Bottle', 3, 8.99);

Run the script with F5 or the Execute button. The examples below use dbo.Product and dbo.Category; swap in Production.Product if you use AdventureWorks.

Aggregated query results summarized for business reporting
Photo by Deng Xiang on Unsplash

3. SELECT — retrieve columns and rows

The simplest query lists every column from a table:

SELECT * FROM dbo.Product;

Prefer naming only the columns you need — less network traffic and clearer intent:

SELECT ProductID, ProductName, ListPrice
FROM dbo.Product;

Expressions compute new columns on the fly:

SELECT
    ProductName,
    ListPrice,
    ListPrice * 0.9 AS DiscountPrice,
    UPPER(ProductName) AS ProductNameUpper
FROM dbo.Product;

DISTINCT removes duplicate rows:

SELECT DISTINCT CategoryID FROM dbo.Product;

4. WHERE and ORDER BY

WHERE filters rows before they are returned. Combine conditions with AND, OR, and parentheses:

SELECT ProductName, ListPrice
FROM dbo.Product
WHERE ListPrice > 0
  AND CategoryID = 1
ORDER BY ListPrice DESC, ProductName ASC;

Useful patterns:

  • LIKE N'Hel%' — pattern match (% = any characters)
  • BETWEEN 10 AND 100 — inclusive range
  • IN (1, 2, 3) — match any value in a list
  • IS NULL / IS NOT NULL — test for missing data
SELECT ProductName, ListPrice
FROM dbo.Product
WHERE ProductName LIKE N'%Bike%'
   OR ListPrice BETWEEN 10 AND 1000;

ORDER BY sorts the final result set. Add OFFSET … FETCH for paging in SQL Server 2012+:

SELECT ProductName, ListPrice
FROM dbo.Product
ORDER BY ListPrice DESC
OFFSET 0 ROWS FETCH NEXT 3 ROWS ONLY;

5. JOINs — combine tables

Relational data is split across tables linked by keys. JOINs stitch them back together.

INNER JOIN

Returns rows where a match exists in both tables:

SELECT
    c.CategoryName,
    p.ProductName,
    p.ListPrice
FROM dbo.Product AS p
INNER JOIN dbo.Category AS c
    ON p.CategoryID = c.CategoryID;

LEFT JOIN

Keeps every row from the left table; unmatched right-side columns are NULL:

SELECT
    c.CategoryName,
    p.ProductName
FROM dbo.Category AS c
LEFT JOIN dbo.Product AS p
    ON c.CategoryID = p.CategoryID
ORDER BY c.CategoryName;

This shows categories with zero products — useful for data-quality checks.

Join tips

  • Always use explicit INNER JOIN syntax instead of old comma-style joins in the FROM clause.
  • Alias tables (p, c) to keep queries readable.
  • Join on indexed columns (primary/foreign keys) for performance.

6. Aggregates, GROUP BY, and HAVING

Aggregate functions summarize many rows into one value:

Function Meaning
COUNT(*) Number of rows
SUM(col) Total of numeric column
AVG(col) Average
MIN(col) / MAX(col) Smallest / largest value
SELECT
    c.CategoryName,
    COUNT(*) AS ProductCount,
    AVG(p.ListPrice) AS AvgPrice,
    MIN(p.ListPrice) AS Cheapest,
    MAX(p.ListPrice) AS MostExpensive
FROM dbo.Product AS p
INNER JOIN dbo.Category AS c ON p.CategoryID = c.CategoryID
GROUP BY c.CategoryName
ORDER BY ProductCount DESC;

HAVING filters groups after aggregation (where WHERE filters individual rows):

SELECT
    c.CategoryName,
    COUNT(*) AS ProductCount
FROM dbo.Product AS p
INNER JOIN dbo.Category AS c ON p.CategoryID = c.CategoryID
GROUP BY c.CategoryName
HAVING COUNT(*) > 1;

7. Common beginner mistakes

  • SELECT * in production — pulls unnecessary columns and breaks when schemas change.
  • Missing GROUP BY columns — every non-aggregated column in SELECT must appear in GROUP BY.
  • Confusing WHERE vs HAVING — filter rows with WHERE; filter groups with HAVING.
  • Implicit conversions — compare dates and strings with correct types; use N'…' for Unicode literals.
  • Not testing on small data first — always run against a sample before a million-row table.

8. Next steps in this series

You now have the foundation for reporting, stored procedures, and BI tools. Continue with:

Practice daily: rewrite a business question as SELECT → JOIN → GROUP BY until it feels natural.


Want live SQL Server and BI classes? Join Alkademy for instructor-led database administration and business intelligence courses.

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted