I do not think that there is a way to conditionally prepare only part of the t-sql statement (at least not in the way you requested).
The main problem with the original query is not that the remote database is sometimes disconnected, that the query optimizer cannot create an execution plan when the remote database is offline. In this sense, an autonomous database is essentially a syntax error, that is, a condition that prevents the creation of a query plan, so all this error fails before it ever gets the opportunity to execute.
The reason EXECUTE
works for you is because it delays the compilation of the request sent to it until the request completes, which calls it, which means that you have potentially two query plans, one for your main request, which checks to see if the remote is available db, and another that is not created until and until the EXECUTE
statement is executed.
Therefore, when you think about it, using EXECUTE
(or, alternatively, sp_executesql
) is not so much a workaround as one possible solution. This is just a mechanism for splitting your request into two separate execution plans.
Given this, you do not have to use dynamic SQL to solve your problem. You can use a second stored procedure to achieve the same result. For instance:
-- create this sp (when the remote db is online, of course) CREATE PROCEDURE usp_CopyRemoteData AS BEGIN INSERT INTO _LOCALTABLE (A, B) SELECT A, B FROM _LINKEDSERVER._DATABASENAME.dbo._REMOTETABLE; END GO
Then your original request looks like this:
IF EXISTS( SELECT * FROM OPENQUERY(_LINKEDSERVER,' SELECT name, state FROM sys.databases WHERE name = ''_DATABASENAME'' AND state = 0') ) BEGIN exec usp_CopyRemoteData; END
Another solution would not even be to check if the remote database is accessible, just try to run the INSERT INTO _LOCALTABLE
and ignore the error if it fails. I'm a little addicted here, but if there is no ELSE
for your IF EXISTS
, i.e. Unless you do something else when the remote db is offline, you simply suppress (or ignore) the error anyway. The functional result is the same as the data is not copied to the local table.
You can do this in t-sql with try / catch, for example:
BEGIN TRY exec usp_CopyRemoteData; END TRY BEGIN CATCH END CATCH
To be fair, this would suppress all errors caused by sp, and not just those that were caused by the remote database offline. And you still have the same root problem as the original query, and to store the false error, you need to store the stored proc or dynamic SQL. BOL has a pretty good example of this; see the section โErrors not affected by the TRY ... CATCH Construct sectionโ of this page: http://technet.microsoft.com/en-us/library/ms175976(v=sql.105).aspx
The bottom line is that you need to split the original request into separate batches, and there are many ways to do this. The best solution depends on your specific environment and requirements, but if your actual request is as simple as the one presented in this question, then your original solution is probably a good solution.