SQL Tran Docs
  • Overview
    • About
    • Getting started
    • Object lifecycle
    • Why is there no AI inside?
    • Performance considerations
    • Security considerations
    • Assessment
    • Unlocking projects
    • Interface walk-through
    • Translation scenarios
    • Prerequisites for Azure Marketplace deployment
  • Emulation Scenarios
    • Emulation in SQL Tran
    • SQL Server to Fabric Warehouse
      • Data types
      • Case sensitivity
      • Cursors
        • Basic cursor loop
        • Cursor types
        • Fetch direction modes
        • Cursors in control flow
        • Nested cursors
        • Data modification cursors
        • Multiple cursors
        • Subqueries and filtering
      • Named procedure parameters
      • Result set limiting
      • MERGE statements
      • Computed columns
      • External tables
      • Materialized views
      • Identity columns
      • Unsupported system objects
    • Synapse Analytics to Fabric Warehouse
      • Emulations
      • Limitations
    • SQL Server to Synapse Analytics
    • Oracle to PostgreSQL
  • Project wizard
    • Source database
    • Target database
    • Wrapping up
  • Projects
    • Project list
    • Overview
    • Workspace
    • Reports
    • Tests
    • Scratch pad
    • Settings
      • Project name
      • Mapping
      • Database connections
    • Navigation
    • Object complexity
    • Static analysis
    • Translation errors
    • Exporting and importing projects
  • Workspace
    • Object tree
    • Data lineage
    • Code
    • Actions
      • Overriding source
      • Overriding target
      • Ignoring objects
  • Tests
    • Workflow
    • Configure SQL Tran
    • Connecting to databases
      • Fabric Warehouse
      • Synapse Dedicated SQL Pool
      • Azure SQL Database, Azure SQL Managed Instance, Microsoft SQL Server
    • Tables
    • Views
    • Procedures
    • Functions
    • Triggers
    • Performance tests
  • Scripter
    • About
    • Supported databases
    • SQL Server
    • Azure SQL
    • Synapse Dedicated Pool
    • Oracle
    • PostgreSQL
    • MySQL
Powered by GitBook
On this page
  • Emulation context
  • Emulation strategy
  • Code example
  • Important notes
  1. Emulation Scenarios
  2. SQL Server to Fabric Warehouse
  3. Cursors

Cursors in control flow

Emulation context

In SQL Server, cursors can be conditionally declared inside control flow constructs like IF / ELSE or repeatedly declared inside loops such as WHILE. This allows dynamic or context-dependent cursor logic where the same cursor name might appear multiple times across different branches or iterations.

Microsoft Fabric Warehouse, however, does not support cursors natively, nor does it have block-scoped or session-scoped temp tables in the same way. This creates challenges when translating control flow code that relies on repeated or nested cursor declarations, particularly regarding temp table reuse and naming.

SQL Tran addresses this by applying its standard emulation pattern — but repeated declarations and reused cursor names can lead to subtle conflicts that require careful manual review.


Emulation strategy

SQL Tran emulates control flow cursor patterns by:

  • Translating each declared cursor into a pre-materialized temp table (e.g., #person_cursor) within its block or loop.

  • Generating per-scope control variables (e.g., @CurrentRow_person_cursor, @RowCount_person_cursor) tied to the cursor name.

  • Recreating the temp table each time the cursor is declared, even inside loops.

Specific behaviors include:

  • Conditional branches (IF / ELSE): SQL Tran translates each branch independently, but if the same cursor name is reused, the temp table name (#person_cursor) will appear identically across branches. This may be harmless if the branches are mutually exclusive but can cause issues if combined.

  • Looped declarations (WHILE): When a cursor is declared inside a loop, SQL Tran generates repeated temp table creation inside each iteration. While this works structurally, it may introduce performance overhead or naming conflicts if temp tables are not properly isolated.

  • Scoping of variables: Scalar variables tied to the cursor (like row counters) are translated as local declarations inside each block, without cross-scope protections. Manual review is recommended if variable reuse could lead to unintended cross-block interference.


Code example

SQL Server:

CREATE PROCEDURE dbo.ProcessPeople
AS
BEGIN
	DECLARE @UseCursor BIT = 1;
	DECLARE @BusinessEntityID INT, @LastName NVARCHAR(50);
	IF @UseCursor = 1
	BEGIN
		DECLARE person_cursor CURSOR FOR
		SELECT BusinessEntityID, LastName FROM Person.Person;
		OPEN person_cursor;
		FETCH NEXT FROM person_cursor INTO @BusinessEntityID, @LastName;
		WHILE @@FETCH_STATUS = 0
		BEGIN
			-- Placeholder for logic
			FETCH NEXT FROM person_cursor INTO @BusinessEntityID, @LastName;
		END;
		CLOSE person_cursor;
		DEALLOCATE person_cursor;
	END
END

Fabric Warehouse (generated by SQL Tran):

CREATE PROCEDURE dbo.ProcessPeople
AS
BEGIN
	DECLARE @UseCursor BIT = 1;
	DECLARE @BusinessEntityID INT, @LastName NVARCHAR(50);
	IF @UseCursor = 1
	BEGIN
		DECLARE @RowCount_person_cursor INT;
DECLARE @CurrentRow_person_cursor INT = 1;
CREATE TABLE #person_cursor (
	RowNum INT, BusinessEntityID INT, LastName NVARCHAR(50)
)INSERT
	INTO #person_cursor (RowNum, BusinessEntityID, LastName)
	SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNum,
		BusinessEntityID,
		LastName
	FROM
		Person.Person;
SELECT @RowCount_person_cursor = COUNT(*)
FROM
	#person_cursor;
		
		SELECT @BusinessEntityID = BusinessEntityID,
	@LastName = LastName
FROM
	#person_cursor
WHERE
	RowNum = @CurrentRow_person_cursor;
		WHILE @CurrentRow_person_cursor <= @RowCount_person_cursor
		BEGIN
			-- Placeholder for logic
			SET @CurrentRow_person_cursor = @CurrentRow_person_cursor + 1;
SELECT @BusinessEntityID = BusinessEntityID,
	@LastName = LastName
FROM
	#person_cursor
WHERE
	RowNum = @CurrentRow_person_cursor;
		END;
		
		DROP TABLE IF EXISTS #person_cursor;
	END
END

Important notes

  • Repeated temp table creation: Declaring a cursor inside a loop leads to repeated CREATE TABLE and DROP TABLE operations on each iteration. This may affect performance and should be reviewed for optimization.

  • Naming conflicts for reused cursors: If the same cursor name is declared in multiple blocks (e.g., in IF / ELSE or across nested loops), SQL Tran generates the same temp table name (#person_cursor) each time. This can lead to overlapping definitions and break the logic.

  • Variable scoping issues: Cursor-related variables (e.g., @CurrentRow_person_cursor) are redeclared per block but use consistent names. Without additional isolation, there is a risk of cross-scope interference when multiple cursors are used.

  • No automatic renaming or suffixing: SQL Tran does not automatically rename temp tables or variables to guarantee uniqueness across control flow blocks. Users must manually adjust the translated code if naming conflicts are suspected.

  • Manual review recommended: Any control flow logic that conditionally or repeatedly declares cursors should be carefully reviewed after translation. Pay special attention to cursor names, temp table definitions, and variable reuse.

PreviousFetch direction modesNextNested cursors

Last updated 6 days ago

Cursor in control flow emulation in SQL Tran