Neater way of dynamically selecting a database other than sp_executesql - sql-server

I am looking to set up a high availability architecture whereby two mirror databases exist (DB1 & DB2) that serve another database with views (DBV) on it. DB1 has the overnight ETL on it, whilst DBV looks at DB2 until the etl is complete on DB1, at which point its views switch to the underlying tables on DB1. Once the ETL is complete on DB1, DB2 is restored with DB1 data before the next day's ETL. The next day, DB1 and DB2 switch roles.
I am looking for a neater/more secure way of switching between the two views than running sp_executesql to run a dynamically built string. I will be looking to also do this on stored procedures from a staging database which need to have their scripts dynamically altered to use the correct database to run the ETL on. Essentially, I am looking to pass the USE statement dynamically and then execute the rest of the script outside of any dynamic statement.
I want to avoid sp_executesql for support reasons for other developers and also to get around any possible extensive concatenation of strings if the stored procedure/view gets particularly lengthy.
Any ideas / different approaches to high availability in this context would be welcome.

One option might be to create a copy of each view in DBV for both target databases - i.e.
some_schema.DB1_myview
some_schema.DB2_myview
and then use a synonym to expose the views under their final names.
CREATE SYNONYM some_schema.myview ON some_schema.DB1_myview
Your switch process would then need only to drop and recreate the synonyms, rather than the views themselves. This would still need to be done with a dynamic SQL statement, but the complexity would be much lower.
A downside would be that there would be a risk of the definitions of the underlying views getting out of sync.
Edit
At the cost of more risk of getting out of sync, it would be possible to avoid dynamic SQL altogether by creating (for instance) a pair of stored procedures each of which generated the synonyms for one database or the other. Your switch code would then only need to work out which procedure to call.

Have you considered renaming the databases as you switch things around? I.e. the following prints 1 followed by 2, nothing in DBV had to be modified:
create database DB1
go
use DB1
go
create table T (ID int not null);
insert into T(ID) values (1);
go
create database DB2
go
use DB2
go
create table T (ID int not null);
insert into T(ID) values (2);
go
create database DBV
go
use DBV
go
create view V
as
select ID
from DB1..T
go
select * from V
go
alter database DB1 modify name = DBt
go
alter database DB2 modify name = DB1
go
alter database DBt modify name = DB2
go
select * from V
Obviously better names than 1 and 2 may be used. This way, DB1 is always the one used for live and DB2 is used for any staging work.

Related

Way to get the CREATE statement of global temporary table?

I have stored procedures I need to rewrite that used global temporary tables but now must use local temporary tables so that there is no cross over between users/the prod and dev db which are on the same SQL Server instances or any other new databases this database will be share the instance with.
I have to convert a lot of code that is like this
EXEC sp_executesql
N'SELECT manyDynamicallyCreatedColumns INTO ##someTempTable
I now for this to work for local tables I must instead create the table first and then INSERT INTO like
CREATE TABLE #tempTable (manyColumns);
EXEC sp_executesql
N'INSERT INTO #tempTable SELECT manyColumns FROM somewhere'
The issue I face is that this stored procedure has 8 different scenarios that lead to the global temp table. The select statement of the SQL is dynamically generated via a number of other queries. I think what would be the easiest way for me to figure out what my CREATE TABLE #tempTable should look like is if I could print/select what global temporary table looks like after it is made, for each of these 8 scenarios. Then I would just need a If/Else If statement that creates the local table appropriately before proceeding. But I don't know how or if this is possible.
For real tables I can right click -> Script to...-> Create. I don't know if there is an analogous way to do this via scripting that works for global temporary tables. Is there?

How to create a table that exist temporarily and that is accessible from many stored procedures?

