sqlserver

Use when writing T-SQL, editing SQL Server .sql files, using sqlcmd, SQL Server connection strings, stored procedures, execution plans, indexes, Always On, JSON, security, or connector code.

9 stars

Best use case

sqlserver is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when writing T-SQL, editing SQL Server .sql files, using sqlcmd, SQL Server connection strings, stored procedures, execution plans, indexes, Always On, JSON, security, or connector code.

Teams using sqlserver should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/sqlserver/SKILL.md --create-dirs "https://raw.githubusercontent.com/cofin/flow/main/plugins/flow/skills/sqlserver/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/sqlserver/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How sqlserver Compares

Feature / AgentsqlserverStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when writing T-SQL, editing SQL Server .sql files, using sqlcmd, SQL Server connection strings, stored procedures, execution plans, indexes, Always On, JSON, security, or connector code.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# SQL Server

Microsoft SQL Server is a relational database engine spanning on-premises, containers, and Azure SQL. This skill covers T-SQL development, performance tuning, high availability, security, and connectivity across all major languages.

## Quick Reference

### Connection Setup (Python pyodbc)

```python
import pyodbc

conn_str = (
    "DRIVER={ODBC Driver 18 for SQL Server};"
    "SERVER=myserver.database.windows.net,1433;"
    "DATABASE=mydb;"
    "UID=myuser;PWD=mypassword;"
    "Encrypt=yes;TrustServerCertificate=no;"
)
conn = pyodbc.connect(conn_str)
cursor = conn.cursor()

# Always use parameterized queries
cursor.execute("SELECT OrderID, Total FROM Orders WHERE CustomerID = ?", (42,))
rows = cursor.fetchall()
```

### Stored Procedure Template

```sql
CREATE OR ALTER PROCEDURE dbo.usp_GetCustomerOrders
    @CustomerID  INT,
    @StartDate   DATE = NULL,           -- optional with default
    @TotalCount  INT OUTPUT             -- output parameter
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        SELECT OrderID, OrderDate, Total
        FROM Orders
        WHERE CustomerID = @CustomerID
          AND (@StartDate IS NULL OR OrderDate >= @StartDate)
        ORDER BY OrderDate DESC;

        SET @TotalCount = @@ROWCOUNT;
    END TRY
    BEGIN CATCH
        THROW;
    END CATCH
END;
GO
```

### Index Patterns

```sql
-- Clustered index (one per table, defines physical order)
CREATE CLUSTERED INDEX IX_Orders_OrderDate ON Orders(OrderDate);

-- Non-clustered covering index (INCLUDE avoids key lookups)
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID
    ON Orders(CustomerID)
    INCLUDE (OrderDate, Total);

-- Filtered index (partial index for common queries)
CREATE NONCLUSTERED INDEX IX_Orders_Active
    ON Orders(Status)
    WHERE Status = 'Active';
```

### Key T-SQL Patterns

```sql
-- CTE with window function
WITH RankedOrders AS (
    SELECT
        CustomerID, OrderID, Total,
        ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY Total DESC) AS RowNum
    FROM Orders
)
SELECT CustomerID, OrderID, Total
FROM RankedOrders
WHERE RowNum = 1;

-- MERGE upsert
MERGE INTO Inventory AS tgt
USING @Updates AS src ON tgt.ProductID = src.ProductID
WHEN MATCHED THEN UPDATE SET tgt.Qty = src.Qty
WHEN NOT MATCHED THEN INSERT (ProductID, Qty) VALUES (src.ProductID, src.Qty);

-- Offset pagination (2012+)
SELECT OrderID, OrderDate, Total
FROM Orders
ORDER BY OrderDate DESC
OFFSET @PageSize * (@PageNum - 1) ROWS
FETCH NEXT @PageSize ROWS ONLY;
```

<workflow>

## Workflow

### Step 1: Identify the Pattern

| Need | Go to | Key Concept |
| --- | --- | --- |
| Write a complex query | tsql_patterns.md | CTEs, window functions, APPLY |
| Build a stored procedure | stored_procedures.md | SET NOCOUNT ON, TRY/CATCH |
| Query is slow | performance.md | Execution plans, Query Store |
| Connect from app code | connections.md | Parameterized queries, drivers |
| Work with JSON data | json.md | JSON_VALUE, OPENJSON, FOR JSON |
| Lock down access | security.md | RLS, Dynamic Data Masking |
| Backup, maintain, monitor | admin.md | DBCC, DMVs, SQL Agent |
| HA / DR architecture | availability.md | Always On AG, FCI |

