I am trying to get data from different sever, and the sever name might change. So I set the server name as a parameter. The idea of my sql store procedure is something like this
CREATE PROCEDURE [dbo].[GetData]
#ServerName
AS
BEGIN
SELECT * FROM #ServerName.ClientDataBase.dbo.Client
END
Does anyone know how to achieve this?
The database version is sql server 2005
Use dynamic SQL, however evil this may be:
exec('select * from ' + #ServerName + '.ClientDatabase.dbo.Client')
Look at using Synonym(s)
Create syntax (from MSDN):
CREATE SYNONYM [ schema_name_1. ] synonym_name FOR < object >
< object > :: =
{
[ server_name.[ database_name ] . [ schema_name_2 ].|
database_name . [ schema_name_2 ].| schema_name_2. ] object_name
}
You could set up a linked server, says "BOB".
Then you could call sp_setnetname to change the underlying target server but keep the name BOB.
So your code would be:
CREATE PROCEDURE [dbo].[GetData]
#ServerName
AS
BEGIN
EXEC sp_setnetname 'BOB', #ServerName
SELECT * FROM BOB.ClientDataBase.dbo.Client
END
-- Proc to get remove server name (domaine+instance name)
IF OBJECT_ID('dbo.getRemoteName') IS NOT NULL
DROP PROC dbo.getRemoteName;
GO
CREATE PROC dbo.getRemoteName
#id AS INT,
#RETURN AS VARCHAR(100) OUTPUT
AS
BEGIN
DECLARE #GetInstances TABLE
( id INT IDENTITY(0,1),
VALUE NVARCHAR(100),
instanceName NVARCHAR(100),
DATA NVARCHAR(100))
INSERT INTO #GetInstances
EXECUTE xp_regread
#rootkey = 'HKEY_LOCAL_MACHINE',
#KEY = 'SOFTWAREMicrosoftMicrosoft SQL Server',
#value_name = 'InstalledInstances'
-- order ascendant
-- Select * from #GetInstances -- uncomment to see all the instances that your have
SELECT #RETURN=instanceName FROM #GetInstances WHERE id=#id ORDER BY instanceName ASC;
SET #RETURN=HOST_NAME()+''+#RETURN;
END;
GO
DECLARE #RETURN AS VARCHAR(100);
-- get the instance number 0
EXEC getRemoteName 0, #RETURN OUTPUT;
PRINT #RETURN;
--
exec('SELECT * FROM ['+#RETURN+'].RemoteDatabase.dbo.SampleTable');
Related
I'm executing a dynamic query from a variable but it always says:
Could not find stored procedure
I have tried to use simpler queries like set #query = 'select * from [table_name]' but it gives the same error.
CREATE TABLE #test
(
id INT IDENTITY(1, 1) NOT NULL,
name VARCHAR(200)
)
DECLARE #TRIGER_NAME VARCHAR(200)
DECLARE #V_MAX INT
DECLARE #V_MIN INT
DECLARE #QUERY VARCHAR(MAX)
SELECT #V_MAX = MAX(id)
FROM #test
SELECT #V_MIN=Min(id)
FROM #test
WHILE #V_MIN <= #V_MAX
BEGIN
SELECT #TRIGER_NAME = name
FROM #test
WHERE id = #V_MIN
SET #QUERY = 'DROP TRIGGER '+ #TRIGER_NAME;
EXEC #query
SET #V_MIN = #V_MIN+1
END
In my temporary table is the list of all my trigger name so the expected output I want to get is Command(s) completed successfully. Not 'Could not find stored procedure', because I supposed to executing a dynamic queries not a stored procedure.
Instead EXEC #query use, EXEC sp_executesql #query. From the docs:
Executes a Transact-SQL statement or batch that can be reused many
times, or one that has been built dynamically. The Transact-SQL
statement or batch can contain embedded parameters.
Or if you want to use EXEC, change it to:
EXEC (#query)
From the documentation you have:
Execute a character string { EXEC | EXECUTE }
( { #string_variable | [ N ]'tsql_string' } [ + ...n ] )
[ AS { LOGIN | USER } = ' name ' ] [;]
which means your #string_variable or string must be wrapped in ().
Is there any good way to do this, or am I just heading in the wrong direction? I would like to create a stored procedure inside an SQL script. I would like to have variables declared at the beginning of the script so that I can create the SPROCs to use in different contexts/servers.Here is what I would like to do (I know this obviously doesn't work, but I'm looking for any ideas of an alternative)..
DECLARE #golbalValue = 'SomeValue'
GO
CREATE PROCEDURE [dbo].[MyStoredProcedure](
AS
BEGIN
SELECT * FROM Mytable WHERE MyCol = #globalValue
END
GO
What you could do is use a scalar function for the variable
create function f ()
returns varchar(20)
as
begin
return 'some value'
end
go
then use it in your procedure
create proc p ()
as
begin
select *
from my_table
where col = f()
end
go
another possibility which is perhaps more appropriate is to use sqlcmd here's an example.
From what I understand, you need to create stored procedures with set value from your parameters. You don't want input parameters in the stored Procedures though. Second, you want to switch database contexts. So I think you'll need a tempTable for your parameters and some dynamic SQL. Try this out:
IF OBJECT_ID('tempdb..#globalParam') IS NOT NULL
DROP TABLE #globalParam;
IF OBJECT_ID('AdventureWorks2012.dbo.myTable') IS NOT NULL
DROP TABLE AdventureWorks2012.dbo.myTable
IF OBJECT_ID('Master..myTable') IS NOT NULL
DROP TABLE Master..mytable
--Create your data tables
SELECT 'SomeValue' AS col1 INTO AdventureWorks2012.dbo.myTable;
SELECT 1000 AS col1 INTO master.dbo.myTable;
CREATE TABLE #globalParam(
ParamName VARCHAR(100),
val SQL_VARIANT --SQL_Variant is designed to hold all data types.
);
--Here are your globalParams
DECLARE #globalParam1 VARCHAR(100) = 'SomeValue';
DECLARE #globalParam2 INT = 1000;
--Load your parameters into a table. Might have to cast some of your parameters to SQL_Variant
INSERT INTO #globalParam
VALUES ('globalParam1',#globalParam1),
('globalParam2',CAST(#globalParam2 AS sql_variant));
GO
--Switch database context
USE AdventureWorks2012
GO
--Variable to hold CREATE PROC
DECLARE #sql VARCHAR(MAX);
--Set #SQL with parameter value from #globalParam
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam1'
--Execute to create the stored procedure
EXEC(#sql)
--Execute it to see if it works
EXEC dbo.myStoredProc
--Switch context. Repeat same steps
USE master
GO
DECLARE #sql VARCHAR(MAX);
SELECT #sql =
'CREATE PROCEDURE dbo.myStoredProc AS
BEGIN
SELECT * FROM myTable WHERE col1 = ''' + CAST(val AS VARCHAR(100)) + '''
END'
FROM #globalParam
WHERE ParamName = 'globalParam2'
EXEC(#sql)
EXEC dbo.myStoredProc
--Cleanup
DROP PROCEDURE dbo.myStoredProc;
USE AdventureWorks2012
GO
DROP PROCEDURE dbo.myStoredProc;
You cannot do what you want. T-SQL doesn't have the concept of global variables. One method is to store values in a "global" table and then reference them as needed. Something like:
create table GlobalParams (
name varchar(255) not null primary key,
value varchar(255) not null
);
create procedure . . .
begin
. . .
declare #value varchar(255);
select #value = value from Globalparams where name = 'name';
select *
from Mytable
where MyCol = #value;
. . .
end;
Note: this is a simplistic example that only allows variables whose type is a string.
You can also wrap the logic in a user-defined function, so the call looks like:
select *
from Mytable
where MyCol = udf_GlobalLookup('name');
It is rather rare to need global parameters that are shared among different stored procedures. Such a global context can be useful, at times, for complex systems. It is unlikely that you need all this machinery for a simple application. An alternative method, such as just passing the parameters in as arguments, is probably sufficient.
I have created a procedure without any problem. I have tested before creating the procedure but when I try to execute my procedure I have a problem only in the first parameter I have
SQL SERVER 2008 SHOW ME Error syntax in 'Mundus'
ProcAvancementTotalbyEtab 'Erasmus Mundus','C:\Users\AA\Desktop\Table1.xlsx'
and After I try to make like this:
ProcAvancementTotalbyEtab N'Erasmus Mundus','C:\Users\AA\Desktop\Table1.xlsx'
This is my stored procedure:
alter proc ProcAvancementbyEtab
(
#nameEtabb nvarchar(50),
#FilePath nvarchar(60)
)
as
begin
EXEC
(
'
SET NOCOUNT OFF;
insert into Avancement(nameEtab)
SELECT distinct T.[EFP]
From OPENROWSET(''MICROSOFT.ACE.OLEDB.12.0'',
''Excel 12.0;Database='+#FilePath+''',
''SELECT *
FROM [Sheet1$]'') T
where T.[EFP] is not null and T.[Avancement] is not null
and
not exists (select * from Avancement where
Avancement.nameEtab=T.[EFP])
and T.[EFP]='+#nameEtabb+'
')
end
When I comment this line
and T.[EFP]='+#nameEtabb+'
it works fine so my probleme is here
and T.[EFP]='+#nameEtabb+'
and when I test without stored procedure it work also OMG.
My guess is that name is stored as a string. You need an extra pair of quotes:
and T.[EFP] = '''+#nameEtabb+'''
Not sure how to implement this, but I need a way to get the current list of parameters for a stored procedure as well as their passed in values (this code will be executed in the stored procedure itself).
I know I can use sys.parameters to get the parameter names, but how to get the actual values?
What I need to do with this is to make a char string of the form
#param_name1=#value1,#param_name2=#value2,...,#param_namen=#valuen
I have tried to use dynamic sql, but not having much joy with that.
Any ideas??
Edit:
Currently I am just going through all the parameters one-by-one to build the string. However I want a "better" way to do it, since there are quite a few parameters. And incase parameters are added later on (but the code to generate the string is not updated).
I tried using dynamic sql but gave up, since the sp_executesql sp requires parameters be passed into it...
You state '(this code will be executed in the stored procedure itself).' so assuming you are in the procedure you will already know the parameter names as you have to declare them when creating your procedure. Just do a select and put the names inside text fields
ALTER PROCEDURE procname
(
#param1 NVARCHAR(255)
,#param2 INT
...
)
SELECT [Parameters] = '#param1=' + #param1
+ ',#param2=' + CONVERT(NVARCHAR(MAX),#param2)...
The CONVERT is there as an example for non-char datatypes.
update
You will need to create a linked server that points to itself to use the OPENQUERY function.
USE [master]
GO
/****** Object: LinkedServer [.] Script Date: 04/03/2013 16:22:13 ******/
EXEC master.dbo.sp_addlinkedserver #server = N'.', #srvproduct=N'', #provider=N'SQLNCLI', #datasrc=N'.', #provstr=N'Integrated Security=SSPI'
/* For security reasons the linked server remote logins password is changed with ######## */
EXEC master.dbo.sp_addlinkedsrvlogin #rmtsrvname=N'.',#useself=N'True',#locallogin=NULL,#rmtuser=NULL,#rmtpassword=NULL
GO
Now you can do something like this cursor to get each parameter name and then use dynamic sql in OPENQUERY to get the value:
DECLARE curParms CURSOR FOR
SELECT
name
FROM sys.parameters
WHERE OBJECT_ID = OBJECT_ID('schema.procedurename')
ORDER BY parameter_id
OPEN curParms
FETCH curParms INTO #parmName
WHILE ##FETCH_STATUS <> -1
BEGIN
SELECT #parmName + '=' + (SELECT * FROM OPENQUERY('linkedservername','SELECT ' + #parmName))
FETCH curParms INTO #parmName
END
CLOSE curParms
DEALLOCATE curParms
Since SQL Server 2014 we have sys.dm_exec_input_buffer, it is a table valued function with an output column event_info that gives the full execution statement (including parameters).
We can parse the param values from sys.dm_exec_input_buffer and get the param names from sys.parameters and join them together to get the string you want.
For example:
create procedure [dbo].[get_proc_params_demo]
(
#number1 int,
#string1 varchar(50),
#calendar datetime,
#number2 int,
#string2 nvarchar(max)
)
as
begin
-- get the full execution statement
declare #statement nvarchar(max)
select #statement = event_info
from sys.dm_exec_input_buffer(##spid, current_request_id())
-- parse param values from the statement
declare #proc_name varchar(128) = object_name(##procid)
declare #param_idx int = charindex(#proc_name, #statement) + len(#proc_name)
declare #param_len int = len(#statement) - #param_idx
declare #params nvarchar(max) = right(#statement, #param_len)
-- create param values table
select value, row_number() over (order by current_timestamp) seq
into #params
from string_split(#params, ',')
-- get final string
declare #final nvarchar(max)
select #final = isnull(#final + ',','') + p1.name + '=' + ltrim(p2.value)
from sys.parameters p1
left join #params p2 on p2.seq = parameter_id
where object_id = ##procid
select #final params
end
To test it:
exec get_proc_params_demo 42, 'is the answer', '2019-06-19', 123456789, 'another string'
Returns the string you want:
#number1=42,#string1='is the answer',#calendar='2019-06-19',#number2=123456789,#string2='another string'
I have something similar wrapped as a UDF. I use it for error logging in catch blocks.
I have a stored procedure that returns rows:
CREATE PROCEDURE MyProc
AS
BEGIN
SELECT * FROM MyTable
END
My actual procedure is a little more complicated, which is why a stored procedure is necessary.
Is it possible to select the output by calling this procedure?
Something like:
SELECT * FROM (EXEC MyProc) AS TEMP
I need to use SELECT TOP X, ROW_NUMBER, and an additional WHERE clause to page my data, and I don't really want to pass these values as parameters.
You can
create a table variable to hold the
result set from the stored proc and
then
insert the output of the
stored proc into the table variable,
and then
use the table variable
exactly as you would any other
table...
... sql ....
Declare #T Table ([column definitions here])
Insert #T Exec storedProcname params
Select * from #T Where ...
You can use a User-defined function or a view instead of a procedure.
A procedure can return multiple result sets, each with its own schema. It's not suitable for using in a SELECT statement.
You either want a Table-Valued function or insert your EXEC into a temporary table:
INSERT INTO #tab EXEC MyProc
You need to declare a table type which contains the same number of columns your store procedure is returning. Data types of the columns in the table type and the columns returned by the procedures should be same
declare #MyTableType as table
(
FIRSTCOLUMN int
,.....
)
Then you need to insert the result of your stored procedure in your table type you just defined
Insert into #MyTableType
EXEC [dbo].[MyStoredProcedure]
In the end just select from your table type
Select * from #MyTableType
You must read about OPENROWSET and OPENQUERY
SELECT *
INTO #tmp FROM
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc #parameters')
It is not necessary use a temporary table.
This is my solution
SELECT * FROM
OPENQUERY(YOURSERVERNAME, 'EXEC MyProc #parameters')
WHERE somefield = anyvalue
You can copy output from sp to temporaty table.
CREATE TABLE #GetVersionValues
(
[Index] int,
[Name] sysname,
Internal_value int,
Character_Value sysname
)
INSERT #GetVersionValues EXEC master.dbo.xp_msver 'WindowsVersion'
SELECT * FROM #GetVersionValues
drop TABLE #GetVersionValues
Try converting your procedure in to an Inline Function which returns a table as follows:
CREATE FUNCTION MyProc()
RETURNS TABLE AS
RETURN (SELECT * FROM MyTable)
And then you can call it as
SELECT * FROM MyProc()
You also have the option of passing parameters to the function as follows:
CREATE FUNCTION FuncName (#para1 para1_type, #para2 para2_type , ... )
And call it
SELECT * FROM FuncName ( #para1 , #para2 )
You can cheat a little with OPENROWSET :
SELECT ...fieldlist...
FROM OPENROWSET('SQLNCLI', 'connection string', 'name of sp')
WHERE ...
This would still run the entire SP every time, of course.
If 'DATA ACCESS' false,
EXEC sp_serveroption 'SQLSERVERNAME', 'DATA ACCESS', TRUE
after,
SELECT * FROM OPENQUERY(SQLSERVERNAME, 'EXEC DBNAME..MyProc #parameters')
it works.
Use OPENQUERY, and before execute set SET FMTONLY OFF; SET NOCOUNT ON;
Try this sample code:
SELECT top(1)*
FROM
OPENQUERY( [Server], 'SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE [database].[dbo].[storedprocedure] value,value ')
If you get the error 'Server is not configured for DATA ACCESS',
use this:
EXEC sp_serveroption 'YourServer', 'DATA ACCESS', TRUE
For the sake of simplicity and to make it re-runnable, I have used a system StoredProcedure "sp_readerrorlog" to get data:
-----USING Table Variable
DECLARE #tblVar TABLE (
LogDate DATETIME,
ProcessInfo NVARCHAR(MAX),
[Text] NVARCHAR(MAX)
)
INSERT INTO #tblVar Exec sp_readerrorlog
SELECT LogDate as DateOccured, ProcessInfo as pInfo, [Text] as Message FROM #tblVar
-----(OR): Using Temp Table
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp;
CREATE TABLE #temp (
LogDate DATETIME,
ProcessInfo NVARCHAR(55),
Text NVARCHAR(MAX)
)
INSERT INTO #temp EXEC sp_readerrorlog
SELECT * FROM #temp
It sounds like you might just need to use a view. A view allows a query to be represented as a table so it, the view, can be queried.
If your server is called SERVERX for example, this is how I did it...
EXEC sp_serveroption 'SERVERX', 'DATA ACCESS', TRUE;
DECLARE #CMD VARCHAR(1000);
DECLARE #StudentID CHAR(10);
SET #StudentID = 'STUDENT01';
SET #CMD = 'SELECT * FROM OPENQUERY([SERVERX], ''SET FMTONLY OFF; SET NOCOUNT ON; EXECUTE MYDATABASE.dbo.MYSTOREDPROC ' + #StudentID + ''') WHERE SOMEFIELD = SOMEVALUE';
EXEC (#CMD);
To check this worked, I commented out the EXEC() command line and replaced it with SELECT #CMD to review the command before trying to execute it! That was to make sure all the correct number of single-quotes were in the right place. :-)
I hope that helps someone.