Why is this statement included in the stored procedure definition? - sql

I got nailed today by a typo, its a simple typo when I defined a script to create a stored procedure under Sql Server 2005, I forgot a GO statement in between the END statement and the GRANT statement, this lead to the GRANT statement being included in the stored procedure definition and running at the end of the stored procedure (verified with SQL Profiler).
Here is the code:
USE [TestGround]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[FooProc]
AS
BEGIN
SELECT * FROM dbo.Foo
END
-- a GO statement is missing here..
GRANT EXECUTE ON [dbo].[Foo] TO dbo
I understand that GO signifies the end of a batch, but I was surprised to see that the GRANT statement was included in the stored procedure, I've never forgotten the GO statement before so haven't seen this issue.
Could someone please explain to me why this happens?

You can leave out the BEGIN / END pair: the definition doesn't end at END. It continues until the end of the file or a GO, whichever comes first.

Related

DB2 stored procedure for clearing the database can't be found

I'm trying to create a DB2 stored procedure that will clear all the data tables and reset the indexes to 0. The creating of the procedure is pretty straightforward, but the issue is that DB2 immediately forgets it exists. What am I doing wrong?
Create a simple script:
create procedure CLEARTABLES()
language sql
BEGIN
commit;
truncate TABLE1 immediate;
truncate TABLE2 immediate;
truncate TABLE3 immediate;
END;
Make sure we can execute it:
GRANT EXECUTE ON PROCEDURE CLEARTABLES TO PUBLIC;
And here is where it all breaks down with No authorized routine named "CLEARTABLES" of type "PROCEDURE" having compatible arguments was found.. SQLCODE=-440, SQLSTATE=42884, DRIVER=4.26.14
CALL CLEARTABLES;
I've also tried execute, but this does not appear to do anything.
EXECUTE CLEARTABLES;
And to prove it exists:
SELECT * FROM SYSIBM.SYSROUTINES s
WHERE s.ROUTINETYPE = 'P' AND s.ROUTINENAME = 'CLEARTABLES'
I feel like I'm missing very obvious here so I've tried a lot of small things like parentheses, no parentheses, lower/upper case etc. I'm using DBeaver and I can see the procedure under Application Objects > Procedures named CLEARTABLES in all caps no parameters, yet DB2 somehow can't find it with the way I'm calling for it.

Stored Procedure: There is already an object named '#columntable' in the database

Please see the code below:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE Test
AS
BEGIN
begin
select * into #dbreviews from dbreviews
end
drop table #dbreviews
begin
select * into #dbreviews from dbreviews
end
END
GO
The error I get is:
There is already an object named '#dbreviews' in the database.
Questions like this: There is already an object named '#columntable' in the database are telling me this should be possible.
As per SQL Server specification, it is not allowed. Please refer to the documentation.
If more than one temporary table is created inside a single stored
procedure or batch, they must have different names.
You are creating two temporary tables, with the same name #dbreviews. This is not allowed.
Please make sure that you use the "alter" syntax:
ALTER PROCEDURE
if you paste code in, you may need to replace "create" with "alter"... this just happened to me and is frustrating, so I hope this helps someone else.
Note: This was my answer to a slightly different question, so I recycled it.
At the end of your PROC, #dbreviews exists. When you run it again, it already exists. If you want to recreate every time you run the proc, use:
IF OBJECT_ID('tempdb..#dbreviews') IS NOT NULL
THEN
drop table #dbreviews
END IF
select * into #dbreviews from dbreviews

Microsoft SQL server: copy table from linked server to current database using a stored procedure

I am using Microsoft SQL server. the following code works if run from a QUERY:
SELECT *
INTO mydatabase.dbo.atable
FROM linkedserver.sandbox.dbo.atable
but it does not if inserted into a stored procedure:
SET ANSI_NULLS ON GO
SET QUOTED_IDENTIFIER ON GO
ALTER PROCEDURE dataMigration
AS BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT *
INTO mydatabase.dbo.atable
FROM linkedserver.sandbox.dbo.atable
END
GO
Command(s) completes successfully but no table is created into mydatabase. Sorry for the trivial question. I had a look at similar issues but i did not find a case similar to mine.
Thank you for your help.
You have to execute the stored Procedure after you run the code to alter it.
try running:
exec dataMigration
Right clickOption Image the store procedure and click "Execute Store procedure"

Should we end stored procedures with the GO statement?