I query my database from within a .NET application (time recoding). I send the Windows user name to the database and query it depending on this information.
I query a lot of different information with stored procedures, such as holiday, overtime etc. and send them back to the .NET application where I show this data in one form.
Let's say I need the information from SP1, 3 and 4 on Form1:
FORM1:
SP1
SP3
SP4
My problem:
I have a quite complicated table that I need for these stored procedures. At the moment I create this table in every of those stored procedures as temporary tables what is obviously quite time consuming.
What I have tried so far is creating a stored procedure that creates a temp table but this one is not accessable within my other stored procedures.
My question: I am looking for a way to create this table for Form1 once, so I can just access these table in the other stored procedures.
I'm using SQL Server 2014 Express.
If you create the temporary table outside of any stored procedure, it will be accessible within each. Assuming that the actual table definition isn't too complex (but populating it may be), this may be doable.
So you'd execute (effectively):
CREATE TABLE #T (A int not null, B varchar(17) not null)
EXEC PopulateTempTable
EXEC SP1
EXEC SP3
EXEC SP4
All on a single connection. PopulateTempTable may or may not be required, depending on how complex the population of the table is and whether you want that to be performed by your calling code or the database.
You cannot create the temp table inside of a stored procedure since temp tables are automatically dropped when the scope of a stored procedure is exited.
Alternatively, you may want to simulate "session-global" temp tables, as I suggest in this answer1.
The risk with using a global temp table is that it is truly global - all sessions see and interact with the data in the same table. You have to be very careful in such circumstances if it's at all possible that two sessions will attempt to use it at the same time; You generally need some means to filter the data in the table so that each session only works with its own data.
1Probably enhanced these days by also adding a Logon Trigger to clear down the old contents of the table whenever a new connection is established.
You have to create global temp table
CREATE TABLE ##TEMP1
(
Name varchar(50)
)

Database name as variable

I have a database with stored procedures which selects data from another database
select * from Users in AnotherDatabase.dbo.Users
I have a couple of versions of the other database, i.e.
AnotherDatabaseProduction, AnotherDatabaseDevelopment, AnotherDatabaseStage
I remember a while back that I created some kind of global variable like AnotherDatabase_Pointer which I could set by running some stored procedure like SetAnotherDatabaseToStage:
AnotherDatabase_Pointer = 'AnotherDatabaseStage' //pseudo-code
Which I could then use in my stored procedures.
But I cannot seem to remember how it was done. All I can find is how to do this with string replacing/concatenating: variable database name :(
Is this possible? MS SQL.
You are probably thinking of a Synonym.
CREATE SYNONYM dbo.whatever FOR dbname.dbo.procedure_name;
Now, if you want to change it to some other database, you just drop and re-create the synonym:
DROP SYNONYM dbo.whatever;
GO
CREATE SYNONYM dbo.whatever FOR other_dbname.dbo.procedure_name;

SQL Server equivalent of MySQL Dump to produce insert statements for all data in a table

I have an application that uses a SQL Server database with several instances of the database...test, prod, etc... I am making some application changes and one of the changes involves changing a column from a nvarchar(max) to a nvarchar(200) so that I can add a unique constraint on it. SQL Server tells me that this requires dropping the table and recreating it.
I want to put together a script that will do the table drop, recreate it with the new schema, and then reinsert the data that was there previously all in one go, if possible, just to keep things simple for use when I migrate this change to production.
There is probably a good SQL Server way to do this but I'm just not aware of it. If I was using Mysql I would mysqldump the table and its contents, and use that as my script for applying that change to production. I can't find any export functionality in SQL server that will give me a text file consisting of inserts for all data in a table.
Use SQL Server's Generate Scripts command
right click on the database; Tasks -> Generate Scripts
select your tables, click Next
click the Advanced button
find Types of data to script - choose Schema and Data.
you can then choose to save to file, or put in new query window.
results in INSERT statements for all table data selected in bullet 2.
No need to script
here are two ways
1 use alter table ....alter column.....
example..you have to do 1 column at a time
create table Test(SomeColumn nvarchar(max))
go
alter table Test alter column SomeColumn nvarchar(200)
go
2 dump into a new table while converting the column
select <columns except for the columns you want to change>,
convert(nvarchar(200),YourColumn) as YourColumn
into SomeNewTable
from OldTable
drop old table
rename this table to the same table as the old table
EXEC sp_rename 'SomeNewTable', 'OldTable';
Now add your index

Database name while referencing tables - Sybase

How do I get away with hardcoding the database name in referencing a table within a stored procedure. For example there are two databases db1 and db2. I am writing a stored procedure in db2 which references two tables, one from db1 and another from db2. Both are on the same sybase server.
If I understand your question correctly, on the one hand, in your stored procedure you can refer to the table in the same database directly by name
SELECT ...
FROM table_in_db2
You can refer to a table in database db1 by prefixing the database name and an empty owner:
SELECT ...
FROM db1..table_in_db1
On the other hand, if you want to avoid hard-coding database names in the procedure you might create a view in database db2 that references the db1 table:
CREATE VIEW view_in_db2
AS
SELECT *
FROM db1..table_in_db1
and use that in the procedure:
SELECT ...
FROM view_in_db2
You need to keep the code portable, involve 2 databases, but avoid referencing databases by name. Then you can create proxy tables (or proxy views, if such views exist in 12.5). Refer to proxy tables as to local objects.
This will work, but will require some extra care, every time you move/change databases. But anyway the separation of concerns you are after can be achieved.

Resources