I want to do something like this:
CREATE OR ALTER PROC myPROC
#myInput NVARCHAR(MAX)
AS
BEGIN
SELECT *
FROM myTABLE
-- I want this next command to run not to be stored for later execution.
EXEC RegisterProcSomewhere
END
GO
Is there a preferred way to do this? Essentially I want to collect metadata on my procedure when I CREATE/ALTER them.
Call it outside the proc to execute it immediately.
CREATE OR ALTER PROC myPROC
#myInput NVARCHAR(MAX)
AS
BEGIN
SELECT * FROM myTABLE
-------------------------------
END
GO
--I want this next command to run not to be stored for later execution.
EXEC RegisterProcSomewhere
Related
Well yeah, pretty specific.
I have a job that executes a SSIS Package. This package has a variable called "Email" which is a string.
I'm executing this job via stored procedure. I need to pass the value for that variable to the job, how do I do it?
This is the stored procedure I'm using to execute the job (#VarValue is the value I want to pass to the SSIS package):
USE [DevDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spChecklistEmail]
#JobName [nvarchar](100),
#VarValue [nvarchar](255),
#ReturnValue [int] OUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #JobId binary(16);
DECLARE #job_status INT
SELECT #JobId = job_id FROM msdb.dbo.sysjobs WHERE (name = #JobName);
SELECT #job_status = [dbo].[fn_GetJobStatus](#JobName);
IF (#job_status IN (2, 4))
BEGIN
SET #ReturnValue=#job_status;
END
ELSE
BEGIN
IF (#JobId IS NOT NULL)
BEGIN
EXEC #ReturnValue=msdb.dbo.sp_start_job #job_id=#JobId;
END
ELSE
BEGIN
SET #ReturnValue=-2;
END
END
RETURN (#ReturnValue)
END
There isn't any real easy way to do this. The only thing I can think of is to take that value and before you call the package create a table or temp table and load the variable into that table you created. After that you could then access that varibale in you ssis package for what you need to use it for. Don't forget to clean up the extra table and/or value after the job.
Check out this link: https://msdn.microsoft.com/en-us/library/jj820152.aspx
Specifically part 2.
Looks like you can create variables and set them in the EXEC statement.
EXEC #ReturnValue=msdb.dbo.sp_start_job #job_id=#JobId, #parameter_name=N'Email', #parameter_value=#VarValue;
Something like that.
I am trying to create a view out of a stored procedure and am perplexed to see two opposing results from a very similar approach.
Example 1
CREATE PROCEDURE cv AS
GO
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
Whereas this example creates the view once the procedure is created for the 1st time, it will not recreate the view when I execute the procedure at a later stage using:
EXEC cv
Example 2
CREATE PROCEDURE cv
#table SYSNAME
AS
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW '+ #table +' AS SELECT * FROM someOtherTable'
This one instead does not create the view when the procedure is created for the first time but creates the view afterwards every time it is called by:
EXEC #sql;
Why is this the case? I think this is really confusing and does not make sense or does it?
For your 1st statement
CREATE PROCEDURE cv AS
GO --<-- This GO here terminates the batch
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
the GO batch terminator create the procedure and the EXECUTES the following statement straightaway. So it appears to you as you have created a procedure which created the view for you.
Infact these are two statements in two batches.
--BATCH 1
CREATE PROCEDURE cv AS
GO
--BATCH 2
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
Batch 1 Creates a procedure which has nothing inside it, but it creates a procedure object for you with no functionality/Definition at all.
Statement after the key word GO is executed separately and creates the view for you.
My Suggestion
Always check for an object's existence before you create it. I would write the procedure something like this..
CREATE PROCEDURE cv
AS
BEGIN
SET NOCOUNT ON;
IF OBJECT_ID ('test', 'V') IS NOT NULL
BEGIN
DROP VIEW test
END
DECLARE #sql nvarchar(MAX)
SET #sql = 'CREATE VIEW test AS SELECT * FROM someOtherTable'
exec (#sql)
END
In Example 1 - you are creating a view with a hard-coded name of test. On subsequent runs of your proc, as the view already exists, SQL Server will throw an error because you are trying to create a view with the same name as one that already exists.
In Example 2, you are passing in the name of the view as a parameter. This will always create a new view unless the #table value you pass in corresponds to an existing view.
Just wondering - why are you creating a view with a stored proc? This is not something you would normally do in SQL.
You need to change
EXEC #sql to EXEC (sql)
EXEC can be use to run stored procedure, not dynamic sql
eg.
declare #dd varchar(100)='Select ''A'''
exec (#dd) ->will work fine
exec #dd -> Error
Read more about The Curse and Blessings of Dynamic SQL
Create view statement cannot be used with a stored procedure
EXEC ('CREATE VIEW ViewName AS SELECT * FROM OPENQUERY(Yourservername,''EXECUTE [databasename].[dbo].[sp_name] ''''' +Parameter + ''''''')')
I need to make a stored procedure which creates a user in more than one database. Something like this:
USE [database1]
CREATE USER [userLogin] FOR LOGIN [userLogin]
USE [database2]
CREATE USER [userLogin] FOR LOGIN [userLogin]
Since the CREATE USER statement does his job in the current database I need to use the USE statement to change between databases, but it can't be used inside stored procedures.
How can I do this?
Dynamic SQL
CREATE PROCEDURE spTestProc
AS
EXEC ('USE [database1]; CREATE USER [userLogin] FOR LOGIN [userLogin]')
EXEC ('USE [database2]; CREATE USER [userLogin] FOR LOGIN [userLogin]')
GO
SQL Server gives us a system stored procedure to do this. My understanding is that the recommended method would be to use sys.sp_grantdbaccess:
CREATE PROCEDURE usp_CreateTwoUSers
AS
BEGIN
-- Create a user for a login in the current DB:
Exec sp_grantdbaccess [userLogin], [name_in_db];
-- Create a user for a login in an external DB:
Exec ExternalDatabaseName.sys.sp_grantdbaccess [userLogin], [name_in_db];
END
I did it like below:
Alter Procedure testProc
#dbName varchar(50)
As
declare #var varchar(100)
set #var = 'Exec(''create table tableName(name varchar(50))'')'
Exec('Use '+ #dbName + ';' + #var)
Exec testProc 'test_db'
CREATE PROCEDURE spTestProc
AS
BEGIN
EXECUTE sp_executesql N'USE DB1 SELECT * FROM TABLE1'
EXECUTE sp_executesql N'USE DB2 SELECT * FROM Table2'
END
exec spTestProc
now it is worked.
If you're writing dynamic SQL with EXEC sp_executesql ('query1') or EXEC ('query2') this will return correct db which you want. If you're writing static SQL or your query outside of dynamic SQL quotes or parantheses it will work on master (where you create stored procedure(default is master)).
CREATE PROCEDURE master.dbo.mysp1
AS
EXEC ('USE model; SELECT DB_NAME()') -- or sp_executesql N'USE model; SELECT DB_NAME()'
--this returns 'model'
GO
CREATE PROCEDURE master.dbo.mysp2
AS
EXEC ('USE model;') -- or sp_executesql N'USE model;'
SELECT DB_NAME()
-- this returns 'master'
GO
It should be noted that if you want to use single quotes within a EXEC command, you will need to double the amount of single quotes
e.g.
EXEC ('USE [database1]; select * from Authors where name = ''John'' ')
In this example, John has 2 single quotes before and after it.
You cannot use double quotes for this type of query.
Using sp_executesql seems to work, for more info see http://msdn.microsoft.com/en-us/library/ms175170.aspx
I tested it using this and it worked fine:
CREATE PROCEDURE spTestProc
AS
BEGIN
EXECUTE sp_executesql N'USE DB1;'
SELECT * FROM TABLE1
EXECUTE sp_executesql N'USE DB2;'
SELECT * FROM Table2
END
exec spTestProc
I have created a stored procedure in SQL Server 2005, also I create another stored proc (that accepts some input parameters), I have to invoke with the use of the first proc.
CREATE PROCEDURE prc_inner (#value INT)
AS
SELECT #value
GO
CREATE PROCEDURE prc_outer (#value INT)
AS
EXEC prc_inner #value
GO
EXEC prc_outer 1
Look up EXEC sp_executesql or just plain EXEC [storedprocedurename]
I store all of my T-SQL DDL statements in a Visual Studio database project under version control. The scripts are meant to always run without error, so they include a drop/create syntax like so:
use MyDatabase
go
if objectproperty(object_id('dbo.MyProcName'), 'IsProcedure') = 1 begin
drop procedure dbo.MyProcName as
end
go
-----------------------------------------------------------------------
-- $Id: $
-- Notes: blah blah
-----------------------------------------------------------------------
create procedure dbo.MyProcName as
--...
go
Trouble is, we've moved to a replication scenario so I can no longer use my drop/create syntax because you cannot drop objects marked for replication. Now I need to create the proc if it doesn't exist, or alter it if it does. And I can't reverse my IF logic because I can't create a proc within an IF statement - I can only drop it. Any ideas?
EDIT:
Thanks to Adam's answer, here's what I wound up using. Don't know why I didn't consider executing a SQL string... must drink more coffee.
use MyDatabase
go
if objectproperty(object_id('dbo.MyProcName'), 'IsProcedure') is null begin
exec('create proc dbo.MyProcName as')
end
go
-----------------------------------------------------------------------
-- $Id: $
-- Notes: blah blah
-----------------------------------------------------------------------
alter procedure dbo.MyProcName as
--...
go
What you can do is have the first portion of your script create a stub for the procedure if it doesn't exist, then turn the rest of the script into an ALTER script instead of a CREATE.
For example:
if objectproperty(object_id('dbo.MyProcName'), 'IsProcedure') <> 1 begin
exec sp_ExecuteSql N'create Procedure dbo.MyProcName as select 1'
end
go
-----------------------------------------------------------------------
-- $Id: $
-- Notes: blah blah
-----------------------------------------------------------------------
alter procedure dbo.MyProcName as
--...
go
Note that you'll have to use sp_ExecuteSql (or something equivalent) here, since create procedure must be the first statement in a batch.
Wrap the creation of the stored procedure into an EXEC and you can reverse your if logic:
exec (N'create procedure...
An example like Adam's answer would be something like:
declare #ID int
select #ID = ID from sysobjects where OBJECT_NAME(ID)='Proc1' and USER_NAME(uid) = 'dbo'
if #ID is null
begin
exec('create procedure dbo.Proc1 as')
end
else
begin
if OBJECTPROPERTY(#ID,N'IsProcedure')=0 or OBJECTPROPERTY(#ID,N'IsMSShipped')=1
begin
RAISERROR('An object called dbo.Proc1 exists in the database, but is of the wrong type',16,1) WITH NOWAIT
end
end
go
ALTER procedure [dbo].[Proc1]
/* Body of procedure */
Adding Examples for TABLE FUNCTIONS:
IF objectproperty(object_id('dbo.udf_MyFunction'), 'IsTableFunction') is null
EXEC sp_ExecuteSql N'CREATE FUNCTION dbo.udf_MyFunction () RETURNS #X TABLE (Id int) AS BEGIN RETURN END'
GO
and SCALAR FUNCTIONS:
IF objectproperty(object_id('dbo.udf_MyFunction'), 'IsScalarFunction') is null
EXEC sp_ExecuteSql N'CREATE FUNCTION dbo.udf_MyFunction () RETURNS int AS BEGIN RETURN 0 END'
GO