Category: SQL Server Fundamentals

Beginner SQL Server tutorials: data manipulation, queries, aggregate functions, multiple tables, constraints.

  • Creating a SQL Server Database on Azure SQL and AWS RDS: A Beginner’s PaaS Guide

    Creating a SQL Server Database on Azure SQL and AWS RDS: A Beginner’s PaaS Guide

    Every option in the last lesson — Developer Edition, Docker, Express — means you install and manage SQL Server. A huge share of real jobs instead use a managed (PaaS) SQL Server, where the cloud provider runs the engine for you. Here’s what that actually looks like, and why it’s worth understanding even as a beginner — you may well connect to one of these on your very first day at a job.

    Who Manages What?(on-prem vs IaaS vs PaaS)this lesson →On-PremYour DatabaseSQL Server EngineOperating SystemHardwareIaaS (VM)Your DatabaseSQL Server EngineOperating SystemHardwarePaaS (Managed)Your DatabaseSQL Server EngineOperating SystemHardware= you manage= provider managesAzure & RDS block ALLIPs by default — evenyours. Add a firewallrule before you connect.

    IaaS vs PaaS vs On-Prem — Where Each Fits

    It helps to place “managed SQL” on a spectrum rather than treat it as one thing:

    • On-prem / local install (what Chapter 0.3 covered) — you own the hardware, the OS, and the SQL Server installation. Maximum control, maximum responsibility.
    • IaaS (e.g. a SQL Server VM on Azure/AWS/GCP) — the cloud provider gives you a virtual machine; you still install and manage SQL Server on it yourself, same as local, just on someone else’s hardware.
    • PaaS (Azure SQL Database, AWS RDS for SQL Server) — the provider manages the SQL Server engine itself. You get a connection string, not a server to log into.

    This lesson is specifically about the third option, since it’s the one most beginners haven’t seen and the one most likely to surprise you in a real job (“why can’t I just RDP into the database server?” — because there isn’t one you can access).

    What “PaaS” Changes

    You installed it (Ch. 0.3) You patch, back up, and size the hardware yourself Full OS/file access Azure SQL / RDS (PaaS) Provider patches, backs up, and handles HA automatically You connect with SSMS — no OS access

    You still write the exact same T-SQL you’ve been learning. What changes is everything around the database — how it’s created, connected to, secured, and maintained.

    Creating a Database on Azure SQL

    1. In the Azure Portal, search for SQL DatabaseCreate
    2. Choose or create a logical server (a management boundary and connection endpoint, not a physical machine — one logical server can host many databases) — set an admin login and password here
    3. Pick a pricing tier: DTU-based (simpler, bundled compute+storage+IO into one number, good for beginners) or vCore-based (separately configurable compute/storage, closer to how you’d think about a VM’s specs, and the tier Microsoft is steering customers toward long-term)
    4. Under Networking, add your current IP to the firewall rule so you can actually connect — by default, Azure SQL blocks every IP, including yours, until explicitly allowed
    5. Click Create — provisioning takes a few minutes
    -- Connect via SSMS using the server's full name, e.g.:
    -- Server: yourserver.database.windows.net
    -- Authentication: SQL Server Authentication, using the admin login you set
    
    SELECT @@VERSION; -- confirms you're connected, same as any other SQL Server

    Creating a Database on AWS RDS for SQL Server

    1. In the AWS Console, go to RDSCreate database
    2. Choose engine: Microsoft SQL Server, pick an edition (Express is free-tier eligible for learning)
    3. Set the DB instance identifier, master username, and password
    4. Under Connectivity, set a Security Group rule allowing inbound traffic on port 1433 from your IP — AWS’s equivalent of Azure’s firewall rule, same underlying idea: nothing gets in until you explicitly allow it
    5. Create — RDS provisions the instance, then gives you an endpoint (hostname) to connect to
    -- Connect via SSMS using the RDS endpoint, e.g.:
    -- Server: yourinstance.abc123xyz.us-east-1.rds.amazonaws.com,1433
    
    CREATE DATABASE TechCorpLite; -- works exactly like it did locally
    GO
    Practical note: Unlike Azure SQL Database (where the “server” is purely logical and databases are created individually), RDS provisions a full DB instance first — conceptually closer to a managed VM running SQL Server — and you then create one or more databases inside it, exactly as shown above.

    What a Beginner Should Actually Know Is Different

    Local / Docker install Azure SQL Database AWS RDS for SQL Server
    You manage backups Automatic, provider-managed, point-in-time restore included Automatic, provider-managed, point-in-time restore included
    Full file system access No file/OS access at all No file access; limited OS-level settings via parameter groups
    Any T-SQL feature works Some features restricted (e.g. cross-database queries on single DBs, SQL Server Agent doesn’t exist — use Elastic Jobs instead) Very close to full on-prem feature set, including SQL Server Agent
    You size the hardware You pick a DTU/vCore tier instead — resizable with minutes of downtime You pick an instance class (like a VM size, e.g. db.t3.medium)
    You control patching schedule Automatic, provider-managed, no maintenance window choice needed for most tiers Automatic, but you choose a maintenance window

    Everything you’ll learn for the rest of this course — SELECT, JOIN, constraints, all of it — works identically once you’re connected. The only thing that changes is how you got connected in the first place, and a short list of admin-level features (cross-database queries, SQL Server Agent, filesystem access) that a beginner course won’t rely on anyway.

    Why This Matters Even If You Never Provision One Yourself

    In most companies, a DBA or platform team provisions the Azure SQL/RDS instance, and you’re handed a connection string. But you’ll still hit PaaS-specific quirks directly: connection timeouts from firewall misconfiguration, “feature X isn’t supported” errors that don’t happen locally, and cost conversations driven by DTU/vCore tier choice. Recognizing “oh, this is a PaaS limitation, not a bug in my query” saves real debugging time — which is exactly why this lesson exists this early in the course, not buried in an advanced chapter.


    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.

  • SQL Server Express vs Docker vs Developer Edition: Which Install Should You Use?

    SQL Server Express vs Docker vs Developer Edition: Which Install Should You Use?

    Before writing a single query, you need SQL Server actually running somewhere. Here’s how to pick without overthinking it — plus enough detail on each option that you’re not just following steps blindly, and know how to troubleshoot when something doesn’t come up cleanly.

    Picking Your Install(there’s no wrong answer here)Your Setup?OS + how often you’ll reset itWindows, want everythingany OS, experimenting a lotWindows, keep it lightDeveloper EditionWindows · every feature, free for devDockerAny OS · instant reset, one commandExpressWindows · lightweight, prod-OK under 10GBDocker container exitsimmediately? Check yourSA password meets thecomplexity rules.

    Option A: SQL Server Developer Edition (Windows, full-featured, free)

    1. Download SQL Server 2022 Developer Edition from Microsoft’s site
    2. Run the installer, choose Basic installation type
    3. Note the instance name at the end — usually localhostSQLEXPRESS or (local)
    4. Install SSMS separately — recent SQL Server installers no longer bundle it

    Developer Edition has every Enterprise Edition feature — In-Memory OLTP, Always Encrypted, columnstore indexes, the works — licensed for free non-production use. Genuinely the best choice if you’re on Windows and want zero feature limitations while learning, including features covered later in the Performance Tuning course that Express doesn’t support at all.

    Option B: Docker (Mac, Linux, or Windows — fastest to reset)

    docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=YourStrong!Passw0rd" 
      -p 1433:1433 --name sql1 --hostname sql1 
      -v sql1data:/var/opt/mssql 
      -d mcr.microsoft.com/mssql/server:2022-latest

    One command, running in under a minute. Breaking down what each flag does:

    Flag What it does
    -e ACCEPT_EULA=Y Required — the container refuses to start without accepting Microsoft’s license terms
    -e MSSQL_SA_PASSWORD=... Sets the sa login’s password — must meet complexity rules (8+ chars, mixed case, a digit, a symbol) or the container silently fails to start
    -p 1433:1433 Maps container port 1433 to your machine’s port 1433, so SSMS on your host can reach it at localhost,1433
    -v sql1data:/var/opt/mssql Persists your data in a named Docker volume — without this, deleting the container also deletes every database inside it

    Useful follow-up commands once it’s running:

    docker ps                         # confirm the container is actually running
    docker logs sql1                  # see startup errors if the connection fails
    docker exec -it sql1 bash         # get a shell inside the container
    docker rm -f sql1                 # completely remove it (data survives if you used -v)

    The real advantage of Docker: a clean-slate reset is one command, with no uninstall wizard and no leftover registry entries — genuinely useful if you want to practice an install/setup scenario repeatedly, or if you’re on macOS/Linux where the native installer isn’t an option.

    Comparing Your Options

    Developer Ed. Windows only Full feature set SSMS built for it Docker Any OS Instant reset Best for experimenting Express Windows only 10GB DB size cap Lightweight install

    Express is genuinely fine for more than “just learning” — plenty of small production applications with modest data volumes run on it for free indefinitely, as long as you stay under the 10GB-per-database cap and 1GB RAM buffer pool limit. If you outgrow it, upgrading in place to Standard or Enterprise is a licensing change, not a data migration — your databases carry over untouched.

    A Fourth Option: Native Linux Install

    SQL Server also installs directly on Ubuntu, RHEL, and SUSE without Docker — useful if you’re deploying to a Linux server long-term and want to match production exactly, though Docker is faster for local experimentation since you’re not managing a package manager and systemd service directly.

    The Client Tool: SSMS or Azure Data Studio

    Tool Platform Best for
    SSMS (SQL Server Management Studio) Windows only The traditional, full-featured tool — richest GUI for administration tasks (backups, security, job scheduling)
    Azure Data Studio Windows, macOS, Linux Lighter, cross-platform, closer to a VS Code-style editor experience — the natural choice if you’re on Mac/Linux or already comfortable with VS Code

    Either works fine — every query in this course runs identically in both. Pick based on your OS, not a perceived “better” choice.

    Troubleshooting a Failed Install

    Common issue: The Docker container starts then immediately exits. Almost always the SA password didn’t meet complexity requirements — check with docker logs sql1, which will show the exact rejection reason.
    Common issue: Windows installer completes, but SSMS can’t connect to localhost. Try the full instance name shown at the end of setup (often localhostSQLEXPRESS) — a named instance doesn’t respond on plain localhost alone.

    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.

  • Your First SQL Server Database: Connect, Create, and Query in 5 Minutes

    Your First SQL Server Database: Connect, Create, and Query in 5 Minutes

    Setup is done. Now let’s actually touch SQL Server — connect, create a database, and prove it works with a real query. We’ll also cover exactly what each authentication option means and the handful of connection errors you’re statistically most likely to hit, so a wrong password doesn’t turn into twenty minutes of confusion.

    Your First 5 Minutes(connect → create → query)1. ConnectSSMS → server name → auth mode2. CREATE DATABASETechCorpLite comes to life3. Prove ItSELECT ‘Connected!’ AS status✓ it’s alivepick one:Windows Authyour OS login, no password to manageSQL Authsa + password — Docker, Linux, cloudGO isn’t T-SQL.It’s a client-side batchseparator — the servernever even sees it.

    Step 1: Connect

    Open SSMS → Connect → enter your server name (e.g. localhost or localhostSQLEXPRESS) → choose an authentication mode.

    Authentication mode How it works When to use it
    Windows Authentication Uses your logged-in Windows account — no separate password to manage Local installs, on-prem corporate networks. The default and generally preferred choice when available
    SQL Server Authentication A username/password stored and checked by SQL Server itself, independent of the OS Docker containers, Linux hosts, cross-platform apps, cloud databases — anywhere there’s no Windows domain to rely on

    For a Docker install, you’ll use SQL Server Authentication with username sa and the password you set in the MSSQL_SA_PASSWORD environment variable when you started the container.

    Step 2: Create Your First Database

    CREATE DATABASE TechCorpLite;
    GO
    
    USE TechCorpLite;
    GO
    
    SELECT 'Connected!' AS status, @@VERSION AS server_version;

    Run it with F5. If you see a result grid with “Connected!” in it, you’re live. TechCorpLite is the database this entire tutorial series builds up, table by table — bookmark this one. By the end of Chapter 7’s capstone project, it’ll have authors, books, customers, and orders tables with real relationships between them.

    What Just Happened, Visually

    SSMS (client) TCP 1433 SQL Server the engine TechCorpLite DB

    SSMS is just a client — it’s not the database itself. It sends your T-SQL over the network (TCP port 1433 by default) to the SQL Server engine, which parses, compiles, and executes it, then creates and manages the actual TechCorpLite database on disk. This client/server split matters later: the exact same T-SQL you type in SSMS is what any application (a web backend, a reporting tool, a Python script) sends over that same connection — SSMS has no special privileges the engine doesn’t also expose to any other client.

    Exploring What You Just Created

    Beyond just running a query, it’s worth seeing how SQL Server itself reports on its own structure — you’ll use these constantly:

    -- List every database on this server
    SELECT name, create_date FROM sys.databases;
    
    -- Confirm which database your current session is using
    SELECT DB_NAME() AS current_database;
    
    -- Standard, cross-vendor way to inspect tables (empty for now — no tables yet)
    SELECT * FROM INFORMATION_SCHEMA.TABLES;

    sys.databases is a SQL-Server-specific system view; INFORMATION_SCHEMA is an ANSI-standard set of views that work similarly across SQL Server, PostgreSQL, and MySQL — useful to know if you ever move between database engines.

    Fixing the Connection Errors You’ll Actually Hit

    Error message What it usually means
    “A network-related or instance-specific error…” Wrong server name, or the SQL Server service isn’t running — check Services (Windows) or docker ps (Docker)
    “Login failed for user ‘sa’” Wrong password, or SQL Server Authentication mode isn’t enabled on the instance (Windows installs default to Windows-only auth)
    “Cannot open database … requested by the login” Database name typo, or your login lacks permission on that specific database
    Connects, but every query times out Almost always a firewall blocking port 1433 — common on cloud VMs and corporate networks
    Practice tip: Deliberately mistype your server name once and read the full error text SQL Server gives you. You’ll see a version of this error again eventually in real work — recognizing it on sight beats re-googling it every time.

    Key Takeaways

    • SQL Server is the engine; SSMS/Azure Data Studio is just a client that talks to it over the network
    • CREATE DATABASE makes a new, empty database; USE switches your session’s default context into it — without USE, unqualified table names resolve against the wrong database
    • GO is a batch separator understood by SSMS/sqlcmd — it’s not T-SQL itself, and the server never sees it; it just tells the client tool where one batch of statements ends and the next begins
    • Windows Authentication uses your OS login; SQL Server Authentication is a separate username/password the engine manages itself — you’ll need the latter for Docker, Linux, and most cloud setups

    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.

  • How to Learn SQL Server the Right Way: A Practical Roadmap for Developers

    How to Learn SQL Server the Right Way: A Practical Roadmap for Developers

    If you’ve ever opened SQL Server Management Studio for the first time and had no idea where to start, this is for you. Most SQL tutorials throw syntax at you in isolation — SELECT here, JOIN there — with no sense of how it all fits together in a real job, and no honest plan for how long it actually takes to get comfortable. This lesson is that plan.

    Your Learning Roadmap(the order that actually works)1. Data FirstCREATE · INSERT · UPDATE2. QuerySELECT · WHERE · ORDER BY3. AggregateGROUP BY → insight4. Join Tableswhere SQL clicks5. Constraintskeys that hold it together= real fluency, not just recognitiontempting shortcut…Performance tipscan’t evaluate advice youcan’t read yet — not first!Type it yourself.Don’t copy-paste.Then break it on purpose.

    Why Most Self-Taught SQL Falls Apart

    The typical failure mode isn’t lack of effort — it’s passive exposure without active retrieval. You watch a video, the syntax makes sense in the moment, you move to the next video. Three weeks later you’re in an interview or a real ticket and you can’t produce a JOIN from scratch, even though you’d recognize one instantly if shown it. Recognition and production are different skills, and only production is useful on the job. Everything in this course is built around forcing production: you’ll type every example, and later chapters include exercises with no visible answer until you’ve tried.

    Concept, Diagram, Example, Practice — In That Order

    Every solid SQL Server learning path follows the same loop: understand the concept in plain language, see it visually, watch it work against real data, then do it yourself without looking at the answer. Skip the last step and you’ll recognize syntax without being able to produce it under pressure — exactly what happens in interviews and on the job in month two.

    ConceptDiagramReal ExampleYou Practice

    Get new lessons in your inbox

    Subscribe and get every new SQL Server lesson as soon as it’s published.

    Type Every Query Yourself — And Break It On Purpose

    Don’t copy-paste. It feels slower, and it is slower — for the first two weeks. The goal isn’t finishing a course; it’s being able to open SSMS cold, six months from now, and write a correct query without googling basic syntax. Muscle memory for T-SQL comes from typing it, not reading it.

    Go further: after you get an example working, deliberately break it. Remove the WHERE clause and see what happens. Misspell a column name and read the exact error message SQL Server gives you — you will see that error again in real work, and recognizing it instantly saves real debugging time. Change a JOIN to a different type and watch the row count change. This is how you build an intuition for why, not just memorized syntax for what.

    What Counts as “Beginner” Here

    Zero SQL knowledge is fine. Zero technical background isn’t the assumption. If you’ve written a spreadsheet formula or a for-loop in any language, you already have the instincts — SQL just applies them to sets of data instead of one value at a time. The biggest mental shift for programmers specifically: SQL is declarative, not procedural. You describe what result you want, not the step-by-step loop to produce it. Fighting this (mentally writing a for-loop and trying to translate it) is the single most common source of beginner frustration — trust the engine to figure out how.

    Who Uses SQL Server, and How Much of This You Actually Need

    Role Core daily skill Where the depth matters
    Data / Business Analyst SELECT, JOIN, GROUP BY, window functions Aggregate functions, reporting queries — rarely touches schema design
    Application Developer All of the above, plus INSERT/UPDATE/DELETE, stored procedures Constraints, transactions, parameterized queries (SQL injection safety)
    Database Administrator (DBA) Everything above, plus indexing, security, backups Performance tuning, execution plans — the follow-on courses in this series

    This course (SQL Server Fundamentals) covers the shared foundation every one of those roles needs. The Developers & DBAs course that follows it branches into the deeper procedural and performance-focused material.

    A Realistic Timeline

    Working through one lesson a day, typing every example and doing the exercises honestly: expect roughly 3–4 weeks to comfortably write SELECT queries with joins and aggregates against an unfamiliar schema, and 6–8 weeks to be comfortable designing a small schema with correct keys and constraints from scratch. That’s genuinely fast for a skill that professionals build careers on — but only if the practice is active, not passive video-watching.

    Practice tip: Revisit a lesson from a week ago and try to reproduce its main example from memory before rereading it. This single habit (spaced retrieval) does more for long-term retention than re-reading the same material five times in a row.

    The Order That Actually Works

    1. Data manipulation (CREATE, INSERT, UPDATE, DELETE) — you need to be able to make your own test data before anything else makes sense
    2. Querying (SELECT, WHERE, ORDER BY) — the daily-driver skill
    3. Aggregate functions and GROUP BY — turning rows into insight
    4. Joining multiple tables — where SQL starts feeling genuinely powerful
    5. Constraints and keys — how real schemas stay correct under pressure

    Follow that order and every new concept builds on something you already trust, instead of feeling like a fresh wall of unfamiliar syntax. Notice what’s not first: performance tuning, security, and advanced procedural T-SQL. Those matter enormously for a working DBA or senior developer, but they’re actively harmful to learn before the fundamentals — you can’t reason about whether an index helps until you can already read the query it’s supposed to help.

    Common mistake: Jumping straight to “performance tips” articles before you can confidently write a JOIN. Advice like “avoid SELECT *” or “add an index here” is meaningless without the query-reading fluency to know when it applies — you’ll end up cargo-culting rules you can’t evaluate.

    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.

  • SQL Server Data Types Explained: Which One Should You Actually Use?

    SQL Server Data Types Explained: Every Major Type, and Which One to Actually Use

    Every column has exactly one data type — SQL Server enforces it strictly, unlike a spreadsheet cell that’ll happily hold text or a number interchangeably. This lesson covers every data type category you’ll realistically encounter: exact and approximate numbers, character strings, dates and times, binary data, and the “special purpose” types like UNIQUEIDENTIFIER and XML.

    Choosing a Data Type(five families, one pick each)Exact NumbersINT, DECIMAL — precise, zero roundingApproximate NumbersFLOAT — fine for science, never moneyCharacter StringsNVARCHAR — safe default for all textDate & TimeDATETIME2 — the modern defaultBinary & SpecialVARBINARY, GUID, XML, spatial typesFLOAT is a binary approximation —it can silently produce $100.00000000001.Use DECIMAL for money. Always.

    Exact Numeric Types

    Use these when the value must be precisely correct — counts, IDs, money. No rounding error, ever.

    Type Storage Range Use for
    TINYINT 1 byte 0 to 255 Small counters, status codes, ages
    SMALLINT 2 bytes -32,768 to 32,767 Small ranges — year, quantity in a typical order
    INT 4 bytes ±2.1 billion The default choice for IDs, counts, foreign keys
    BIGINT 8 bytes ±9.2 quintillion High-volume identity columns (event logs, telemetry) that will exceed 2.1 billion rows
    DECIMAL(p,s) / NUMERIC(p,s) 5–17 bytes (depends on precision) Exact, defined by precision p and scale s Money, measurements, anything requiring exact arithmetic — DECIMAL and NUMERIC are functionally identical, DECIMAL is the conventional spelling
    MONEY 8 bytes ±922 trillion, 4 decimal places Legacy currency type — most teams prefer DECIMAL(19,4) for portability and clearer rounding behavior
    SMALLMONEY 4 bytes ±214,748.3648 Rarely used; same caveats as MONEY at a smaller range

    Approximate Numeric Types

    Type Storage Use for
    FLOAT 4 or 8 bytes Scientific/statistical values where tiny binary rounding error is acceptable — never for money
    REAL 4 bytes Lower-precision FLOAT(24); rarely chosen deliberately today

    FLOAT is a binary approximation and can accumulate tiny rounding errors — summing many FLOAT values can produce $100.00000000001 instead of exactly $100.00. DECIMAL stores exact values with zero rounding error, which is why it’s the correct choice for financial data.

    Character String Types

    Type Storage Use for
    CHAR(n) Fixed n bytes, space-padded Fixed-length codes — country codes, status flags (e.g. CHAR(2) for ‘US’)
    VARCHAR(n) Variable, up to n bytes Variable-length ASCII/Latin text — names, addresses, single-language content
    VARCHAR(MAX) Up to 2GB Long non-Unicode text — logs, descriptions
    NCHAR(n) Fixed 2n bytes Fixed-length Unicode — rare
    NVARCHAR(n) Variable, up to 2n bytes Variable-length Unicode text — the default recommendation for almost all text, since it safely holds any language or emoji
    NVARCHAR(MAX) Up to 2GB Long Unicode text — articles, JSON payloads, free-form notes
    TEXT / NTEXT Deprecated. Use VARCHAR(MAX) / NVARCHAR(MAX) instead

    Rule of thumb: default to NVARCHAR. The storage cost difference versus VARCHAR is small, and it avoids an entire class of bugs where a user’s name or a customer’s address contains a character your ASCII column silently mangles.

    Date and Time Types

    Type Storage Precision Use for
    DATE 3 bytes Day Birthdates, due dates — anything with no time component
    TIME 3–5 bytes Up to 100ns A time of day with no date — daily opening hours, alarm times
    SMALLDATETIME 4 bytes Minute Legacy; low precision, narrow range
    DATETIME 8 bytes ~3ms, rounded Legacy — the older default; rounding quirks make DATETIME2 the better modern choice
    DATETIME2 6–8 bytes Up to 100ns The modern default for date + time — wider range and better precision than DATETIME, at equal or smaller storage
    DATETIMEOFFSET 8–10 bytes Up to 100ns Date + time + UTC offset — required whenever you need to store a time zone alongside the timestamp (multi-region applications)

    Binary Types

    Type Storage Use for
    BINARY(n) Fixed n bytes Fixed-length raw bytes — hashes of a known fixed length
    VARBINARY(n) Variable, up to n bytes Variable-length raw bytes — small file attachments, encrypted blobs
    VARBINARY(MAX) Up to 2GB Large binary objects — documents, images stored in-database
    IMAGE Deprecated. Use VARBINARY(MAX) instead

    Other Special-Purpose Types

    Type Use for
    BIT True/false flags (0, 1, or NULL) — SQL Server packs up to 8 BIT columns into a single byte
    UNIQUEIDENTIFIER A 16-byte GUID — useful for IDs that must be unique across multiple databases/systems without coordination, at the cost of larger, less sequential index keys than INT
    XML Native XML storage with schema validation and XQuery support
    SQL_VARIANT Stores a value of almost any base type in one column — rare, generally avoided since it defeats type-checking and indexing efficiency
    ROWVERSION (formerly TIMESTAMP) An automatically-incrementing binary value per row, used for optimistic concurrency checks — not an actual date/time despite the old name
    HIERARCHYID Compact encoding of a position in a tree — org charts, category trees
    GEOGRAPHY / GEOMETRY Spatial types for round-earth (GEOGRAPHY) or planar (GEOMETRY) coordinates, with built-in distance/intersection methods

    There’s no dedicated JSON type in SQL Server — JSON is stored as NVARCHAR(MAX) and manipulated with built-in functions like JSON_VALUE, JSON_QUERY, and ISJSON.

    A Real Table Using a Representative Mix

    CREATE TABLE dbo.Example_DataTypes (
        id            INT             IDENTITY(1,1) PRIMARY KEY,
        public_id     UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID(),
        full_name     NVARCHAR(100)   NOT NULL,
        country_code  CHAR(2)         NOT NULL,
        price         DECIMAL(10,2)   NOT NULL,
        quantity      SMALLINT        NOT NULL,
        is_active     BIT             NOT NULL DEFAULT 1,
        signed_up_on  DATE            NOT NULL DEFAULT GETDATE(),
        last_login    DATETIME2       NULL,
        profile_json  NVARCHAR(MAX)   NULL,
        avatar        VARBINARY(MAX)  NULL,
        row_version   ROWVERSION
    );

    Why DECIMAL, Never FLOAT, for Money

    This is one of the most common code-review flags in real SQL Server codebases: FLOAT’s binary rounding makes it fundamentally unsuitable for currency, while DECIMAL guarantees exact values.

    The Rule of Thumb

    Pick the smallest type that can never realistically overflow, and default to Unicode (NVARCHAR) for text and DATETIME2 for timestamps unless you have a specific reason not to. Using NVARCHAR(MAX) or BIGINT everywhere “to be safe” wastes storage and slows indexes down — you’ll see exactly why once we get to performance tuning.


    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server Fundamentals, coming soon on this site.