Simulate a table creation with SQL - sql

Is there a standard way to simulate a table creation in a database by using SQL? I don't want the table to be created, just check if it could be created.
One way would be to create it and then delete it again.
Any other way?

Most major servers support transactional DDL, so you can do something along these lines:
begin transaction
create table Foo ...
rollback transaction
Theoretically, in case of error it should be reported back to client, but table will not be created altogether.

Depends on the SQL DBMS you're interested in. For example Postgres supports transactional DDL and the following will work:
START TRANSACTION;
CREATE TABLE ... ();
<check for error here>
ROLLBACK;

If you're using MySQL, you could create it using a transient storage engine, like MEMORY .

Really, you have to actually create it to make sure everything is OK.
Foreign key references, functions used as default or check constraints or in computed columns are not checked until execute time.

One basic method (SQL Server) is to use "SET FMTONLY ON".
Useful for checking the statement is valid, though won't tell you everything (e.g. if the table already exists).
This will succeed:
SET FMTONLY ON
EXECUTE ('CREATE TABLE SomeTable(SomeField INTEGER)')
SET FMTONLY OFF
This will not:
SET FMTONLY ON
EXECUTE ('CREATE TABLE SomeTable(dodgysyntax)')
SET FMTONLY OFF
This approach is probably more useful for SELECT statements, which is what I've used it for in the past. It doesn't actually execute the statement, but returns out the metadata.

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.

SQL Server 17, database migration, function for setting identity in primary key

I have two twin databases and want to migrate one into another. For that I would like to have a written function so that primary key can be set by utils function. I did already by using UI in SQL Server, but that is tiresome, as there are many tables to repeat that process. Utils function would be setting identity before migrating table and then removing it after job is done.
For example:
insert into TABLE
(colum_names)
select column_names
from TABLE
Before and after I would like to set and remove identity automatically stead doing this:
I know there are ways around this with recreating tables, but for obvious reasons(query time, server load) I do not want to do that :)
If I'm not misunderstanding, you are using an external utility to perform this migration. In that case, you can execute the SET IDENTITY_INSERT [dbo].[YourTable] ON; statement in a command prior to your migration steps.
For example, with C#:
using(SqlConnection myConn= new SqlConnection(conn))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "SET IDENTITY_INSERT [dbo].[YourTable] ON;";
//Migration steps here...
cmd.CommandText += "SET IDENTITY_INSERT [dbo].[YourTable] OFF;";
}
EDIT:
The below is actually incorrect! I overlooked that IDENTITY_INSERT can only be set for a SINGLE table per SESSION. See MS documentation
As per a the commented suggestion by #benjamin moskovits to use the undocumented sp_msforeachtable, while this would work to SET IDENTITY_INSERT for each table in your database, this approach is nevertheless a bit of a sledgehammer which may have unintended consequences depending on the specifics of your migration pattern.
exec sp_msforeachtable 'SET IDENTITY_INSERT ? ON;'
If you want to do something to each table in a database you can use the 'unsupported' but very widely used and available in almost every version of SQL Server, sp_msforeachtable to execute something....
exec sp_msforeachtable 'select count(*) ''?'' from ?'
will give you a list of every table in a database and the number of rows it contains.

sql server trigger to update another database whenever a sproc is created

Is there a way to update another database with the newly created stored procedure whenever a stored procedure is created in the main database?
For example, i have two databases, DB1 and DB2.
When I create a stored procedure in DB1, i want that same procedure to created in DB2 automatically? Is there a trigger that can do this?
USE [DB1]
CREATE PROCEDURE [dbo].[TestSproc]
..something
AS
BEGIN
...something
END
I know a use [DB2] statement will do the job, but i want this to be done automatically. Any thought?
Thanks for the help!
This might be a bit evil, but in SQL Server you are able to create DDL triggers which fire when you create/alter/drop tables/procedures etc. The syntax to fire when a procedure is created is:
CREATE TRIGGER <proc-name>
ON DATABASE
FOR CREATE_PROCEDURE
AS
--Your code goes here
In a DDL trigger you get access to an object called EVENTDATA. So to get the text of the procedure you created:
SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
Now all you need to do is keep that value and execute it in your secondary database. So your query becomes something like this, though I leave the code to update the secondary database down to you as I don't know if it's on the same server, linked server etc.:
CREATE TRIGGER sproc_copy
ON DATABASE
FOR CREATE_PROCEDURE
AS
DECLARE #procedureDDL AS NVARCHAR(MAX) = EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')
--Do something with #procedureDDL
As this is not tested, there's probably a few gotchas. For example, what happens if you create procedure with full name (CREATE PROC server.database.schema.proc)
No simple solution for this unless you want to execute the same statement twice, once on each target database,
One thing that comes to my mind is that you can Set up Replication and only publish Stored Procedures to your second database which will be the subscriber in this case.
Following is the window where you select which Objects you want to send over to your secondary databases.