### Step 2: Implement

1. Use parameterized queries for all external input -- never concatenate strings
2. Start stored procedures with `SET NOCOUNT ON` to suppress row count messages
3. Wrap DML in explicit transactions with `TRY/CATCH` and `THROW`
4. Add covering indexes (`INCLUDE` columns) to eliminate key lookups
5. Test with actual execution plans (`SET STATISTICS XML ON` or SSMS Ctrl+M)

### Step 3: Validate

Run through the validation checkpoint below before considering the work complete.

</workflow>

<guardrails>

## Guardrails

- **Always use parameterized queries**: `?` placeholders in pyodbc, `@Param` in T-SQL -- never string concatenation
- **Always SET NOCOUNT ON** in stored procedures -- reduces network traffic and prevents DONE_IN_PROC interference
- **Always use TRY/CATCH** for error handling in procedures -- use `THROW` (not `RAISERROR`) for re-throwing
- **Always use `CREATE OR ALTER`** (2016 SP1+) instead of DROP/CREATE to preserve permissions
- **Prefer inline TVFs** over multi-statement TVFs and scalar UDFs -- multi-statement TVFs prevent parallelism
- **Prefer `OFFSET/FETCH`** over `ROW_NUMBER()` for simple pagination (2012+)
- **Never use `SELECT *`** in production queries -- always specify columns explicitly
- **Never use cursors** unless no set-based alternative exists -- set-based operations are orders of magnitude faster

</guardrails>

<validation>

### Validation Checkpoint

Before delivering SQL Server code, verify:

- [ ] All user input passes through parameterized queries (no string concatenation)
- [ ] Stored procedures have `SET NOCOUNT ON` as the first statement
- [ ] DML operations are wrapped in `BEGIN TRY / BEGIN CATCH` with `THROW`
- [ ] Indexes include `INCLUDE` columns to cover common query patterns
- [ ] No implicit conversions in WHERE clauses (match data types exactly)
- [ ] `CREATE OR ALTER` used instead of `DROP`/`CREATE` where supported

</validation>

<example>

## Example

**Task:** "Create a stored procedure to search orders by customer and date range, with a Python caller using parameterized queries."

```sql
-- T-SQL: Stored procedure with proper error handling
CREATE OR ALTER PROCEDURE dbo.usp_SearchOrders
    @CustomerID  INT,
    @StartDate   DATE = NULL,
    @EndDate     DATE = NULL,
    @PageNum     INT = 1,
    @PageSize    INT = 50
AS
BEGIN
    SET NOCOUNT ON;

    BEGIN TRY
        SELECT
            o.OrderID,
            o.OrderDate,
            o.Total,
            c.CustomerName
        FROM Orders o
        INNER JOIN Customers c ON c.CustomerID = o.CustomerID
        WHERE o.CustomerID = @CustomerID
          AND (@StartDate IS NULL OR o.OrderDate >= @StartDate)
          AND (@EndDate IS NULL OR o.OrderDate <= @EndDate)
        ORDER BY o.OrderDate DESC
        OFFSET @PageSize * (@PageNum - 1) ROWS
        FETCH NEXT @PageSize ROWS ONLY;
    END TRY
    BEGIN CATCH
        THROW;
    END CATCH
END;
GO
```

```python
# Python: Parameterized call via pyodbc
import pyodbc

conn = pyodbc.connect(
    "DRIVER={ODBC Driver 18 for SQL Server};"
    "SERVER=myserver,1433;DATABASE=mydb;"
    "UID=myuser;PWD=mypassword;"
    "Encrypt=yes;TrustServerCertificate=no;"
)

cursor = conn.cursor()
cursor.execute(
    "EXEC dbo.usp_SearchOrders @CustomerID=?, @StartDate=?, @PageNum=?, @PageSize=?",
    (42, "2025-01-01", 1, 25),
)

for row in cursor.fetchall():
    print(row.OrderID, row.OrderDate, row.Total, row.CustomerName)

cursor.close()
conn.close()
```

</example>

## References Index

For detailed guides and code examples, refer to the following documents in `references/`:

