Creation of stored procedures in SQL Server - sql-server

I'm working on a fairly large application in which a database schema (tables, stored procedures, etc) is created by running a SQL script. The script is invoked from a stored procedure via xp_cmdshell like this.
CREATE PROC CreateNewScheme AS
BEGIN
...
EXEC xp_cmdshell 'osql createschema.sql -U username ...'
...
END
This stored procedure is run once during program initialization and again by SQL Server Agent during a scheduled job.
For security purposes we are required to disable xp_cmdshell. My first inclination was to just insert all of the schema creation commands into the existing stored procedure so it can be that can be executed as needed. However, this approach will not work because SQL Server does not support creation of stored procedures from other stored procedures.
One alternative might be to call the schema creation script from an external application rather than from a SQL script, but that's requires a fairly large rewrite, which we're trying to avoid if possible.
Is there a way to accomplish this with minimal changes?

My first inclination was to just insert all of the schema creation commands into the existing stored procedure so it can be that can be executed as needed. However, this approach will not work because SQL Server does not support creation of stored procedures from other stored procedures.
If you really need to wrap creation of stored procedures inside another store procedure you could wrap it with dynamic SQL:
CREATE PROC CreateNewScheme AS
BEGIN
EXEC('CREATE PROCEDURE myfirstproc AS ...');
EXEC('CREATE PROCEDURE mysecondproc AS ...');
END
Of course you will have to escape every ' inside dynamic SQL.
Another way is to exeute osql directly from SQL Server Agent job:
You should check if SQL Server Agent Account have sufficient privileges or create proxy.
EDIT:
If you cannot use SQL Server Agent, use Windows Task Scheduler to run osql:
Start Task Scheduler
Schedule a Task

We are in the same situation like you, whereby we want to disable xp_cmdshell, which we used for a couple of things on our production servers.
What we did was to create SQLCLR methods for the operations that xp_cmdshell performed in our environment. Sure, the assembly had to be created as UNSAFE, but the methods could only be called for the individual operations, and the methods had a lot of validation code, so that we didn't do anything "stupid".

Related

Does a Stored Procedure calling a SQL Agent Job have to reside on the same server?

I would like to create a stored procedure that calls a SQL Agent job, which will in turn call an SSIS package. The job and the SSIS package will reside on the same database server. However, I would prefer that the stored procedure resides on a different database server. The reason behind this is that we have an app that will be calling the sproc. I don't want to give it access to the database where the SQL Agent job and SSIS package reside.
How would I go about doing this?
In a different database in the same instance is very simple. Just use a doted name (db_name.schema_name.object_name).
In a different instance, you must create a linked server and use a doted name like :
instance_name.db_name.schema_name.object_name

SQL Server stored procedure - designate database to use

I am tasked with creating a stored procedure from a script I wrote which will update tables with data.
Since I run this script against a dev database and a live database, we have always manually changed the USE DATABASE in the script before running.
I am looking for a way to use USE DATABASE within a stored procedure.
Is this possible without having to create two stored procedures of the same script for each database (dev versus live)?
Assuming you mean MS SQL Server. You cannot use USE ... within a stored procedure, but you can directly reference a different database with fully qualified object notation.
database.schema.objectname
Example:
dev_mydb.dbo.MyTable
Do note though that if you need that database name to be variable then you will need to use dynamic SQL to set the dbname.

How to log to an external file from SQL Server 2016

I have a 3rd party software which calls a stored procedure in my SQL Server to insert log entries. I would rather have the log entries write directly to a txt file instead of being in a SQL Server table.
I have tried collecting the entries in a ##temptable and using BCP to write them out but ran into an issue. The 3rd party software wraps all calls to the stored procedure in a transaction which causes BCP to hang during exports.
I thought about using a ##temptable and having a SQL Server Agent job dump it on a regular interval but the transactions can be long running and I'm not sure how to make sure I can write entries to the text files without duplicate or missing rows depending on transaction lengths.
Is there a good way to write from a stored procedure into a file? If so, is there a way to batch the writes over multiple calls of the stored procedure?
To access resources being out of SQL Server control from TSQL batch you can use a CLR Stored Procedure. With it you can write some .NET code to do anything you want with for example files or network connection. Then you have to prepare a DLL assembly and connect it with SQL Server. Here you are an example from MSDN how to create a procedure from external assembly:
CREATE ASSEMBLY MyFirstUdp FROM 'C:\Programming\MyFirstUdp.dll';
CREATE PROCEDURE HelloWorld
AS EXTERNAL NAME MyFirstUdp.StoredProcedures.HelloWorld;
EXEC HelloWorld;
More information about CLR Stored Procedures (and presented example) you can find on https://msdn.microsoft.com/pl-pl/library/ms131094(v=sql.110).aspx

Running Stored Procs on Different Databases through Agent Job

I have a list of three stored procedures that need to be ran daily on a number of separate SQL databases. Each database is named differently, but the stored procedures on each are the same.
I have extremely limited knowledge on anything other than basic queries, but was thinking I could have a SQL Server Agent job on a database I set up as Master. Then I have that server push that job to the other databases once I configure those as Targets. My issue is that in thinking through this, the database names are different and within the SQL Server Agent wizard I can only set the database to what's currently on master instance.
What would be the best approach to executing this looping through servers to run the stored procs?
What you're looking for is a linked-server. They allow servers to be linked so that you can call objects from one server to another. They are very easy to setup. In your case, you'll need to create 3 linked-servers on the main server, which will be used to schedule the job. A linked-server will allow the main server to link to listed servers. Here are tutorials of how you can create a linked-server.
Once you've created a linked-server you'll simply create a job that will execute all 3 sprocs, something like this:
EXEC [server1].[database].[schema].[sp_name];
EXEC [server2].[database].[schema].[sp_name];
EXEC [server3].[database].[schema].[sp_name];

USE Statement in SQL Server

I am currently using USE [databaseName] in my stored procedures. However, is there a way that I can point this at the current local database and not give a database name? I know this may sound a bit obscure but its highly likely that I will be using these Stored Procedures in many different databases.
remove the USE [databaseName] from your stored procedure.
By default, the stored procedure will run on the current database (in which SP is created)

Resources