Getting server name who is executing query in a linked Server - sql-server

In SQL Server, I have a server A and I linked a server B to A, so from server A I can execute query like :
exec B.DataBase1.dbo.simplePs.
My question is how can I get the server who is executing the PS? I tried ##ServerName like this :
Create procedure simplePs
as
insert into TRACE(EventInfo) values (##SERVERNAME)
but I get server B not server A.
Please help.

You could try querying the sys.sysprocesses table - there's lots of useful connection information there e.g.
insert into TRACE(EventInfo)
values (select distinct hostname from sys.sysprocesses where spid = ##SPID)
will insert the source hostname of the connection.

You don't have such context information, for the server B,
the query is executed on its own instance/database.
The best you could do, is to pass the source server as a parameter in the procedure with ##SERVERNAME as default value.
Create procedure simplePs
#sourceServer as nvarchar(255) = ##SERVERNAME
as
insert into TRACE(EventInfo) values (#sourceServer)

Related

Running SQL Server query in Remote Server

I have three SQL Servers A, B and C. I am trying to run a same query like select ##servername from A server and run the same query in B and C from Server A. I am loading this results in a server A table. Please let me know how to accomplish this one.
You could run the inserts from the two remote servers using OPENQUERY which essentially runs the select locally on the remote server to be able to use the proper local indexes etc.
insert into localTableOnA (col1,col2,...)
select col1,col2,... from [dbname].dbo.[tablename] --on ServerA
insert into localTableOnA (col1,col2,...)
select col1,col2,... from openquery([ServerB],'select col1,col2,... from [dbname].dbo.[tablename]')
insert into localTableOnA (col1,col2,...)
select col1,col2,... from openquery([ServerC],'select col1,col2,... from [dbname].dbo.[tablename]')
You can make using linked servers.
1- WITHIN A instance
INSERT INTO [DatabaseName].[SchemaName].[TableName] (...) SELECT ... FROM [B].[DatabaseName].[SchemaName].[TableName];
INSERT INTO [DatabaseName].[SchemaName].[TableName] (...) SELECT ... FROM [C].[DatabaseName].[SchemaName].[TableName];
2- WITHIN A instance (Dynamic SQL)
EXEC ('INSERT INTO [A].[DatabaseName].[SchemaName].[TableName] (...) SELECT ... FROM [DatabaseName].[SchemaName].[TableName]') AT [B];
EXEC ('INSERT INTO [A].[DatabaseName].[SchemaName].[TableName] (...) SELECT ... FROM [DatabaseName].[SchemaName].[TableName]') AT [C];
3- WITHIN Other instance
INSERT INTO [A].[DatabaseName].[SchemaName].[TableName] (...) SELECT ... FROM [DatabaseName].[SchemaName].[TableName];

Remote Call Compiles SPROC differently to local, causes error

I have a stored proc that returns details of SQL Agent Jobs on the local server. There is a master script that calls this proc, using OPENQUERY, against every SQL server in the ecosystem. In pseudocode, the master script looks something like this:
FOR EACH #LinkedServer in the list
SET #SQL = 'INSERT #Results SELECT * FROM OPENQUERY(' + #LinkedServer + ',''EXEC ScriptToGetAgentJobInfo'')'
EXEC sp_executesql #SQL
NEXT #LinkedServer
Some of the agent jobs are created from SSRS report subscriptions, so they have horrible looking names. In order to replace them with the name of the report that is the target of the subscription, I appeal to the ReportServer database on the #LinkedServer, as part of the ScriptToGetAgentJobInfo.
However, not every server contains a ReportServer database, so sometimes this appeal would fail. To get round that failure, I have the following lines of script:
DECLARE #Reports TABLE
( AgentJob SYSNAME
,Reportname NVARCHAR(128));
IF EXISTS(SELECT 1 FROM [master].[dbo].sysdatabases WHERE [name] = 'ReportServer')
BEGIN;
INSERT #Reports(AgentJob,Reportname)
SELECT Job.job_id, Report.[Name]
FROM
ReportServer.dbo.ReportSchedule AS ReportSched
INNER JOIN dbo.sysjobs AS Job ON CONVERT(SYSNAME,ReportSched.ScheduleID) = Job.[name]
INNER JOIN ReportServer.dbo.Subscriptions AS Subscription ON ReportSched.SubscriptionID = Subscription.SubscriptionID
INNER JOIN ReportServer.dbo.[Catalog] AS Report ON Subscription.report_oid = Report.itemid;
END;
The idea is that if the reportserver database doesn't exist, I can avoid any calls to it, which would error, but if it does, I can get data from it. I then join the #Reports table to my SQL Agent job query with a LEFT JOIN to show the name of the relevant report if there is one.
All this works fine when I run the script locally, but when it is called through the master procedure, I get an error saying Invalid object name 'ReportServer.dbo.ReportSchedule'.
I can get round this problem by making the reportserver select statement "dynamic" (although it is totally static) and calling it with another sp_executesql call, but I really hate doing this!
So my question is this: Why does the error only occur when calling the script remotely and how can I avoid it without recourse to dynamic sql?
The master script is written and run in SQL Server 14.0, while the linked server that is causing the problem is only on SQL Server 10.50.

Microsoft SQL Server Management Studio Select Database Syntax Error [duplicate]

It is a bit of a "chicken or egg" kind of query, but can someone dreamup a query that can return the name of the current database instance in which the query executes? Believe me when I say I understand the paradox: why do you need to know the name of the database instance if you're already connected to execute the query? Auditing in a multi-database environment.
I've looked at all the ## globals in Books Online. "SELECT ##servername" comes close, but I want the name of the database instance rather than the server.
SELECT DB_NAME()
Returns the database name.
SELECT
##servername AS 'Server Name' -- The database server's machine name
,##servicename AS 'Instance Name' -- e.g.: MSSQLSERVER
,DB_NAME() AS 'Database Name'
,HOST_NAME() AS 'Host Name' -- The database client's machine name
I'm not sure what you were exactly asking. As you are writing this procedure for an Auditing need I guess you're asking how do you get the current database name when the Stored Procedure exists in another database. e.g.
USE DATABASE1
GO
CREATE PROC spGetContext AS
SELECT DB_NAME()
GO
USE DATABASE2
GO
EXEC DATABASE1..spGetContext
/* RETURNS 'DATABASE1' not 'DATABASE2' */
This is the correct behaviour, but not always what you're looking for. To get round this you need to create the SP in the Master database and mark the procedure as a System Procedure. The method of doing this differs between SQL Server versions but here's the method for SQL Server 2005 (it is possible to do in 2000 with the master.dbo.sp_MS_upd_sysobj_category function).
USE MASTER
/* You must begin function name with sp_ */
CREATE FUNCTION sp_GetContext
AS
SELECT DB_NAME()
GO
EXEC sys.sp_MS_marksystemobject sp_GetContext
USE DATABASE2
/* Note - no need to reference master when calling SP */
EXEC sp_GetContext
/* RETURNS 'DATABASE2' */
Hope this is what you were looking for
You can use DB_NAME() :
SELECT DB_NAME()
SELECT DB_NAME() AS DatabaseName
simply use:
select ##servicename
You should be able to use:
SELECT SERVERPROPERTY ('InstanceName')
You can get the instance name of your current database as shown below:
SELECT ##SERVICENAME -- SQLEXPRESS
SELECT SERVERPROPERTY ('InstanceName') -- SQLEXPRESS

How to create SSIS package for deleting records by joining two tables of different servers without using linked servers [duplicate]

Any suggestions how to join tables from different servers in stored procedure?
Without more details, it's hard to give direct examples, but here is the basic idea:
First, outside of the stored procedure, the host server (the server the stored procedure will be on) has to know about the second server, including (possibly) login information.
On your main server, run the sp_addlinkedserver stored procedure. This only has to be done once:
exec sp_addlinkedserver #server='(your second server)';
If you need to provide login information to this second server (for example, the process can't log in with the same credentials that are used in the initial database connection), do so with the sp_addlinkedsrvlogin stored proc:
exec sp_addlinkedsrvlogin #rmtsrvname='(your second server)',
#useself=false,
#rmtuser='yourusername',
#rmtpassword='yourpassword';
Then, in your stored procedure, you can specify tables on the second server:
SELECT table1.*
FROM table1
INNER JOIN [secondserver].[database].[schema].[table] AS table2 ON
table1.joinfield = table2.joinfield
1. Check to see if you have any linked servers using exec sp_helpserver
2. If your server is not returned then it is not Linked meaning you will need to add it. Otherwise move to step 3.
For Sql Server 2008 R2, go to Server Object > Linked Servers > Add new Linked Server
Or
exec sp_addlinkedserver #server='ServerName';
3. Connect to the Secondary server like so...
exec sp_addlinkedsrvlogin
#rmtsrvname='ServerName'
, #useself=false
, #rmtuser='user'
, #rmtpassword='Password';
4. Now you can Join the tables for the two different servers.
SELECT
SRV1.*
FROM
DB1.database_name.dbo.table_name SRV1
INNER JOIN DB2.database_name.dbo.table_name SRV2
ON SRV1.columnId = SRV2.columnId
GO
You have to first link two servers before joining the tables. Once they are linked, you can just use the below query and replace server, database & table names.
Remember to execute the below sql in DB2:
EXEC sp_addlinkedserver DB1
GO
-- below statement connects sa account of DB2 to DB1
EXEC sp_addlinkedsrvlogin #rmtsrvname = 'DB1', #useself = 'false', #locallogin = 'sa', #rmtuser = 'sa', #rmtpassword = 'DB1 sa pwd'
GO
SELECT a.columns
FROM DB1.database_name.dbo.table_name a
INNER JOIN DB2.database_name.dbo.table_name b
ON a.columnId = b.columnId
GO
Linking servers - http://msdn.microsoft.com/en-us/library/ms188279.aspx
You can write query as below syntax to join other server in SQL Server
SELECT table_1.*
FROM [Database_1].[dbo].[Table_1] table_1
INNER JOIN [IP_OF_SERVER_2].[Database_2].[dbo].[Table_2] table_2 ON table_1.tablekey COLLATE DATABASE_DEFAULT = table_2.tablekey COLLATE DATABASE_DEFAULT
p/s: COLLATE DATABASE_DEFAULT to encode,
Prevent bellow error
Cannot resolve the collation conflict between "Vietnamese_CI_AS" and "SQL_Latin1_General_CP1_CI_AS" in the equal to operation.

Query multiple SQL Servers in One query

I am trying to set up a query that will grab the Windows version of each SQL Server I have and throw it into a table. I have the query that grabs the version but I think there is a better way to get the information needed than connecting to each indiviual server one by one to run the query. I am not opposed to using XP_cmdshell I am just wondering if there is a way to run one query that will grab the version of each Windows OS I have on the sql servers. Also I do have a list of servers to use.
EDIT: I know I wil have to in some way touch each server. I would just like a way to get around having the RDP to each server and open SQL server and query it or haveing to connect to each server within sql server and running the query one by one.
All I have right now code wise is a simple INSERT STATEMENT I get here and I draw a blank on where to go next of even hoe to tackle the problem. The table below has two columns ServerName and Win_Ver ServerName is already populated with all the servers I have.
INSERT INTO mtTable
(Win_Ver)
SELECT ##Version
Given that:
there are "roughly 112 servers"
the servers being a "mixture between 2008 - 2012"
"There is table we are keeping with all of our DB server Statistics."
and "We periodically get asked to produce these statistics"
one option is to cycle through that table of servers using a cursor, and for each one, execute xp_cmdshell to call SQLCMD to run the query. You would use a table variable to capture the result set from SQLCMD as returned by xp_cmdshell. Something like:
DECLARE #ServerName sysname,
#Command NVARCHAR(4000),
#CommandTemplate NVARCHAR(4000);
DECLARE #Results TABLE ([ResultID] INT IDENTITY(1, 1) NOT NULL, [Result] NVARCHAR(4000));
SET #CommandTemplate = N'SQLCMD -S {{SERVER_NAME}} -E -h-1 -Q "PRINT ##VERSION;"';
DECLARE srvrs CURSOR LOCAL READ_ONLY FAST_FORWARD
FOR SELECT [ServerName]
FROM ServerStats;
OPEN srvrs;
FETCH NEXT
FROM srvrs
INTO #ServerName;
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #Command = REPLACE(#CommandTemplate, N'{{SERVER_NAME}}', #ServerName);
INSERT INTO #Results ([Result])
EXEC xp_cmdshell #Command;
-- Get results via SELECT [Result] FROM #Results ORDER BY [ResultID];
-- Do something with the data in #Results
DELETE FROM #Results;
FETCH NEXT
FROM srvrs
INTO #ServerName;
END;
CLOSE srvrs;
DEALLOCATE srvrs;
And it wouldn't hurt to throw in a TRY / CATCH in there :-).
Even if not the most ideal of solutions, it is at least doesn't require adding 112 Linked Servers, and is dynamic and will adjust to servers being added and removed.
In SQL Server you are able to create a Linked Server that you can query from another server.
On the server you wish to write the query in:
Open the Object Explorer
Go to Server Objects
Right Click Linked Servers and add a New Linked Server
Add the Name of your networked server, select SQL server and make sure to define security roles.

Resources