How to update SQL Batch?

In my client place they have a database. Once I complete the incremental changes on database, I have prepare the list of SQL object changes in one SQL file.
The script is like this:
If sql object 1 present in database
DROP the SQL object 1
GO
create the SQL Object 1
If sql object 2 present in database
DROP the SQL object 2
create the SQL Object 2
All the time I have drop the existing Object and re-create the same.
Now this batch may contains some error.
My requirement is that if there any error in file the file. non of the the sql objects has been re-created. it should rollback the old sql objects.
If there is no error then it would create all the SQL objects.
Due the GO statement in middle I could not able to user the TRANSACTION in sql.
How can this be solved?
Don't use GO, then. Simply remove it from your script, and add your BEGIN and COMMIT TRANSACTION commands where you need them.
BEGIN TRAN
IF EXISTS Object1
BEGIN
DROP Object1;
END
CREATE Object1;
IF EXISTS Object2
BEGIN
DROP Object2;
END
CREATE Object2;
COMMIT TRAN
Modifying database schema via DROP/CREATE has many problems:
it may loose data
it looses permissions and extended properties added to the objects dropped
cross object dependencies (eg. foreign keys) require a certain order of drop/create
Usually is better to try to ALTER the object from schema version to schema version. This requires you to know which schema version is currently deployed, but that problem is easily solvable (use a database extended property, see Version Control and your Database).
Back to your question, a naive approach is to wrap your entire script in a big BEGIN TRAN/COMMIT but that seldom works:
it creates a potentially large transaction that requires much log space.
the result is impossible to validate until after the commit when is too late to do anything about it
the behavior mingling exceptions and transactions is messy at best. XACT_ABORT ON helps somehow, but only so much.
Not all DLL statements can be run from inside a transaction
For these resons I would recommnd a much simpler and safer approach: take a backup, WITH COPY_ONLY, of the database before modifying the schema. If anything goes wrong, rollback to the copy. Alternative, a database snapshot can be used as a backup. See How to: Revert a Database to a Database Snapshot.
Note that BEGIN TRAN/COMMIT can span batches (ie. can be separated by multiple GO) so your concern is not an issue.

DROP...CREATE vs ALTER

