Variables in OPENQUERY "Deferred prepare could not be completed" error - sql

I understand that you cannot include variables in OPENQUERY so the work around is dynamic SQL and I did the following:
DECLARE #etd AS DATETIME = '2014-06-28'
DECLARE #source AS VARCHAR(46)
DECLARE #dbName AS VARCHAR(30)
DECLARE #query AS VARCHAR(MAX)
DECLARE #openQuery AS VARCHAR(MAX)
SELECT TOP(1) #source = [Source], #dbName = DbName
FROM dbo.SomeTable
WHERE SystemCode = 'SomeSystem'
SET #query = 'SELECT *
FROM [' + #dbName + '].dbo.Table1 t1
LEFT JOIN [' + #dbName + '].dbo.Table2 t2 ON t1.bookno = t2.tranno
WHERE (YEAR(t1.etddate) = ' + CAST(YEAR(#etd) AS VARCHAR(4)) +
' AND MONTH(t1.etddate) = ' + CAST(MONTH(#etd) AS VARCHAR(2)) +
' AND DAY(t1.etddate) = ' + CAST(DAY(#etd) AS VARCHAR(2)) +')'
SET #openQuery = 'SELECT * FROM OPENQUERY([' + #source + '],''' + #query + ''')'
EXECUTE (#openQuery)
When I use SELECT #openQuery I don't see anything wrong with the query string, but once I execute it, I received the following error:
OLE DB provider "SQLNCLI11" for linked server "xxx.xxx.xxx.xxx,1433" returned message "Deferred prepare could not be completed.".
Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 208, Level 16, State 1, Line 1
Invalid object name 'xxxx.dbo.t1'. (where 'xxxx' is the table name variable)
I've been searching for answers but I cannot find any, I really need your help guys.

You might temporarily change the EXECUTE to PRINT (PRINT #openQuery), see what SQL is actually being generated, then attempt to run the generated sql directly in SSMS. It might be obvious when you see the generated sql, but if not, you might get a more descriptive error message.

Related

'Msg 137, Level 16, State 1, Line 17 Must declare the scalar variable "#tempFinalTable"' error but #tempFinalTable is declared

(Working with Microsoft SQL Server Management Studio)
I have a query that should, in theory, return a table containing all of the tables contained within the databases of the server to which I am connected.
However, whenever I run the query, I get the following error:
Msg 137, Level 16, State 1, Line 17
Must declare the scalar variable "#tempFinalTable".
The query itself
DECLARE #tempTableVariable TABLE (id INT NOT NULL IDENTITY(1,1), DB varchar(1000))
DECLARE #tempFinalTable TABLE (id INT NOT NULL IDENTITY(1,1), DB varchar(1000), TABLE_LOC varchar(1000))
DECLARE #DBIndex INT = 1
DECLARE #Query varchar(1000)
DECLARE #MyDB varchar(1000)
DECLARE #RowCount INT = (SELECT COUNT(*) FROM #tempTableVariable)
INSERT INTO #tempTableVariable
SELECT [name]
FROM MASTER.dbo.SYSDATABASES WITH (NOLOCK)
WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')
WHILE #DBIndex < #RowCount
BEGIN
SET #MyDB = (SELECT DB FROM #tempTableVariable WHERE id = #DBIndex)
SET #Query = 'INSERT INTO'+ #tempFinalTable + ' (DB, TABLE_LOC)
SELECT TABLE_CATALOG, CONCAT(TABLE_CATALOG, ''.'', TABLE_SCHEMA, ''.'', TABLE_NAME)
FROM ' + #MyDB + '.INFORMATION_SCHEMA.TABLES
ORDER BY TABLE_CATALOG'
EXEC(#QUERY)
SET #DBIndex = #DBIndex + 1
END
SELECT *
FROM #tempFinalTable
Any guidance as to where I have made a mistake would be greatly appreciated.
Your primary issue is that you have a syntax error, because you are trying to use the value of the table variable as part of the dynamic SQL string, but only a scalar variable can be used like that.
Even if you put the table variable within the string properly, you would still run into scoping issues, because variables don't pass over to dynamic SQL.
A much better solution is to forgo the table variable, and instead build a UNION ALL query to select it straight from dynamic SQL.
Note also:
Object names are nvarchar(128) you can use the alias sysname
You need to quote names with QUOTENAME
Don't use dbo.sysdatabases and INFORMATION_SCHEMA, they're deprecated. Instead use sys.databases and sys.tables
DECLARE #sql nvarchar(max) = (
SELECT STRING_AGG(CAST('
SELECT
DB = ' + QUOTENAME(d.name, '''') + ',
TABLE_LOC = ' + QUOTENAME(d.name, '''') + ' + ''.'' + s.name + ''.'' + t.name
FROM ' + QUOTENAME(d.name) + '.sys.tables t
JOIN ' + QUOTENAME(d.name) + '.sys.schemas s ON s.schema_id = t.schema_id
'
AS nvarchar(max)), 'UNION ALL')
FROM sys.databases d
WHERE d.database_id > 4 -- not system DB
);
PRINT #sql; --for testing
EXEC sp_executesql #sql;
I can't say whether you need QUOTENAME within the dynamic query, because I don't know what result you want, or what you intend to do with the result. If need be, you can do
TABLE_LOC = QUOTENAME(' + QUOTENAME(d.name, '''') + ') + ''.'' + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name)

Using a variable as table name fails

Why does this fail with the following error message:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'reporting_rawdata_v2'.
the name of the table is "dbo.reporting_rawdata_v2" but either with/without "dbo" it still fails...
Use reporting2
Go
Declare #Backupdate varchar(25), #sql NVARCHAR(max)
Set #Backupdate = REPLACE(REPLACE(CAST(CONVERT(VARCHAR(20), SYSDATETIME(), 100) as varchar),' ','_'),':', '')
Select #Backupdate
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + 'From reporting_rawdata_v2';
EXEC (#sql);
No space between dynamically named table and From
SET #sql = 'Select * Into reporting_rawdata_BACKUP_' + #Backupdate + ' From reporting_rawdata_v2';
EXEC (#sql);

Syntax issue in SQL Server, using OPENROWSET

I am trying to Execute a stored procedure that requires to variables be passing into to it. One is a static, the other is a dynamic variable.
DECLARE #Filt DATETIME
SET #Filt = (SELECT DISTINCT MAX(Date) FROM Data.db.Staging)
SELECT * INTO #tempData FROM OPENROWSET('SQLNCLI', 'Server=ISR14 \MSSQL2012;Trusted_Connection=yes;', 'EXEC GetData.db.Staging #Mode = ''Date'' #Filt ')
but that doesn't work, got the error back
"Msg 8180, Level 16, State 1, Line 1
Statement(s) could not be prepared.
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '#Filt'."
I'm guessing it is because Filt is dynamic statement. So I tried this
DECLARE #FilterData DATETIME
DECLARE #sql VARCHAR(200)
SET #Filt = (SELECT DISTINCT MAX(AsOfDate) FROM Data.db.Staging)
SET #sql = 'EXEC GetData.db.Staging #Mode = ''Date'' #Filt = ' + #Filt
SELECT * INTO #tempData FROM OPENROWSET('SQLNCLI', 'Server=ISR14\MSSQL2012;Trusted_Connection=yes;',
#sql)
But I get the message back
"Msg 102, Level 15, State 1, Line 24
Incorrect syntax near '#sql'."
It seems that OPENROWSET can only accept strings. But I want to pass a variable that is dynamic.
You have to put the whole statement into a variable and run it, and convert #FilterData to a varchar to concatenate it.
You can't use variables with openquery/openrowset.
Try this and check the print output... if it works and looks ok, then EXEC(#sql2)
DECLARE #FilterData DATETIME
DECLARE #sql VARCHAR(200), #sql2 VARCHAR(500)
SET #FilterData = '2014-07-01'--(SELECT DISTINCT MAX(AsOfDate) FROM Data.db.Staging)
SET #sql = 'EXEC GetData.db.Staging #Mode = ''''Date'''', #Filt = ''''' + CONVERT(VARCHAR(20),#FilterData ,120) + ''''''
SET #sql2 = 'SELECT * INTO #tempData FROM OPENROWSET(''SQLNCLI'', ''Server=ISR14\MSSQL2012;Trusted_Connection=yes;'',
'''+#sql+''')'
print #sql2
--exec(#sql2)
You need to make the whole query dynamic, not sure if I got it nailed down, but something like:
DECLARE #Filt DATETIME
,#sql VARCHAR(MAX)
SET #Filt = (SELECT MAX(Date) FROM Data.db.Staging)
SET #sql = 'SELECT * INTO #tempData FROM OPENROWSET(''SQLNCLI'', ''Server=ISR14 \MSSQL2012;Trusted_Connection=yes;'', ''EXEC GetData.db.Staging #Mode = ''''Date''' +#Filt+ ')'
EXEC (#sql)

Database distribution dose not exist in sp_replmonitorsubscriptionpendingcmds

I'm creating a dynamic SQL log that will tell me the unpending transaction.
I'm trying to enter sp_replmonitorsubscriptionpendingcmds into a table for that reason in need to execute it as sp_executesql.
For some reason when I finish running the script it says
Msg 911, Level 16, State 4, Line 1
Database 'distribution' does not exist. Make sure that the name is entered correctly.
and im running it on distribution database.
Thank you for your help
set #counter = 1
while #counter <#NOR
BEGIN
select #v_publisher=servername,
#v_publisher_db=DbName,
#v_publication = DbName+'_1way',
#v_subscriber = ##servername,
#v_subscriber_db =DbName
from Serverses
where id = #counter
SET #sql = N'SELECT * INTO #pendingcmds
FROM OPENROWSET(''SQLOLEDB'',''SERVER=(LOCAL);TRUSTED_CONNECTION=YES''
,''SET FMTONLY OFF EXEC distribution.dbo.sp_replmonitorsubscriptionpendingcmds #publisher=['
+ #v_publisher + '],
#publisher_db='+ #v_publisher_db + ',
#publication='+ #v_publication + ',
#subscriber=['+ #v_subscriber + '],
#subscriber_db='+ #v_subscriber_db + ',
#subscription_type=' + CONVERT(CHAR(1),#pubtype) + ''')'
select #sql
EXEC sp_executesql #sql
set #counter=#counter+1
END

Error while passing a where clause as a stored procedure parameter

I have created following stored procedure in SQL Server,
create procedure sp_test
#columns nvarchar(max),
#tablename nvarchar(max),
#whereClause nvarchar(max)
as
DECLARE #sql AS NVARCHAR(MAX)
SET #sql = 'SELECT ' + #columns + ' FROM ' + #tablename + #whereClause;
EXEC sp_executesql #sql
I am trying to call it like this
exec sp_test 'title,name','person','where name = ''john'''
And I'm getting an error like this,
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '='.
You have an extra single quote, why not use double quote, like:
exec sp_test 'title,name','person'," where name = 'john'"
Add an extra space also here:
SET #sql = 'SELECT ' + #columns + ' FROM ' + #tablename+ ' ' + #whereClause;
Hint: It's because
SELECT title,name FROM personwhere name = 'john'
is not a valid SQL.
The reason should be obvious now and is left as an exercise to the reader...