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

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.

Related

How to alter table add column then update within single script?

We have a custom database updater which runs various SQL scripts on SQL Server. Some of the scripts need to add a new column to a table, then populate the values, in a single script, within a transaction:
using (var scope = new TransactionScope()) {
... alter table MyTable add FOOBAR int;
... update schappointment set FOOBAR = 1;
}
Problem is, SQL spits back "Invalid column name 'FOOBAR' because the "alter table" command hasn't taken effect. Wrapping it in exec() makes no difference:
... exec('alter table MyTable add FOOBAR int;')
... update schappointment set FOOBAR = 1;
It works OK within SQL Management Studio because it splits it up with GO commands (which I know are not valid T-SQL commands).
I'd prefer not to create any new dependencies in the project.
My preference is not to split the schema & data scripts as this doubles the number of scripts for no reason other than to make SQL happy.
How can I solve this?
You can't do this exactly in a single statement (or batch) and it seems the tool you are using does not support GO as a batch delimiter.
You can use EXEC to run it in a child batch though.
ALTER TABLE A
ADD c1 INT, c2 VARCHAR(10);
EXEC('
UPDATE A
SET c1 = 23,
c2 = ''ZZXX'';
');
NB: All single quotes in the query need to be doubled up as above to escape them inside a string literal.
I tried this approach this is working.
alter table then update in single statement
Our solution was to sprinkle "GO" commands throughout the scripts, and customize our script execution function to split them up and run them seperately.
This mimics what SQL management studio does and seems to work.

Script for creating database if it doesn't exist yet in SQL Azure

This question may related to Checking if database exists or not in SQL Azure.
In SQL Azure, I tried to use a script like this to check the existence of a database, and create the database if it doesn't exist yet (in both SQLCmd and SSMS):
IF db_id('databasename') IS NULL CREATE DATABASE databasename
GO
However, SQL Azure keeps telling me
Msg 40530, Level 16, State 1, Line 2
The CREATE DATABASE statement must be the only statement in the batch.
While the same script did work on a local SQL express instance.
Does this mean it is not supported on SQL Azure?
Or is there any work around?
Thanks in advance.
Eidt:
Let me clarify what I want to achieve:
I want a script which will create a certain database only if it doesn't exist before.
Is it possible to have such kind of script for SQL Azure?
We have a similar problem.
It looks like we can do something with SET NOEXEC ON, as in the following StackExchange answer.
IF (<condition>)
SET NOEXEC ON
ELSE
SET NOEXEC OFF
GO
CREATE DATABASE databasename
GO
SET NOEXEC OFF
GO
It's saying you can't do theck and create in the same piece of sql.
i.e you need to do Select IF db_id('databasename')
test the whether it returns null, and if so then execute the create database.

sp_generate_inserts for all the tables? or something similar

I have two databases.
Database A - full of data
Database B - backup of database A, but without data
how can I get all data from database A and just merge it into database B?
My thoughts were to just generate an insert of the whole data or something.
Thanks
Take a look at redgate's SQL Data Compare.
OP said:
database is full of triggers and
constraints
Just restore a complete backup of A as a new database and be done with it. Lots of "one off" inserts created by a script will take forever, play havoc with your transaction log, and most likely fail because of FKs, etc.
That would work if you're trying to do something ongoing, but if you want to do it just once and you have SQL Server Management Studio installed, you can have it do the Export/Import for you. Here's a walk-though with some screenshots:
http://www.databasejournal.com/features/mssql/article.php/3580216/SQL-Server-2005-Import--Export-Wizard.htm
If you don't have any identity fields to worry about, and it's a one-time operation, you can do something like this, which uses sp_msforeachtable and dynamic SQL:
DECLARE #SQL varchar(max)
SET #SQL = '
INSERT INTO DatabaseB.? WITH (TABLOCK)
SELECT *
FROM DatabaseA.?'
exec sp_MSforeachtable #SQL

DataTable identity column not set after DataAdapter.Update/Refresh on table with "instead of"-trigger (SqlServer 2005)

Within our unit tests we use plain ADO.NET (DataTable, DataAdapter) for preparing the database resp. checking the results, while the tested components themselves run under NHibernate 2.1. .NET version is 3.5, SqlServer version is 2005.
The database tables have identity columns as primary keys. Some tables apply instead-of-insert/update triggers (this is due to backward compatibility, nothing I can change). The triggers generally work like this:
create trigger dbo.emp_insert
on dbo.emp
instead of insert
as
begin
set nocount on
insert into emp ...
select ##identity
end
The insert statement issued by the ADO.NET DataAdapter (generated on-the-fly by a thin ADO.NET wrapper) tries to retrieve the identity value back into the DataRow:
exec sp_executesql N'
insert into emp (...) values (...);
select id, ... from emp where id = ##identity
'
But the DataRow's id-Column is still 0. When I remove the trigger temporarily, it works fine - the id-Column then holds the identity value set by the database.
NHibernate on the other hand uses this kind of insert statement:
exec sp_executesql N'
insert into emp (...) values (...);
select scope_identity()
'
This works, the NHibernate POCO has its id property correctly set right after flushing. Which seems a little bit counter-intuitive to me, as I expected the trigger to run in a different scope, hence ##identity should be a better fit than scope_identity().
So I thought no problem, I will apply scope_identity() instead of ##identity under ADO.NET as well. But this has no effect, the DataRow value is still not updated accordingly.
And now for the best part: When I copy and paste those two statements from SqlServer profiler into a Management Studio query (that is including "exec sp_executesql"), and run them there, the results seem to be inverse! There the ADO.NET version works, and the NHibernate version doesn't (select scope_identity() returns null). I tried several times to verify, but to no avail. Well, actually that was what I would have expected - ##identity to be OK, and scope_identity() to fail.
Of course invoking it in Management Studio just shows the resultset coming from the database, whatever happens inside NHibernate and ADO.NET is another topic. Also, several session properties defined by T-SQL SET are different in the two scenarios (Management Studio query vs. application at runtime)
This is a real puzzle to me. I would be happy about any insights on that. Thank you!
Found it. The identity value actually was transmitted into the DataTable, just not in the column I expected. Instead of using existing column "id", ADO.NET created a new column "Column1".
Reason is this line at the end of the instead-of trigger:
select ##identity
Unfortunately, NHibernate seems to require "select ##identity" at the end of instead-of triggers (this was mentioned in a Hibernate forum posting, and I verified it again now - it is indeed necessary). But I can go along from here (adapting NHibernate dialect is one possibility)...

Simulate a table creation with 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.