When it comes to creating stored procedures, views, functions, etc., is it better to do a DROP...CREATE or an ALTER on the object?
I've seen numerous "standards" documents stating to do a DROP...CREATE, but I've seen numerous comments and arguments advocating for the ALTER method.
The ALTER method preserves security, while I've heard that the DROP...CREATE method forces a recompile on the entire SP the first time it's executed instead of just a a statement level recompile.
Can someone please tell me if there are other advantages / disadvantages to using one over the other?
ALTER will also force a recompile of the entire procedure. Statement level recompile applies to statements inside procedures, eg. a single SELECT, that are recompiled because the underlying tables changes, w/o any change to the procedure. It wouldn't even be possible to selectively recompile just certain statements on ALTER procedure, in order to understand what changed in the SQL text after an ALTER procedure the server would have to ... compile it.
For all objects ALTER is always better because it preserves all security, all extended properties, all dependencies and all constraints.
This is how we do it:
if object_id('YourSP') is null
exec ('create procedure dbo.YourSP as select 1')
go
alter procedure dbo.YourSP
as
...
The code creates a "stub" stored procedure if it doesn't exist yet, otherwise it does an alter. In this way any existing permissions on the procedure are preserved, even if you execute the script repeatedly.
Starting with SQL Server 2016 SP1, you now have the option to use CREATE OR ALTER syntax for stored procedures, functions, triggers, and views. See CREATE OR ALTER – another great language enhancement in SQL Server 2016 SP1 on the SQL Server Database Engine Blog. For example:
CREATE OR ALTER PROCEDURE dbo.MyProc
AS
BEGIN
SELECT * FROM dbo.MyTable
END;
Altering is generally better. If you drop and create, you can lose the permissions associated with that object.
If you have a function/stored proc that is called very frequently from a website for example, it can cause problems.
The stored proc will be dropped for a few milliseconds/seconds, and during that time, all queries will fail.
If you do an alter, you don't have this problem.
The templates for newly created stored proc are usually this form:
IF EXISTS (SELECT * FROM sysobjects WHERE type = 'P' AND name = '<name>')
BEGIN
DROP PROCEDURE <name>
END
GO
CREATE PROCEDURE <name>
......
However, the opposite is better, imo:
If the storedproc/function/etc doesn't exist, create it with a dummy select statement. Then, the alter will always work - it will never be dropped.
We have a stored proc for that, so our stored procs/functions usually like this:
EXEC Utils.pAssureExistance 'Schema.pStoredProc'
GO
ALTER PROCECURE Schema.pStoredProc
...
and we use the same stored proc for functions:
EXEC Utils.pAssureExistance 'Schema.fFunction'
GO
ALTER FUNCTION Schema.fFunction
...
In Utils.pAssureExistance we do a IF and look at the first character after the ".": If it's a "f", we create a dummy fonction, if it's "p", we create a dummy stored proc.
Be careful though, if you create a dummy scalar function, and your ALTER is on a table-valued function, the ALTER FUNCTION will fail, saying it's not compatible.
Again, Utils.pAssureExistance can be handy, with an additional optional parameter
EXEC Utils.pAssureExistance 'Schema.fFunction', 'TableValuedFunction'
will create a dummy table-valued function,
Additionaly, I might be wrong, but I think if you do a drop procedure and a query is currently using the stored proc, it will fail.
However, an alter procedure will wait for all queries to stop using the stored proc, and then alter it. If the queries are "locking" the stored proc for too long (say a couple seconds), the ALTER will stop waiting for the lock, and alter the stored proc anyway: the queries using the stored proc will probably fail at that point.
DROP generally loses permissions AND any extended properties.
On some UDFs, ALTER will also lose extended properties (definitely on SQL Server 2005 multi-statement table-valued functions).
I typically do not DROP and CREATE unless I'm also recreating those things (or know I want to lose them).
I don't know if it's possible to make such blanket comment and say "ALTER is better". I think it all depends on the situation. If you require this sort of granular permissioning down to the procedure level, you probably should handle this in a separate procedure. There are benefits to having to drop and recreate. It cleans out existing security and resets it what's predictable.
I've always preferred using drop/recreate. I've also found it easier to store them in source control. Instead of doing .... if exists do alter and if not exists do create.
With that said... if you know what you're doing... I don't think it matters too much.
If you perform a DROP, and then use a CREATE, you have almost the
same effect as using an ALTER VIEW statement. The problem is that you need to entirely re-establish your permissions on who can and can’t use the view. ALTER retains any dependency information and set permissions.
You've asked a question specifically relating to DB objects that do not contain any data, and theoretically should not be changed that often.
Its likely you may need to edit these objects but not every 5 minutes. Because of this I think you've already hit the hammer on the head - permissions.
Short answer, not really an issue, so long as permissions are not an issue
We used to use alter while we were working in development either creating new functionality or modifying the functionality. When we were done with our development and testing we would then do a drop and create. This modifys the date/time stamp on the procs so you can sort them by date/time.
It also allowed us to see what was bundeled by date for each deliverable we sent out.
Add with a drop if exists is better because if you have multiple environments when you move the script to QA or test or prod you don't know if the script already exists in that environment. By adding an drop (if it already exists) and and then add you will be covered regardless if it exists or not. You then have to reapply permissions but its better then hearing your install script error-ed out.
From a usability point of view a drop and create is better than a alter. Alter will fail in a database that doesn't contain that object, but having an IF EXISTS DROP and then a CREATE will work in a database with the object already in existence or in a database where the object doesn't exist. In Oracle and PostgreSQL you normally create functions and procedures with the statement CREATE OR REPLACE that does the same as a SQL SERVER IF EXISTS DROP and then a CREATE. It would be nice if SQL Server picked up this small but very handy syntax.
This is how I would do it. Put all this in one script for a given object.
IF EXISTS ( SELECT 1
FROM information_schema.routines
WHERE routine_schema = 'dbo'
AND routine_name = '<PROCNAME'
AND routine_type = 'PROCEDURE' )
BEGIN
DROP PROCEDURE <PROCNAME>
END
GO
CREATE PROCEDURE <PROCNAME>
AS
BEGIN
END
GO
GRANT EXECUTE ON <PROCNAME> TO <ROLE>
GO