Execute section of SQL based on presense of a linked server - sql

I'm trying to write a query that can run on different servers. One way I'm trying to detect which server i'm on is the presense of a certain linked server (i.e. Server1 will have a link to Server2 and vice versa).
Trouble is, I can't get SQL Server to ignore/skip the code that runs on the non-existant linked server. There are two nearly identical sections of code, one which uses the Linked Server1 and one which does not (because it's running on Server1 already).
drop table #origdates
if exists(select 1 from sys.servers where name = N'Server1')
BEGIN
Select * into #origdates from openquery([Server1],'Select accounts, dates from table1')
END
if not exists(select 1 from sys.servers where name = N'Server1')
BEGIN
Select accounts, dates into #origdates from table1
END
If I execute the individual sections, everything is fine; the code either executes or not as specified, but the moment I run the entire thing together it's as if the server ignores the if exists section, with an error like:
Could not find server 'Server1' in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.
The reason I'm doing this is so I don't have to maintain two identical scripts with two separate begginning sections.
Using ELSE in place of the second if not exists line results in the server complaining that the #origdates table already exists, even if a drop table command is issued right before the line of the select into command.
Using different table names returns the error to the 'Could not find server' message, despite that it's not even supposed to be executing that code at all...

Try this, SQL is trying to validate the OPENQUERY, but it can't because [Server1] is not a valid linked server. Hiding the OPENQUERY in a variable should fix it.
Note, you need to pass FROM db.owner.table in an OPENQUERY, not just FROM table
declare #sql nvarchar(max)
if object_id('tempdb..#origdates') is not null
drop table #origdates
create table #origdates (accounts int, dates datetime)
if exists(select 1 from sys.servers where name = N'Server1')
BEGIN
set #sql='insert into #origdates Select * from openquery([Server1],''select accounts, dates from db.dbo.table1'')'
exec(#sql)
END
else
BEGIN
insert into #origdates Select accounts, dates from table1
END

Related

Passing temp table from one execution to another

I want to pass a temp table from one execution path to another one nested in side it
What I have tried is this:
DECLARE #SQLQuery AS NVARCHAR(MAX)
SET #SQLQuery = '
--populate #tempTable with values
EXECUTE('SELECT TOP (100) * FROM ' + tempdb..#tempTable)
EXECUTE sp_executesql #SQLQuery
but it fails with this error message:
Incorrect syntax near 'tempdb'
Is there a another\better way to pass temporary table between execution contexts?
You can create a global temp table using the ##tablename syntax (double hash). The difference is explained on the TechNet site:
There are two types of temporary tables: local and global. They differ from each other in their names, their visibility, and their availability. Local temporary tables have a single number sign (#) as the first character of their names; they are visible only to the current connection for the user, and they are deleted when the user disconnects from the instance of SQL Server. Global temporary tables have two number signs (##) as the first characters of their names; they are visible to any user after they are created, and they are deleted when all users referencing the table disconnect from the instance of SQL Server.
For example, if you create the table employees, the table can be used by any person who has the security permissions in the database to use it, until the table is deleted. If a database session creates the local temporary table #employees, only the session can work with the table, and it is deleted when the session disconnects. If you create the global temporary table ##employees, any user in the database can work with this table. If no other user works with this table after you create it, the table is deleted when you disconnect. If another user works with the table after you create it, SQL Server deletes it after you disconnect and after all other sessions are no longer actively using it.
If a temporary table is created with a named constraint and the temporary table is created within the scope of a user-defined transaction, only one user at a time can execute the statement that creates the temp table. For example, if a stored procedure creates a temporary table with a named primary key constraint, the stored procedure cannot be executed simultaneously by multiple users.
The next suggestion may be even more helpful:
Many uses of temporary tables can be replaced with variables that have the table data type. For more information about using table variables, see table (Transact-SQL).
Your temp table will be visible inside the dynamic sql with no problem. I am not sure if you are creating the temp table inside the dynamic sql or before.
Here it is with the table created BEFORE the dynamic sql.
create table #Temp(SomeValue varchar(10))
insert #Temp select 'made it'
exec sp_executesql N'select * from #Temp'
The reason for your syntax error is that you are doing an unnecessary EXECUTE inside an EXECUTE, and you didn't escape the nested single-quote. This would be the correct way to write it:
SET #SQLQuery='
--populate #tempTable with values
SELECT TOP 100 * FROM tempdb..#tempTable'
However, I have a feeling that the syntax error is only the beginning of your problems. Impossible to tell what you're ultimately trying to do here, only seeing this much of the code, though.
Your quotations are messed up. Try:
SET #SQLQuery='
--populate #tempTable with values
EXECUTE(''SELECT TOP 100 * FROM '' + tempdb..#tempTable + '') '

How to execute sql query when debugging a stored procedure

I'm debugging a stored procedure on SQL Server 2008 and I have this:
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
How can I view the data into #tempTable on Debug time?
In SQL Server Management Studio, you can't execute query directly while debugging stored procedure, and that's still not implemented(I think). You can only view the local variables value in Local Debug Window.
There are some work around to see temp table values while in Debugging mode:-
1) In the stored procedure, after insert data into #temptable, add this line of code to get temptable values in xml table varriable where you want to see temptable values. Then you can check the values in Local Debug window in xml format
--inserting data into temp table
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
--to see records of temp table
DECLARE #temptable XML
SET #temptable = (SELECT * FROM ##temptable FOR XML AUTO)
2) You can convert local temp table(#temptable) to global temptable(##temptable), so when you insert date in temp table, you can open new query window, and able to see global temp table records using select query.
This blog post describes how to access a temporary table from another session:
http://web.archive.org/web/20180409190701/http://sqlblog.com:80/blogs/paul_white/archive/2010/08/14/viewing-another-session-s-temporary-table.aspx
Alternative you can use two ## in the table name to make the table globally accessible from other sessions: ##tempTable (The table might be locked for reading while your insert is running)
Even though SQL Server Management Studio has some debugging functions , but I find them pretty useless.
I don't think there are any debugging tools out there for SQL Server like Visual Studio, which will give you a step by step information at runtime.
The way normally developers debug sql server code is to use print statement, for stored procedures take the sp definition out declare a variable for each parameter that procedure expects , hardcode the values for variables and execute smaller logical blocks of code to see what's going on where.

Running scripts - Check if a SQL Server 2008 database exists and replace if not (USE Database)

Running scripts - check if a SQL Server 2008 database exists and replace if not (USE Database)
I run a script on lots of servers. However some database names are not always the same hence we have to edit 'use database'
if DB_ID('sports') is not null -- check to see if exists
use sports
else
use SportsLive`-- use the correct one
Always one is not going to exist...
Msg 911, Level 16, State 1, Line 15
Database 'SportsLive' does not exist. Make sure that the name is entered correctly.
Any way around this?
use[xxx] must be at beginning of the code so
if you what to use this query
you need to put the rest of the code together
with the 'use[xxx]...' like in the example
DECLARE #i nvarchar(50)
DECLARE #a nvarchar(50)
SET #i =DB_NAME(coalesce((db_id('sports')),(db_id('SportsLive'))))
SELECT #i
SET #a= 'USE ['+#i+']
select * from [your table]'
EXEC (#a)

Stored procedure parameters with literals not working in SQL Server 2008 R2

I have a stored procedure that takes two parameters as varchar(50). The stored procedure does a few simple queries into a temp table and the returns the result set from the temp table (I removed the actual queries)
ALTER PROCEDURE [dbo].[cv_GetBooks]
#bookNumber as varchar(50),
#bookDate as varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--a few select statements
if #ismultiple = '0'
begin
select * from books where bookNumber = #bookNumber
and bookDate = #bookDate
and Bookname is not null
end
ELSE
Begin
select * into #temp from books
where bookNumber = #bookNumber
and bookDate = #bookDate
and Bookname is null
select * from books
where bookauthor not in (select bookauthor from #temp)
and bookNumber= #bookNumber
and bookDate= #bookDate
drop table #temp
end
END
I have this query installed on my local development machine on SQL Server 2008. I have also installed it on a two test machines running Windows Server 2003 and SQL Server 2008. The stored procedure has been working as expected.
cv_GetBooks '012345678', '06062012' --returns result set as expected
I recently moved it to a test server in another remote environment that is running Windows server 2008 and SQL Server 2008 R2. The stored procedure no longer works as expected. After running SQL Profiler I have confirmed that the same code is being executed:
cv_GetBooks '012345678', '06062012' --run on SQL server 2008 r2 returns nothing
When I removed the quotes from the query I got the expected result:
cv_GetBooks 012345678, 06062012 --run with out quotes server returns expected result set
I have since installed the same stored procedure on local version of SQL Server 2008 R2 and everything is running as expected, with the literal string quotes in place, as in the first example.
At first I thought it was an escape issue with the passed parameters but that doesn't seem correct because the passed values are do not contain any single quotes.
Having installed and had it working on so many environments, I am under the impression that this is maybe a setting in SQL Server that I am unaware of.
What could be causing the stored procedure to not return the result set with the string literals in place on the SQL Server 2008 r2 instance, but work correctly with out them there?
You did not post the table definition of table Books, but
cv_GetBooks '012345678', '06062012'
--run on SQL server 2008 r2 returns nothing
cv_GetBooks 012345678, 06062012
--run with out quotes server returns expected result set
could be caused if BookNumber and BookDate were numeric rather than varchar:
Leading zero in ints is dropped, and when converted to varchar the resulting string does not contain the leading zero.
It's also not clear how the data in your table affects the execution (IF statement!) in your code.
This might not be the exact answer, but try this as a way to finding out more about the problem. Run some basic queries (not the whole proc) in SSMS, with the parameters in place, such as:
(I'm not sure where #ismultiple comes from - doesn't seem to be declared or parameterised?)
select *
from books
where bookNumber = '012345678'
and bookDate = '06062012'
and Bookname is null
and
select *
from books
where bookNumber = 012345678
and bookDate = 06062012
and Bookname is null
Do you get the same results? What results do you get?
My suspicion is the data types: Somewhere something is being converted, and therefore not working in one environment but working in another (where the data type is different or the SQL version doesn't convert automatically). EG: 012345678 could be being converted to 12345678 if the data is stored in the table as a numeric data type. But try and isolate the behaviour without the stored procedure and/or the temp table, that might help narrow the possible causes down...

Why does Microsoft SQL Server check columns but not tables in stored procs?

Microsoft SQL Server seems to check column name validity, but not table name validity when defining stored procedures. If it detects that a referenced table name exists currently, it validates the column names in a statement against the columns in that table. So, for example, this will run OK:
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
Col1, Col2, Col3
FROM
NonExistentTable
END
GO
... as will this:
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
ExistentCol1, ExistentCol2, ExistentCol3
FROM
ExistentTable
END
GO
... but this fails, with 'Invalid column name':
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
NonExistentCol1, NonExistentCol2, NonExistentCol3
FROM
ExistentTable
END
GO
Why does SQL Server check columns, but not tables, for existence? Surely it's inconsistent; it should do both, or neither. It's useful for us to be able to define SPs which may refer to tables AND/OR columns which don't exist in the schema yet, so is there a way to turn off SQL Server's checking of column existence in tables which currently exist?
This is called deferred name resolution.
There is no way of turning it off. You can use dynamic SQL or (a nasty hack!) add a reference to a non existent table so that compilation of that statement is deferred.
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
CREATE TABLE #Dummy (c int)
SELECT
NonExistantCol1, NonExistantCol2, NonExistantCol3
FROM
ExistantTable
WHERE NOT EXISTS(SELECT * FROM #Dummy)
DROP TABLE #Dummy
END
GO
This article in MSDN should answer your question.
From the article:
When a stored procedure is executed for the first time, the query
processor reads the text of the stored procedure from the
sys.sql_modules catalog view and checks that the names of the objects
used by the procedure are present. This process is called deferred
name resolution because table objects referenced by the stored
procedure need not exist when the stored procedure is created, but
only when it is executed.