- **[T-SQL Patterns](references/tsql_patterns.md)** -- Window functions, CTEs, MERGE, APPLY, PIVOT, temporal tables, pagination.
- **[Stored Procedures & T-SQL Programming](references/stored_procedures.md)** -- Procedures, functions, error handling, transactions, cursors, dynamic SQL, triggers.
- **[Performance Tuning](references/performance.md)** -- Execution plans, Query Store, indexing strategy, wait stats, parameter sniffing, deadlocks.
- **[Connection Patterns](references/connections.md)** -- Python, Node.js, .NET, Java, Go drivers; connection strings; Azure AD / Managed Identity.
- **[JSON in SQL Server](references/json.md)** -- JSON_VALUE, OPENJSON, FOR JSON, computed-column indexing, JSON type (2022+/2025).
- **[Security](references/security.md)** -- RLS, Dynamic Data Masking, Always Encrypted, TDE, auditing, roles and permissions.
- **[Administration](references/admin.md)** -- Backup/restore, DBCC, maintenance, SQL Agent, DMV monitoring, server configuration.
- **[High Availability & DR](references/availability.md)** -- Always On AG, FCI, log shipping, Azure SQL geo-replication, contained AGs.
- **[Columnstore & Analytics](references/columnstore.md)** -- Columnstore indexes, batch mode, HTAP patterns, In-Memory OLTP.
- **[CLI & Tools](references/sqlcmd.md)** -- sqlcmd, SSMS, Azure Data Studio, dbatools, sp_whoisactive, Ola Hallengren.

## Official References

- <https://learn.microsoft.com/en-us/sql/sql-server/>
- <https://learn.microsoft.com/en-us/sql/t-sql/language-reference>
- <https://learn.microsoft.com/en-us/azure-data-studio/>

## Shared Styleguide Baseline

- Use shared styleguides for generic language/framework rules to reduce duplication in this skill.
- [General Principles](https://github.com/cofin/flow/blob/main/templates/styleguides/general.md)
- Keep this skill focused on tool-specific workflows, edge cases, and integration details.

Related Skills

flow-memory-keeper

9
from cofin/flow

Use at task, phase, flow, sync, archive, finish, revise, or failure checkpoints to keep Flow specs clean, capture learnings and failures, elevate durable patterns, and refine this skill with project-specific nuances

vue

9
from cofin/flow

Use when editing Vue projects, .vue files, vue.config.js, Vue 3 components, Composition API, <script setup>, SFC state, deployment workflows, or Vue CI configuration.

vite

9
from cofin/flow

Use when editing Vite projects, vite.config.ts, vite.config.js, Vite plugins, HMR, asset bundling, frontend build settings, deployment config, or Litestar/Vite integration.

uvicorn

9
from cofin/flow

Use when deploying ASGI apps with uvicorn, editing uvicorn CLI commands, Config or Server usage, workers, reload, event loop selection, SSL, lifespan, logging, or development server behavior.

tracer

9
from cofin/flow

Use when tracing execution paths, mapping dependencies, understanding unfamiliar code, following data flow, investigating end-to-end behavior, debugging call chains, or deciding which files to read next.

testing

9
from cofin/flow

Use when writing or refactoring tests, editing test_*.py, *.test.ts, *.spec.ts, conftest.py, vitest.config.ts, pytest fixtures, mocks, coverage, async tests, anyio, or test failure debugging.

terraform

9
from cofin/flow

Use when creating, adopting, refactoring, or operating Terraform, *.tf files, .terraform.lock.hcl, terragrunt.hcl, root modules, backends, state, workspaces, imports, CI plan/apply, tests, or policy checks.

tanstack

9
from cofin/flow

Use when editing TanStack code, @tanstack imports, useQuery, createRouter, React Query, TanStack Router, Table, Form, Store, file-based routing, data fetching, or SPA state management.

tailwind

9
from cofin/flow

Use when styling with Tailwind CSS, editing tailwind.config.ts, tailwind.config.js, @tailwind directives, utility classes, responsive layouts, @apply, cn(), @theme config, dark mode, or forms.

svelte

9
from cofin/flow

Use when editing Svelte components, .svelte files, svelte.config.js, Svelte 5 runes, $state, $derived, SvelteKit, component state, or migrating away from Svelte 4 patterns.

sqlalchemy

9
from cofin/flow

Use when editing SQLAlchemy code, sqlalchemy imports, mapped_column, DeclarativeBase, ORM models, relationships, select() queries, async sessions, engines, events, or migrations.

sphinx

9
from cofin/flow

Use when editing Sphinx docs, conf.py, .rst files, docs/source, autodoc, Read the Docs builds, Shibuya or Immaterial themes, Wasm extensions, VHS terminal recordings, or Sphinx CI.