If you spend much time writing T-SQL scripts, you’ve probably seen the GO keyword. It looks like a T-SQL command, but it’s not really part of T-SQL. Instead, it’s a batch separator recognized by SQL Server Management Studio (SSMS) and other client tools. When you hit the “Execute” button, any GO keyword in your script tells the tool that this is the end of a batch, and to send what came before it to SQL Server as one unit.
Many scripts will run fine without the GO keyword, but others will fail miserably. Understanding how GO works can save you from frustrating errors and unexpected behavior.
How Batches Work
SQL Server processes statements in batches. A batch is essentially a group of statements that SQL Server compiles and executes together. Some statements, like CREATE PROCEDURE, CREATE VIEW, or variable declarations, can only exist cleanly at the start of a batch. If you pile everything together without using GO, you’ll likely see errors you weren’t expecting.
If you’ve only ever run single queries, chances are you’ve never had a problem. It’s only when you try to combine multiple operations into a single script that you might start running into errors.
However, it all depends on the statements you’re trying to combine. Not all combined statements will fail without GO. there are many cases where we can combine multiple statements into a single batch, and therefore omit the GO keyword. Other times, we’ll need to include it.
Example: Omitting GO
Take this script for instance:
DROP TABLE IF EXISTS TestTable
CREATE TABLE TestTable
(
Id INT PRIMARY KEY,
Name NVARCHAR(50)
)
INSERT INTO TestTable (Id, Name)
VALUES (1, 'Sample')
This script contains three different statements. If you run this in one shot without GO, SQL Server sees it all as one batch. In this case there’s no problem – the script will run without error.
But now let’s try the following:
DROP TABLE IF EXISTS TestTable
CREATE TABLE TestTable
(
Id INT PRIMARY KEY,
Name NVARCHAR(50)
)
CREATE PROCEDURE GetTestTable
AS
BEGIN
SELECT * FROM TestTable
END
Output:
Msg 111, Level 15, State 1, Procedure GetTestTable, Line 11
'CREATE/ALTER PROCEDURE' must be the first statement in a query batch.
This time an error is returned. That’s because SQL Server requires that if we’re going to use the CREATE PROCEDURE statement, it must be the first statement in a query batch.
The Fix: Using GO
Add a GO where the logical break is needed:
DROP TABLE IF EXISTS TestTable
GO
CREATE TABLE TestTable
(
Id INT PRIMARY KEY,
Name NVARCHAR(50)
)
GO
CREATE PROCEDURE GetTestTable
AS
BEGIN
SELECT * FROM TestTable
END
GO
Now the first batch drops the table (if it exists), the second creates the table, and the third batch creates the procedure. SQL Server is fine with this, because we used the GO keyword to separate each statement into its own batch.
In this case, it’s the CREATE PROCEDURE statement that’s the main issue. We could have removed the other two GO keywords and left just one – the one before the CREATE PROCEDURE statement:
DROP TABLE IF EXISTS TestTable
CREATE TABLE TestTable
(
Id INT PRIMARY KEY,
Name NVARCHAR(50)
)
GO
CREATE PROCEDURE GetTestTable
AS
BEGIN
SELECT * FROM TestTable
END
However, now that the procedure already exists, if we were to run the script again, we’d need to add a DROP PROCEDURE statement to drop the existing one (otherwise we’ll get another error, due to the procedure already existing).
DROP TABLE IF EXISTS TestTable
CREATE TABLE TestTable
(
Id INT PRIMARY KEY,
Name NVARCHAR(50)
)
GO
DROP PROCEDURE IF EXISTS GetTestTable
GO
CREATE PROCEDURE GetTestTable
AS
BEGIN
SELECT * FROM TestTable
END
And because CREATE PROCEDURE must be the first statement in a batch, we needed to follow the DROP PROCEDURE statement with the GO keyword.
This leaves the script slightly inconsistent. There are GO statements in some parts but not in others. However, they’re only in the parts that require it. You’ll need to decide whether or not to include GO only when required, or simply include it even when not required, in order to keep things looking consistent.