SQL Server Quick Start and T-SQL Cheat Sheet
If you already speak SQL — PostgreSQL, MySQL, or anything ANSI-flavored — then Microsoft SQL Server is not a new language so much as a new dialect with its own accent, its own tooling, and a handful of opinions that will trip you up in the first hour. This post is the onramp: enough to connect, run queries, understand the engine’s quirks, and keep one tab open as a T-SQL reference. It assumes you know what a JOIN and an index are, and focuses on what is different about SQL Server rather than re-teaching relational basics.
A note on versions: the current release as of mid-2026 is SQL Server 2025 (internally version 17). It is the biggest developer-facing release in a decade — native regular expressions in T-SQL, a real vector data type for semantic search, native JSON up to 2 GB per row with JSON indexes, REST endpoints built into the engine, and change event streaming to Kafka and Azure Event Hubs. We will touch the highlights, but most of this cheat sheet is dialect bedrock that has been stable for years and will serve you on 2019, 2022, and 2025 alike.
Getting an engine in front of you
You do not need Windows. Since SQL Server 2017 the engine runs natively on Linux, and the fastest way to a working instance is a container. This is the single most useful thing to know coming from the Postgres/MySQL world, where docker run is reflexive.
|
|
A few things that surprise newcomers:
- The default port is 1433, not 5432 (Postgres) or 3306 (MySQL).
- The password policy is enforced — at least 8 characters across upper, lower, digit, and symbol classes. A weak
MSSQL_SA_PASSWORDmakes the container start and then immediately exit; checkdocker logs mssqlif it will not stay up. MSSQL_PID=Developerselects the free-for-non-production Developer edition, which is feature-identical to Enterprise. Use it for everything that is not production.- SQL Server 2025 defaults to encrypted connections (
Encrypt=True) and TLS 1.3. Clients that worked against older servers with no TLS config may now needTrustServerCertificate=Truefor the self-signed container cert, or a proper certificate. This is a real gotcha — an old connection string can fail against a 2025 server purely on encryption defaults.
Connecting: three clients, one protocol
| Client | What it is | When to reach for it |
|---|---|---|
| sqlcmd | The command-line client (a modern Go-based sqlcmd has replaced the old ODBC one) |
Scripting, CI, quick checks, anything headless |
| Azure Data Studio (ADS) | Cross-platform (Win/Mac/Linux) Electron GUI, notebook support | Day-to-day querying on a non-Windows workstation |
| SQL Server Management Studio (SSMS) | The heavyweight Windows-only admin GUI | Deep administration, execution-plan analysis, the full toolbox |
The mental mapping from Postgres: sqlcmd is your psql, Azure Data Studio is your cross-platform pgAdmin/DataGrip, and SSMS is the Windows power-tool with no Postgres equivalent (it does far more than pgAdmin).
|
|
The biggest sqlcmd/psql difference: statements do not run until you type GO on its own line. GO is not T-SQL — it is a batch separator the client understands. This confuses everyone at first: you type a SELECT, hit enter, and nothing happens, because the engine has not received a batch yet.
|
|
The T-SQL accent: what is actually different
Here is the core of the cheat sheet — the dialect divergences that matter, side by side with what you already know.
Limiting rows: TOP and OFFSET/FETCH, not LIMIT
There is no LIMIT. To grab the first N rows, use TOP:
|
|
For pagination, the ANSI-standard OFFSET ... FETCH is the right tool (and it requires an ORDER BY):
|
|
Identifiers and strings
- Bracket-quote identifiers with
[ ]:SELECT [Order].[Total] FROM [Order]. Double quotes work only whenQUOTED_IDENTIFIERis on (it usually is), but brackets are the idiomatic SQL Server way. - Unicode string literals take an
Nprefix:N'café'. Without theN, a literal is non-Unicodevarcharand can mangle characters. When in doubt, prefix it. This is the single most common encoding bug newcomers hit. - String concatenation is
+, not||:SELECT FirstName + ' ' + LastName. Beware:NULL + 'x'isNULL. UseCONCAT()to treat NULLs as empty strings.
NULL-handling and common functions
| You want | Postgres/MySQL | SQL Server (T-SQL) |
|---|---|---|
| Coalesce two values | COALESCE(a, b) |
ISNULL(a, b) or COALESCE(a, b) |
| Current timestamp | now() |
SYSDATETIME() / GETDATE() |
| Cast | a::int |
CAST(a AS int) / TRY_CAST(a AS int) |
| String length | length(s) |
LEN(s) (trims trailing spaces!) / DATALENGTH(s) |
| Substring | substring(s,1,3) |
SUBSTRING(s,1,3) |
| Conditional | CASE |
CASE or IIF(cond, a, b) |
| Auto-increment | SERIAL / AUTO_INCREMENT |
IDENTITY(1,1) |
Two traps worth memorizing: LEN() ignores trailing spaces (use DATALENGTH for byte length), and SQL Server’s + concatenation propagates NULL while CONCAT() does not.
MERGE: upsert in one statement
SQL Server has had MERGE for years (Postgres only gained it recently). It does insert/update/delete against a target from a source in one statement:
|
|
A caution from the field: MERGE has historically had subtle concurrency and bug edge cases. For high-contention simple upserts, many practitioners still prefer an explicit UPDATE then INSERT ... WHERE NOT EXISTS under a transaction. Know MERGE, use it deliberately.
Common table expressions and window functions
These are ANSI-standard and behave the way you expect — good news, since they cover most of the analytical work you will do.
|
|
The full window-function vocabulary is here: ROW_NUMBER, RANK, DENSE_RANK, NTILE, LAG/LEAD, running aggregates with OVER (... ROWS BETWEEN ...). One nicety: SQL Server’s STRING_AGG(expr, ',') is the equivalent of Postgres string_agg / MySQL GROUP_CONCAT.
Data types you need to get right
| Category | Use this | Avoid / why |
|---|---|---|
| Variable text | nvarchar(n) or nvarchar(max) |
nvarchar is Unicode; varchar is single-byte. Use n-types unless you have a reason not to |
| Fixed text | char / nchar |
Pads with spaces; rarely what you want |
| Whole numbers | int, bigint |
tinyint is 0–255 only (not signed!) |
| Money/exact decimal | decimal(p,s) |
Never float/real for currency |
| Date + time | datetime2(n) |
The old datetime has a 3.33 ms resolution and a 1753 floor — prefer datetime2 |
| Date only | date |
— |
| Boolean | bit (0/1) |
There is no real boolean type; bit holds 0, 1, or NULL |
| Unique id | uniqueidentifier (GUID) |
Random GUIDs fragment clustered indexes; consider NEWSEQUENTIALID() |
| JSON | json (native, 2025) or nvarchar(max) |
2025 adds a real json type + indexing; older versions store JSON as text |
The headline surprises for a Postgres refugee: there is no boolean type (use bit), no array type (normalize, or use JSON), and the default datetime is a legacy minefield — reach for datetime2.
Identity columns and getting the new key back
|
|
Use SCOPE_IDENTITY() rather than @@IDENTITY — the latter can return an id from a trigger that fired on your insert, a classic foot-gun. For bulk inserts that need the keys back, the OUTPUT clause is cleaner:
|
|
Indexes and execution plans
SQL Server’s indexing has one concept that dominates everything: the clustered index is the table. The clustered index defines the physical order of the rows, so a table has at most one. By default a PRIMARY KEY becomes the clustered index. Everything else is a nonclustered index, which stores the key columns plus a pointer back to the clustered key.
Clustered index (the table itself, sorted by key)
┌──────────────────────────────────────────┐
│ CustomerId | Email | CreatedAt ... │ ← rows live here, in key order
└──────────────────────────────────────────┘
▲
│ lookup by clustered key
Nonclustered index on (Email)
┌────────────────────────────┐
│ Email → CustomerId (ptr) │ ← small, points back to the table
└────────────────────────────┘
Practical consequences:
- A query filtering on a nonclustered-indexed column does a key lookup back into the clustered index for any columns the index does not contain. Avoid the lookup by covering the query: add the needed columns with
INCLUDE.
|
|
- Read the plan. In Azure Data Studio or SSMS, enable “Include Actual Execution Plan” (Ctrl+M in SSMS). The graphical plan reads right-to-left. Watch for Key Lookups (often fixable with
INCLUDE), Scans where you expected Seeks, and fat arrows indicating large row counts. The text equivalents areSET STATISTICS IO ON(logical reads per table) andSET STATISTICS TIME ON.
|
|
A “Seek” means the engine jumped straight to the rows via the index; a “Scan” means it read the whole structure. Turning Scans into Seeks is most of practical query tuning.
Stored procedures and functions
T-SQL’s procedural side is more central to SQL Server culture than to Postgres — a lot of business logic lives in stored procedures. The basics:
|
|
Notes that matter:
dbois the default schema — the equivalent of Postgrespublic. Qualify objects asdbo.Thing.- Variables are
@-prefixed; parameters too. SET NOCOUNT ONat the top of every procedure avoids extra round-trip metadata and is near-universal practice.CREATE OR ALTER(since 2016) is the idempotent form you want in migration scripts.- Functions come in flavors: scalar functions (avoid them in
WHERE/SELECTover large sets — they historically killed parallelism and performance) and inline table-valued functions, which the optimizer can fold into the query and are the performant choice.
Backup and restore
The fundamentals every admin needs on day one. SQL Server backs up to .bak files and the model is straightforward once you know the recovery models.
|
|
The one concept to understand is the recovery model:
- SIMPLE — no transaction-log backups, log truncates automatically. Easiest; you can only restore to the last full/differential backup. Fine for dev and many internal apps.
- FULL — every change is logged until you back up the log; enables point-in-time restore but the log grows until you take log backups. Required for most production. Forgetting to back up the log under FULL is the classic “why is my disk full?” incident — the log grows forever.
|
|
What is new in SQL Server 2025 (and worth knowing)
You can be productive without any of this, but a few 2025 features change what is reasonable to do in the database:
- Native RegEx in T-SQL —
REGEXP_LIKE,REGEXP_REPLACE, and friends, finally ending the era of nightmarish nestedPATINDEX/CHARINDEXhacks for pattern work. - The
vectordata type and vector search — store embeddings and run nearest-neighbor similarity directly, no separate vector database required. Combined with the ability to call external AI models from T-SQL, this brings semantic search into the engine. - Native JSON type with indexing — up to 2 GB per row, with indexes on JSON path expressions so filtering/sorting on a JSON field is no longer a full scan.
- Built-in REST endpoints and GraphQL — expose data over HTTP through the engine itself.
- Change Event Streaming — push row changes to Kafka or Azure Event Hubs for real-time pipelines, plus Fabric Mirroring for analytics.
- Security defaults tightened — encrypted connections (
Encrypt=True) and TLS 1.3 by default, which, again, is the thing most likely to break an old connection string.
The newcomer gotcha list
Keep these pinned; they account for most of the “why doesn’t this work” moments in week one:
GOis required to send a batch insqlcmd/SSMS — it is a client directive, not SQL.- No
LIMIT— useTOP (n)orOFFSET/FETCH(which needsORDER BY). - Prefix Unicode literals with
N—N'text'— or risk silent character corruption. +concatenates and propagates NULL;CONCAT()does not. There is no||.- No boolean type — use
bit(0/1/NULL). datetimeis legacy — usedatetime2.LEN()trims trailing spaces — useDATALENGTH()for true length.SCOPE_IDENTITY(), not@@IDENTITY, to get the inserted id safely.dbo.is the default schema — qualify your objects.- 2025 encrypts by default — add
TrustServerCertificate=Truefor self-signed dev certs or supply a real certificate.
With those internalized, the rest of T-SQL is the SQL you already know. Keep this page open in a tab, lean on Azure Data Studio for cross-platform querying, run the engine in a container for everything non-production, and read your execution plans — that combination will make you dangerous on SQL Server within a week.
Sources:
Comments