Should we end stored procedures with GO statement, if so what are the advantages of using GO?
CREATE PROCEDURE uspGetAddress #City nvarchar(30)
AS
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City
GO
The statement go, per the documentation
Signals the end of a batch of Transact-SQL statements to the SQL Server utilities.
...
GO is not a Transact-SQL statement; it is a command recognized by the sqlcmd and osql
utilities and SQL Server Management Studio Code editor.
SQL Server utilities interpret GO as a signal that they should send the current batch
of Transact-SQL statements to an instance of SQL Server. The current batch of statements
is composed of all statements entered since the last GO, or since the start of the
ad-hoc session or script if this is the first GO.
A Transact-SQL statement cannot occupy the same line as a GO command. However, the line
can contain comments.
Users must follow the rules for batches. For example, any execution of a stored procedure
after the first statement in a batch must include the EXECUTE keyword. The scope of
local (user-defined) variables is limited to a batch, and cannot be referenced after a
GO command.
A stored procedure definition, per the documentation for create procedure, comes with restrictions. it must be the first (and only) statement in the batch:
The CREATE PROCEDURE statement cannot be combined with other Transact-SQL statements in
a single batch.
That means the body of stored procedure ends with the batch. Adding GO in your source file is good practice. Especially since it's common to do things prior to and following the creation of a stored procedure. You'll often see source files that look something like this:
if (object_id('dbo.foobar') is not null ) drop procedure dbo.foobar
GO
-- dbo.foobar --------------------------------------------
--
-- This stored procedure does amazing and wonderful things
----------------------------------------------------------
create procedure dbo.foobar
as
...
{a sequence of amazing and wonderful SQL statements}
...
return 0
GO
grant execute on dbo.foobar to some_schema
GO
And the value for GO is adjustable in Sql Server Management Studio's options. If you'd like to use something like jump instead of go, you can (bearing in mind that you're almost certainly going to give yourself grief in doing so.).
No, you should end your procedure with RETURN.
CREATE PROCEDURE uspGetAddress #City nvarchar(30)
AS
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City
RETURN
The GO is really meant to separate commands in a sql script.
Just wanted to point out that without a GO at the end of your stored procedure, any T-SQL after the supposed end of the procedure body will still be included in the body of the proc.
For example
CREATE PROCEDURE Foo
BEGIN
SELECT * FROM dbo.Bar;
END
DROP TABLE dbo.Bar;
In this example, running EXEC dbo.Foo will end up dropping the table even though it is after the END. To avoid that, you need to place a GO after the END.
I prefer to surround the body of the stored procedure with begin and end statements:
CREATE PROCEDURE uspGetAddress (
#City nvarchar(30)
) AS
BEGIN
SELECT *
FROM AdventureWorks.Person.Address
WHERE City = #City;
END;
GO is a not a T-SQL command. It is understood by the tools that run scripts. As the documentation describes:
GO is not a Transact-SQL statement; it is a command recognized by the
sqlcmd and osql utilities and SQL Server Management Studio Code
editor.
SQL Server utilities interpret GO as a signal that they should send
the current batch of Transact-SQL statements to an instance of SQL
Server. The current batch of statements is composed of all statements
entered since the last GO, or since the start of the ad hoc session or
script if this is the first GO.
By the way, in your case, a user-defined table function might be more appropriate than a stored procedure.

create stored procedure if doesn't exist in sql server

Oracle does "create or replace" statements. Sql server does not seem to - if you are scripting out from Enterprise Manager, it instead suggests "drop and create" instead. Drop and create is undesirable in any situation where you've done grants on the stored procedure, because it tosses out any grants your database administration team has done. You really need "create or replace" to help with separation of conerns between developers and administrators.
What I've been doing recently is this:
use [myDatabase]
go
create procedure myProcedure as
begin
print 'placeholder'
end
go
alter procedure myProcedure as
begin
-- real sproc code here
end
go
This does what I want. If the procedure doesn't exist, create it then alter in the correct code. If the procedure does exist, the create fails and the alter updates the code with the new code.
It creates a different problem for the administrators, because the create throws a misleading error if the stored procedure already exists. Misleading, of course, in the fact that you shouldn't see red error text when the desired outcome has occured.
Does anyone have a way to suppress the red text? Everything I've tried leads to a 'CREATE/ALTER PROCEDURE must be the first statement in a query batch' error in some way or another.
This will work and keep the permissions intact:
use [myDatabase]
go
if object_id('dbo.myProcedure', 'p') is null
exec ('create procedure myProcedure as select 1')
go
alter procedure myProcedure as
SET NOCOUNT ON
-- real sproc code here. you don't really need BEGIN-END
go
Like this:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[myProcedure]')
AND type in (N'P', N'PC'))
BEGIN
EXEC('
create procedure myProcedure as
begin
print ''placeholder''
end
')
END
EXEC('
alter procedure myProcedure as
begin
-- real sproc code here
end
')
NOTES:
remember to double up your quotes in the dynamic SQL strings.
I have indented it for readability, but that will also add the extra indent spaces to your actual procedures listings. If you don't wnat that, then just reduce the indentation level on the dynamic SQL text.
Finally the day is here where SQL Server has implemented an equivalent to Create or Replace. Their equivalent is "Create or Alter". This is available as of SQL Server 2016 SP1. Example usage:
use [myDatabase]
go
Create or Alter procedure myProcedure as
begin
-- procedure code here
end
go