OPENQUERY query stored in string fails with EXEC - sql

I'm trying to pull back some data via a linked server that has 'Geography' fields present, consequntly I'm trying to use Open Query.
I'm also trying to pass in a variable...
Can anyone explain this:
This is my sql...
DECLARE #Sql VARCHAR(200)
DECLARE #tnum VARCHAR(20)= 'abc';
SET #Sql = 'SELECT * FROM NationalPolygon.dbo.Polygon WHERE TitleNumber = ''''' + #tnum + '''''';
SET #Sql = 'SELECT * FROM OPENQUERY(mylinkedserver01, ''' + REPLACE(#Sql, '?', '''') + ''')'
SELECT #Sql;
EXEC #Sql;
If I select #Sql and run it, it works.
If I run the #Sql via EXEC it fails with:
Database 'SELECT * FROM OPENQUERY(mylinkedserver01, 'SELECT * FROM NationalPolygon' does not exist. Make sure that the name is entered correctly.
Thanks
C

You need to surround #Sql with brackets
EXEC (#Sql);

Related

query sql server in multiple database

i would like to execute this query 'select count(*) from Aircraft' on multiple database. We have 50 database and all of those have the same table. i'm using sql server 2019.
I know there is a possibilty to loop this query so that's why i'm asking you.
I found some old reply but not recently.
I used this query but it didn't work
SELECT #Query = COALESCE(#Query + ' UNION ALL ', '') + 'select * from [' + TABLE_CATALOG+'].dbo.[Aircraft]'
FROM information_schema.tables
SET #Query = STUFF(#Query, CHARINDEX('UNION ALL', #Query), 10, '')
PRINT #Query
EXEC(#Query)
If all target databases are located in one instance, this can be done using the string_agg function in the following way:
Declare #schema_name sysname = N'dbo'
Declare #table_name sysname = N'Aircraft'
Declare #max nVarChar(max) = ''
Declare #QueryText nVarChar(max)
Select #QueryText = String_Agg(Concat(#max, N'Select * From ',
QuoteName([name]), N'.',
QuoteName(#schema_name),N'.',
QuoteName(#table_name), Char(10)),
Concat(N'UNION ALL',Char(10)))
From master.dbo.sysdatabases
Where OBJECT_ID(Concat(QuoteName([name]),'.',
QuoteName(#schema_name),'.',
QuoteName(#table_name))) Is Not Null
Print #QueryText
Exec sp_executesql #QueryText
You can achieve this by taking advantage of the undocumented stored procedure in SQL Server i.e. sp_MSforeachdb
DECLARE #query NVARCHAR(1000)
SET #query =
'USE ?
IF DB_NAME() NOT IN (''master'', ''tempdb'', ''model'', ''msdb'')
SELECT COUNT(*) AS Count FROM ?.dbo.fin_MemberAccount'
EXEC sp_MSforeachdb #command1 = #query
-- ? : this means the current db while iterating through db by stored procedure

Union of multiple sp_MSforeachdb result sets

I can successfully query the same table in multiple databases as follows:
DECLARE #command varchar(1000)
SELECT #command = 'select * from table'
EXEC sp_MSforeachdb #command
However, all of these results are, as expected, returned in different result windows. What's the easiest way to perform a union of all of these results?
Please stop using sp_MSforeachdb. For anything. Seriously. It's undocumented, unsupported, and spectacularly broken:
Making a more reliable and flexible sp_MSforeachdb
Execute a Command in the Context of Each Database in SQL Server
If you know that all databases have the same table (and that they all have the same structure!), you can do this:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'';
SELECT #sql = #sql + N'UNION ALL SELECT col1,col2 /*, etc. */
FROM ' + QUOTENAME(name) + '.dbo.tablename'
FROM sys.databases WHERE database_id > 4 AND state = 0;
SET #sql = STUFF(#sql, 1, 10, '');
EXEC sp_executesql #sql;
This ignores system databases and doesn't attempt to access any databases that are currently not ONLINE.
Now, you may want to filter this further, e.g. not include any databases that don't have a table called tablename. You'll need to nest dynamic SQL in this case, e.g.:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'DECLARE #cmd NVARCHAR(MAX);
SET #cmd = N'''';';
SELECT #sql = #sql + N'
SELECT #cmd = #cmd + N''UNION ALL
SELECT col1,col2 /*, etc. */ FROM '
+ QUOTENAME(name) + '.dbo.tablename ''
WHERE EXISTS (SELECT 1 FROM ' + QUOTENAME(name)
+ '.sys.tables AS t
INNER JOIN ' + QUOTENAME(name) + '.sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name = N''tablename''
AND s.name = N''dbo'');'
FROM sys.databases WHERE database_id > 4 AND state = 0;
SET #sql = #sql + N';
SET #cmd = STUFF(#cmd, 1, 10, '''');
PRINT #cmd;
--EXEC sp_executesql #cmd;';
PRINT #sql;
EXEC sp_executesql #sql;
This doesn't validate the column structure is compatible, but you'll find that out pretty quickly.
Another way to skin this cat is to use dynamic SQL:
DECLARE #sql varchar(max);
SELECT #sql = Coalesce(#sql + ' UNION ALL ', '') + 'SELECT list, of, columns FROM ' + QuoteName(name) + '.schema.table'
FROM sys.databases
;
PRINT #sql
--EXEC (#sql);
Had some collation issues and had to use
AND COLLATION_NAME = 'SQL_Latin1_General_CP1_CI_AS'

in operator issue in sql server

dECLARE #LS_SQL CHAR(100)
dECLARE #SQL varCHAR(max)
SET #LS_SQL=ltrim('''STOCK IN HAND'',''STORE'',''PRODUCT''')
set #SQL='SELECT * FROM ITEM WHERE GROUPNAME IN(' + rtrim(#LS_SQL) + ')'
PRINT #SQL
execute #SQL
result
SELECT * FROM ITEM WHERE GROUPNAME IN('STOCK IN
HAND','STORE','PRODUCT') Msg 2812, Level 16, State 62, Line 9 Could
not find stored procedure 'SELECT * FROM ITEM WHERE GROUPNAME
IN('STOCK IN HAND','STORE','PRODUCT')'.
This command
execute #SQL
run a procedure. If you wan to run dynamic sql you should use below command:
exec (#SQL)
you can also use
execute sp_sqlexec #SQL
I suggest to use sp_executesql, like:
exec sp_executesql #stmt = #SQL
you can see more help here Dynamic SQL - EXEC(#SQL) versus EXEC SP_EXECUTESQL(#SQL)
try this
dECLARE #LS_SQL CHAR(100)
dECLARE #SQL varCHAR(max)
SET #LS_SQL=ltrim('''STOCK IN HAND'',''STORE'',''PRODUCT''')
set #SQL='SELECT * FROM ITEM WHERE GROUPNAME IN(' + rtrim(#LS_SQL) + ')'
PRINT #SQL
execute sp_sqlexec #SQL

Concatenate in SQL Server

I have the following code in SQL
DECLARE c CURSOR FOR select MSISDN FROM
OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;Database=' + #Path + ';HDR=YES', 'SELECT MSISDN FROM [sheet1$]')
i want to concatenate the path in the database , but the concatenation isn't working , any idea ?
You can't do string concatenation in OPENROWSET - the command expects string literals. I recently had a project at work converting some old SQL that used OPENROWSET and ran into that issue.
One way around this is by using OPENROWSET to dump the data into a table variable, and then declare your cursor from the table variable. Something like this (not tested):
DECLARE #data AS TABLE(MSISDN VARCHAR(255))
DECLARE #sql AS VARCHAR(4000)
SET #sql = 'SELECT MSISDN FROM '
SET #sql = #sql + ' OPENROWSET(''Microsoft.ACE.OLEDB.12.0'','
SET #sql = #sql + '''Excel 12.0;Database=' + #Path + ';HDR=YES'','
SET #sql = #sql + '''SELECT MSISDN FROM [sheet1$]'')'
INSERT INTO #data
EXECUTE sp_executesql #sql
DECLARE c CURSOR FOR SELECT MSISDN FROM #data

Stored procedure: how to use column as an input

I'm trying to create a simple stored procedure to count the number of empty records in my database:
CREATE PROCEDURE dbo.cnt_empty
#col NVARCHAR(10)
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
SELECT COUNT(#col) AS cnt
FROM dbo.mytable
WHERE #col = ''
END
GO
EXECUTE dbo.cnt_empty #col = N'field1' -- nvarchar(10)
I returns 0 for all the columsn I tested. What is wrong with this procedure?
Your string is not being assessed as the column name, so you are actually running "where 'field1' = ''"
You need to do something like this
set #sql = 'select #cnt = COUNT(*) from [' + #tableSchema + '].[' + #tableName +
'] where [' + #columnName + '] is not null';
-- print #sql; --uncomment for debugging
exec sp_executesql #sql, N'#cnt bigint output', #cnt = #cnt output;
Look at http://blog.hoegaerden.be/2009/02/15/script-find-all-empty-columns-in-database/ for the full script.
By doing this, your SQL statement is treating the parameter like a string, not like the name of a column. Take a look at sp_executesql. That will help you build up a SQL string and execute it.
you are matching #col (i.e. 'field1') against empty (i.e. '') in your where clause - that will never return a row.
What you want to do is declare a variable like #sql VARCHAR(500)
Then do
SET #sql = 'SELECT COUNT('+#col+') AS cnt FROM dbo.mytable'
Then try use the built in sp called sp_Executesql
http://msdn.microsoft.com/en-us/library/ms188001.aspx
This is because you are selecting the count of the variable not the count of the column.
Take a look at this article: http://www.mssqltips.com/sqlservertip/1160/execute-dynamic-sql-commands-in-sql-server/
Basically using EXEC statement or sp_executesql should be your choice.