Analyzing SQL Dynamic Patterns
Analyzes Dynamic SQL occurrences flagged by SnowConvert (issue code SSC-EWI-0030), classifies them against a dialect-specific pattern catalog, scores complexity, and records migration considerations. All operations go through the scai assessment sql-dynamic command — there are no Python helpers, no CSV/JSON scripts, no bash loops.
Sub-Agent Mode
When invoked from a parent skill (e.g., assessment/SKILL.md) as a sub-agent, the parent provides a context block with the fields below. The review_mode field controls whether the per-occurrence review loop runs.
| Field | Required | Notes |
|---|---|---|
project_dir |
yes | absolute path to the SCAI project root |
output_dir |
yes | typically <project_dir>/assessment/json |
review_mode |
yes | generate-only, auto-review-all, or skip |
On entry: call the configure MCP tool with project_dir from the context block. Snowflake credentials are not required — scai assessment sql-dynamic reads only local CSVs and source files.
Branching by review_mode:
generate-only— run onlyscai assessment sql-dynamic generate(Workflow Step 1) and return. The output JSON will containPENDINGoccurrences; that is expected.auto-review-all— generate, then loopshow-code-unit→ analyze →update --status REVIEWEDfor every PENDING occurrence (Workflow Steps 2–6). Runstatsat the end and confirm zero PENDING. The single-record / unique-analysis rule from Critical Rules (NO BATCH UPDATES) still applies — each occurrence gets its own analysis.skip— return immediately with"status": "skipped". The parent should not have dispatched in this case; this branch is defensive.
On completion, return JSON only:
{
"sub_skill": "analyzing-sql-dynamic-patterns",
"status": "ok",
"output_json": "<abs path to sql_dynamic_analysis.json>",
"summary": "<one-line: total occurrences, REVIEWED count, PENDING count>",
"error": null
}
On skip: "status": "skipped", "output_json": null. On failure: "status": "error", "error": "<message>".
Critical Rules
ONLY USE scai assessment sql-dynamic: All generate / show / update / stats operations are subcommands of scai assessment sql-dynamic. Do not write custom scripts, parsers, or batch wrappers.
NO BATCH UPDATES: Each update invocation processes ONE record with ONE unique analysis.
- Do not "walk IDs" sequentially as a batch just because they are adjacent.
- Do not use shell loops (e.g.
for id in ...; do scai assessment sql-dynamic update ...; done) to apply the same update across many records. - Do not copy/paste identical notes across multiple IDs; each occurrence must have its own specific rationale, even within the same code unit.
CODE-UNIT-BASED WORKFLOW: Use show-file (or show-code-unit) to view all occurrences within a procedure/function. Analyze each code unit separately by reading its source code.
- The generated analysis JSON stores the full procedure source text inside each code unit under the
procedurefield, alongsidefileName,procedureName,codeUnitStartLine, andlinesOfCode. Treat the JSON as the "source bundle" for analysis.
QUALITY OVER SPEED: This work is often fast, but do not "rush" by batching, reusing notes, or skipping code review. Aim for consistent, defensible analyses per occurrence.
Source Platform Detection
CRITICAL FIRST STEP: Before classifying patterns, determine the source platform.
Detection methods:
- Check
TopLevelCodeUnits.*.csv—SourceLanguagecolumn (e.g.Transactfor SQL Server,RedShiftfor Redshift,Oraclefor Oracle,Teradatafor Teradata). - Examine code syntax in the procedure source (visible in the analysis JSON):
- SQL Server indicators:
sp_executesql,EXEC(@sql),QUOTENAME(),sys.*catalog views. - Redshift indicators:
EXECUTE ... USING,QUOTE_IDENT(),QUOTE_LITERAL(),pg_catalog.*,plpgsqlfunctions. - Oracle indicators:
EXECUTE IMMEDIATE,DBMS_SQL.*,DBMS_ASSERT.*,ALL_*/USER_*/DBA_*catalog views,PRAGMA AUTONOMOUS_TRANSACTION,:varnamenamed bind variables,@dblinkreferences. - Teradata indicators:
REPLACE PROCEDURE ... BEGIN ... END,EXECUTE IMMEDIATE <sql> USING ...with positional?placeholders,DBC.TablesV/DBC.ColumnsV/DBC.DatabasesV/DBC.IndicesVcatalog views,REPLACE MACRO/EXEC macro_name(...),VOLATILE TABLE,MULTISET/SETtable semantics,SET QUERY_BAND, BTEQ&variablesubstitution andBT/ETtransaction control.
- SQL Server indicators:
- Review source file extensions and DDL:
.sql,.prc,.fnc.
Pattern catalog selection:
- SQL Server → Snowflake:
reference/PATTERNS_TRANSACT.md - Redshift → Snowflake:
reference/PATTERNS_REDSHIFT.md - Oracle → Snowflake:
reference/PATTERNS_ORACLE.md - Teradata → Snowflake:
reference/PATTERNS_TERADATA.md
⚠️ Always confirm the source platform with the user if it is unclear. Pattern definitions differ significantly between platforms.
Inputs (auto-detected by parent)
The parent assessment skill resolves all inputs from project_dir. Do not prompt the user for paths.
| Input | Where it lives under project_dir |
|---|---|
| Project directory (preferred) | The project root itself — pass via --project-dir |
Issues.*.csv (CSV mode) |
reports/SnowConvert/ |
TopLevelCodeUnits.*.csv (CSV mode) |
reports/SnowConvert/ |
| Source code directory | source/ |
Mode selection:
- Project mode (preferred) —
scai assessment sql-dynamic generate --project-dir <project_dir> --output <path>. SCAI auto-detects the registry / CSV reports and the source directory. - CSV mode (fallback) —
scai assessment sql-dynamic generate --csv-dir <reports_dir> --source-dir <source_dir> --output <path>when the project layout is not standard.
Workflow
- Generate the analysis JSON from the project (or CSVs).
- Show file / show-code-unit to surface all occurrences in a procedure plus its source.
- Analyze each occurrence against the dialect's pattern catalog.
- Update each occurrence individually with
--status REVIEWEDand the per-occurrence fields. - Stats to track progress.
- Repeat steps 2–4 until every occurrence is
REVIEWED.
1. Generate
# Project mode (preferred)
scai assessment sql-dynamic generate \
--project-dir <project_dir> \
--output <project_dir>/assessment/json/sql_dynamic_analysis.json
# CSV mode (fallback)
scai assessment sql-dynamic generate \
--csv-dir <project_dir>/reports/SnowConvert \
--source-dir <project_dir>/source \
--output <project_dir>/assessment/json/sql_dynamic_analysis.json
What this creates:
- A JSON file with
metadata(totals, generation timestamp, input files) and acodeUnitsmap. - Each code unit holds
codeUnitId,procedureName,fileName,codeUnitStartLine,linesOfCode, the fullproceduretext, and anoccurrenceslist. - Each occurrence starts with
status: PENDINGand empty analysis fields, ready for review.
2. View occurrences for a code unit
Group occurrences by file or by code unit:
# All occurrences in the file containing a given record (or with no --id, list all files)
scai assessment sql-dynamic show-file <analysis.json>
scai assessment sql-dynamic show-file <analysis.json> --file <fileName>
# Full code unit view including the procedure source and every occurrence inside it
scai assessment sql-dynamic show-code-unit <analysis.json> --code-unit-id "[DB].[schema].[ProcName]"
# Single occurrence detail
scai assessment sql-dynamic show <analysis.json> --id <N>
Analysis approach:
- Use
show-fileto enumerate code units per file. - Pick one code unit and read its full procedure source (
show-code-unit). - Open the dialect-appropriate
reference/PATTERNS_<DIALECT>.mdand classify each dynamic SQL site against the catalog. - Update each occurrence individually (next step).
- Move on to the next code unit.
3. Classify patterns
Reference per dialect (must read before classifying):
- SQL Server migrations →
reference/PATTERNS_TRANSACT.md - Redshift migrations →
reference/PATTERNS_REDSHIFT.md - Oracle migrations →
reference/PATTERNS_ORACLE.md - Teradata migrations →
reference/PATTERNS_TERADATA.md
⚠️ Pick the correct catalog based on the source platform (see Source Platform Detection).
Process:
- Read every pattern in the appropriate catalog before reviewing the first occurrence.
- Compare the procedure source against each pattern.
- Identify all patterns that apply (multiple may apply to the same occurrence).
- Collect the analysis fields described below.
- Pass the patterns to
--categoryas a pipe-separated string ("Pattern-A | Pattern-B"); SCAI stores them as a list.
Per-occurrence fields to collect:
generated_sql (--generated-sql):
- The actual SQL that would be executed at runtime.
- Include the dynamic-SQL construction logic so it is clear what is built.
- Use representative values for variables; provide a complete best-effort statement (no ellipses or vague placeholders).
sql_classification (--sql-classification):
- DQL (SELECT) | DML (INSERT/UPDATE/DELETE) | DDL (CREATE/ALTER/DROP) | DCL (GRANT/REVOKE) | TCL (COMMIT/ROLLBACK) | UNKNOWN.
- Drives operation-level prioritization. Pattern tagging is separate — do not infer patterns from the SQL classification; choose them from the dialect catalog and pass via
--category.
notes (--notes): A JSON object with three required keys (see Notes Structure).
4. Score complexity
Scale: low (0–30), medium (31–60), high (61–85), critical (86–100).
Process:
- Start from the base complexity of the matched pattern in
PATTERNS_<DIALECT>.md. - Read the actual code carefully.
- Override the base score only if the code materially differs from the pattern baseline.
- Document the override reasoning under
complexityin the notes JSON.
5. Update an occurrence
scai assessment sql-dynamic update <analysis.json> \
--id <N> \
--line <line_number> \
--status REVIEWED \
--category "Pattern-Name | Additional-Pattern" \
--complexity medium \
--sql-classification DDL \
--generated-sql "CREATE TABLE dbo.TempTable (ID INT, Name VARCHAR(100))" \
--notes '{
"justification": "Line X uses dynamic SQL to construct a table name from user-supplied variables...",
"complexity": "- Deep concatenation chains (5+ levels)\n- No input validation detected\n- Cross-schema dynamic references",
"migration_considerations": "- Recommend Snowflake IDENTIFIER() function\n- Add input validation before migration\n- Estimated effort: 4–6 hours per occurrence"
}'
Command notes:
- The first positional argument is the analysis JSON path.
--idis required; it identifies the occurrence to update.--lineshould be set after reading the procedure source — generated records start withline = 0. Keep0only when the source line cannot be reliably determined.- At least one of
--line,--status,--category,--complexity,--notes,--generated-sql,--sql-classificationmust be supplied. --categoryaccepts pipe-separated names; SCAI splits them into a list internally.
6. Track progress
scai assessment sql-dynamic stats <analysis.json>
Reports totals, per-status counts, and per-category counts. Repeat steps 2–5 until no PENDING records remain.
Notes Structure
Each --notes value must be a JSON object with the three required keys below:
{
"justification": "Why this is dynamic SQL, what it does, context.",
"complexity": "Technical factors affecting migration difficulty.",
"migration_considerations": "Snowflake-specific recommendations, alternatives, effort estimate."
}
Field length and tone:
justification: 40+ words, full sentences, reference specific code elements.complexity: 30+ words, full sentences, list the technical drivers.migration_considerations: 40+ words, full sentences, end with a concrete effort estimate.- Do not write "similar to occurrence ##"; restate the context explicitly for every record.
Formatting tips:
- Use
\nfor line breaks within a multi-line field. - Single-quote the entire JSON in shell to avoid quote escaping headaches.
Reference Files
reference/PATTERNS_TRANSACT.md— pattern catalog for SQL Server → Snowflake migrations.reference/PATTERNS_REDSHIFT.md— pattern catalog for Redshift → Snowflake migrations.reference/PATTERNS_ORACLE.md— pattern catalog for Oracle → Snowflake migrations.reference/PATTERNS_TERADATA.md— pattern catalog for Teradata → Snowflake migrations.
Platform selection:
- Use
PATTERNS_TRANSACT.mdfor SQL Server sources. - Use
PATTERNS_REDSHIFT.mdfor Redshift sources. - Use
PATTERNS_ORACLE.mdfor Oracle sources. - Use
PATTERNS_TERADATA.mdfor Teradata sources.