Bypassing character limit on OPENQUERY failing use EXECUTE - sql

I am currently using SQL Server Management Studio 17 to connect to an Oracle database instance and then extract some data and insert it into a SQL Server Table I have.
I have tried doing the following:
DROP TABLE IF EXISTS [jerry].[dbo].[purchases]
SELECT * INTO [jerry].[dbo].[purchases] FROM OPENQUERY(OLAP, '
proprietary sql code
');
However the SQL code is about 9500 characters and thus OPENQUERY fails, which is supported by MSDN articles
I referenced these sites:
- MSDN One - MSDN Two
and learned that I can use EXEC to accomplish my goal.
I have tried to implement the following:
EXEC master.dbo.sp_serveroption #server=N'OLAP', #optname=N'rpc out', #optvalue=N'true'
DECLARE #sqlcode VARCHAR(MAX)
SET #sqlcode = 'sql code'
DROP TABLE IF EXISTS [jerry].[dbo].[purchases]
EXEC #sqlcode AT OLAP
However, I am still getting an Invalid Syntax near OLAP error.
I have confirmed that OLAP is the correct name from our DBA and other OPENQUERY functions work just fine (with much shorter SQL statements).
I cannot edit the SQL query
I cannot edit the external OLAP's databases permissions (I am not the DBA nor am I in the security group)
Any assistance is greatly appreciated.

EXEC without parentheses runs a stored procedure.
So try:
truncate table [jerry].[dbo].[purchases]
insert into [jerry].[dbo].[purchases]
exec ( #sqlcode ) at olap
See execute

Related

How to create stored procedure to create views across databases in the same SQL server?

I'm trying to create a stored procedure in the master database that creates views across other databases under this.
I tried using "USE dbname" under EXEC, but it did not work.
This is the code I'm using,
CREATE PROCEDURE BuildMultipleViews
AS
EXEC ('USE database1
GO
CREATE VIEW ST
AS
SELECT DISTINCT t.col1, t.col2
FROM table1 t')
GO
GO is not a T-SQL statement. GO is a batch separator that's recognized only by T-SQL utilities like SSMS and SQLCMD and some SMO APIs. SQL Server will not understand the meaning of GO in the T-SQL script in your question.
To create views in databases other than the one of the invoking stored procedure, use sp_executesql qualified with the target database name and make sure the CREATE VIEW is the only statement in the executed batch:
CREATE PROCEDURE dbo.BuildMultipleViews
AS
DECLARE #CreateViewStatement nvarchar(MAX) =
N'CREATE VIEW ST
AS
SELECT DISTINCT t.col1, t.col2
FROM table1 t;';
EXECUTE Database1..sp_executesql #CreateViewStatement;
EXECUTE Database2..sp_executesql #CreateViewStatement;
GO

How to use 'use' command across all database to execute certain script in sql

I have a certain script which I need to execute across all databases in SQL Server. I have used the following logic to loop through all database excluding the system databases.
declare #DBName varchar(500)
DECLARE #Database_id int
DECLARE #Query varchar(MAX)
select #Database_id = MIN(database_id) from sys.databases where database_id>4
while #Database_id is not null
begin
select #DBName=name from sys.databases where database_id=#Database_id
set #Query = 'Use'+#DBName
--some script
Print ''+#DBName+''
exec (#Query)
select #Database_id = MIN(database_id) from sys.databases where database_id>4 AND database_id>#Database_id
end
But the problem is I can't use the 'Use' command with a variable. Is there any other way to make use of 'Use' command to hit the database?
And I don't want to use sp_MSforeachdb command as my query is too long.
Any help would be appreciated!
There is an undocumented function doing this. You can use the question mark in the place of the db's name:
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_spaceused'
Find this example and more explanations here: http://weblogs.sqlteam.com/joew/archive/2008/08/27/60700.aspx
EDIT: From your comments above I find, that you do not want to includ the system dbs into your run. It seems to be q bit tricky to detect, whether a db is a system db or not but you could go like this:
DECLARE #cmd VARCHAR(1000)='USE [?];IF DB_ID(DB_NAME())<=4 RETURN;EXEC sp_spaceused;'
EXECUTE master.sys.sp_MSforeachdb #cmd;
GO
Read about the flaws here (about SQL Server 2005!): SQL Server: How to tell if a database is a system database?
If you don't like this <=4 you could simply do it like
IF DB_NAME() IN('master','model',... any more names here ... ) RETURN;
The only real restriction I know of is, that sp_MSforeachdb does not like "GO".

SQL Server Linked Server Join

I have added a linked server in my sql server 2008. I want to fetch data from a table and a table valued function residing on my linked server and join this data on a local table by following below given naming convention.
<server>.<database>.<schema>.<table>
However my first problem is I need to fetch <server> part from a table. So when I try to do something like following it fails
Select * FROM #ServerNameVariable.database.dbo.myTable
Any idea how can I form fully qualified linked server table name with a user defined variable ?
My SP is as follows
CREATE PROCEDURE TEST_SP
AS
BEGIN
DECLARE #NetworkDBName VARCHAR(255)
SET #NetworkDBName = '[MyLinkedServerName]'
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select * from #NetworkDBName + '.' + testDatabase.dbo.Invoice_tb
END
GO
You cannot use variables in place of database, schema or table names.
Instead you can build and execute dynamic SQL statements, using sp_ExecuteSQL.
This example won't work, as the server name is seen as a string and not a server object.
Failed Example
/* Anti-pattern.
* Does not work.
*/
DECLARE #Server SYSNAME = 'Server001';
SELECT
*
FROM
#Server.Database1.dbo.Table1
;
This example shows a method that does work. Here the SQL statement is built as a string, which is then executed.
/* Dynamic SQL statement.
* Will work.
*/
DECLARE #Server SYSNAME = 'Server001';
DECLARE #Statement NVARCHAR(255);
SET #Statement = 'SELECT * FROM ' + QUOTENAME(#Server) + '.Database1.dbo.Table1;';
EXECUTE sp_ExecuteSQL #Statement;
As ever; please be careful when generating and executing dynamic SQL statements. You do not want to open yourself up to SQL injection attacks. Look into OPENROWSET or check the passed server name against the code kindly supplied by #Devart above (SELECT name FROM sys.servers WHERE server_id > 0) before executing.
EDIT 1: Added more detail to the paragraph on SQL injection.
EDIT 2: Removed square brackets from 2nd example query, replaced with QUOTENAME, as per #TTs comment.
Use the name of link server it will a 4 part qualifier e.g
Select * From [Link Server Name ].[Database].[Schema].[Table]

Drop multiple databases in SQl Azure

I would like to run a script to drop the multiple databases from SQL Azure as soon I finish using it. When I tried as following,
DECLARE #dbname varchar(100);
DECLARE #stmt nvarchar(3000);
SET #dbname = '6A732E0B';
SELECT #stmt = (SELECT 'DROP DATABASE [' + name + ']; ' FROM sys.databases
WHERE name LIKE '%' +#dbname +'%');
EXEC sp_executesql #stmt;
SQL Azure throws error message as “The DROP DATABASE statement must be the only statement in the batch”
Can somebody help me on this?
This is a known limitation in SQL Azure - certain statements need to be in a batch by themselves to be executed. This includes CREATE/ALTER DATABASE, ALTER DATABASE and a few more.
To solve you problem, you can create a loop in you application where you iterate over all the databases and drop them by issuing DROP DATABASE statements in separate batches.
I believe this is a bug of SQL Azure. I've recently reported it to Microsoft:
https://connect.microsoft.com/SQLServer/feedback/details/684160/sp-executesql-the-drop-database-statement-must-be-the-only-statement-in-the-batch

Execute sybase stored procedure as linked server procedure sql server 2008

EDIT
The final goal is to call a stored procedure hosted in sybase with input and output parameters from SQL Server 2008 via Linked Server
I think title is pretty clear.
My goal is to execute a stored procedure hosted in Sybase SQL Anywhere 8 in SQL Server 2008 through the linked server I already created.
Any SQL query made through the linked server is working.
In addition I was able to execute a function but I don't now how to get the return value like that
EXEC ('CALL "dbname"."procedurename"(''param1'', ''param2'', ''param3'')') AT LinkedServerAlias;
Thanks 4 all your help!
Mauro
can you use four part naming convention?
like
exec LinkedServerName.dbname.dbo.procedurename #param1, #param2, #param3
I was finally able to do it by calling
SELECT * FROM OPENQUERY([LinkedServer], 'SELECT "dbname"."spname"(#p1,#p2, #p3)')
I'll add comments and example as soon as I experiment it.
4 part object names are valid only for SQL Server linked servers.
You have to have your EXEC inside an OPENQUERY
SELECT * FROM OPENQUERY([LinkedServer], 'EXEC MyDB.MyScheme.MyProc.spname #p1, #p2, #p3')
Now, you can't parametrise OPENQUERY calls so you have use dynamic SQL
DECLARE #sql nvarchar(4000), #linkedsql nvarchar(4000)
SET #sql = 'EXEC MyDB.MyScheme.MyProc.spname ' + CAST(#p1value as int) + ...
SET #linkedsql = 'SELECT * FROM OPENQUERY(LinkedServer, ''' + #sql + ''')'
EXEC (#linkedsql)