Differences Between @, #, and ## in SQL Server: A Comprehensive Analysis

Dec 07, 2025 · Programming · 9 views · 7.8

Keywords: SQL Server | Temporary Tables | Variable Declaration

Abstract: This article provides an in-depth analysis of the three key symbols in SQL Server: @, #, and ##. The @ symbol declares variables for storing scalar values or table-type data; # creates local temporary tables visible only within the current session; ## creates global temporary tables accessible across all sessions. Through practical code examples, the article details their lifecycle, scope, and typical use cases, helping developers choose appropriate data storage methods based on specific requirements.

Introduction

In SQL Server development, understanding the differences between symbol prefixes is crucial for effective data management and query optimization. This article systematically analyzes the core distinctions among @, #, and ##, with practical examples illustrating their applications.

Variable Declaration: The @ Symbol

@variableName declares a variable, whose type determines the storable data content. Variables are defined within batches or stored procedures, with a lifecycle limited to the current execution context. For example:

DECLARE @employeeCount INT = 100;
DECLARE @employeeTable TABLE (ID INT, Name NVARCHAR(50));
INSERT INTO @employeeTable VALUES (1, 'John');

Here, @employeeCount stores an integer value, while @employeeTable is a table variable for temporary multi-row storage. Variables are commonly used for intermediate results or parameter passing, but note their performance characteristics: table variables lack row count statistics, potentially leading to suboptimal query plans.

Local Temporary Tables: The # Symbol

#tableName creates a local temporary table, visible only to the user session that created it. The system automatically drops the table when the session ends or the connection closes. For example:

CREATE TABLE #TempSales (
    SaleID INT PRIMARY KEY,
    Amount DECIMAL(10,2)
);
INSERT INTO #TempSales VALUES (1, 1500.00);
SELECT * FROM #TempSales;

Local temporary tables are suitable for complex data processing within a single session without cross-session sharing. Created in the tempdb database, they support indexes and statistics, making them ideal for large datasets. However, naming conflicts may occur: different sessions can create local temporary tables with the same name, as the system appends a unique suffix.

Global Temporary Tables: The ## Symbol

##tableName creates a global temporary table, visible to all database connection sessions. The system automatically drops it only when the creating session ends and all other sessions stop referencing the table. For example:

CREATE TABLE ##GlobalLog (
    LogID INT IDENTITY(1,1),
    Message NVARCHAR(255),
    LogTime DATETIME DEFAULT GETDATE()
);
-- Any session can insert data
INSERT INTO ##GlobalLog (Message) VALUES ('System started');

Global temporary tables are appropriate for cross-session data sharing, such as application-level temporary configurations or logging. Due to their global visibility, careful management is required to avoid data contamination or concurrency issues. It is recommended to explicitly drop them after use: DROP TABLE ##GlobalLog.

Comparative Analysis and Best Practices

In terms of scope, variables (@) are limited to the current batch, local temporary tables (#) to the current session, and global temporary tables (##) across all sessions. Regarding lifecycle, variables are released at batch end, local temporary tables are dropped at session end, and global temporary tables are removed when the creating session ends with no references.

Performance-wise, table variables are generally faster but offer limited optimization, while temporary tables support full optimization with higher overhead. Selection advice: use variables for small intermediate storage, local temporary tables for complex intra-session processing, and global temporary tables for cross-session sharing. Code example:

-- Use variable for aggregate result
DECLARE @totalSales DECIMAL(10,2);
SELECT @totalSales = SUM(Amount) FROM Sales;
-- Use local temporary table for data transformation
SELECT * INTO #FilteredData FROM Products WHERE Price > 100;
-- Use global temporary table for shared state
IF OBJECT_ID('tempdb..##SystemStatus') IS NULL
    CREATE TABLE ##SystemStatus (Status BIT);

In practice, choices should consider data volume, concurrency needs, and performance requirements. For instance, local temporary tables often outperform table variables in stored procedures handling large datasets; in systems requiring inter-session communication, global temporary tables provide a lightweight solution.

Conclusion

Understanding the differences between @, #, and ## is fundamental to efficient SQL Server development. Variables offer flexible scalar or table-value storage, local temporary tables support complex intra-session operations, and global temporary tables enable cross-session data sharing. By making informed choices, developers can optimize data management workflows, enhancing application performance and maintainability.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.