Dynamic Table name being recognised as a column name - sql

Any reason why the dynamic schema and table name in the below script is being recognised as a column name? IF i hard code in the schema and table names outside of the dynamic script the function executes no issues.
Error = Msg 207, Level 16, State 1, Line 38
Invalid column name '55_Dataset'.
Msg 207, Level 16, State 1, Line 38
Invalid column name 'EPAPRIORITY'.
repeated for each iteration
Table example enter image description here
DECLARE #Counter INT;
DECLARE #DATASET nvarchar(50);
DECLARE #STATE nvarchar(50);
DECLARE #sql nvarchar(max);
SET #Counter = 1;
WHILE #Counter <= 10
BEGIN
SET #DATASET = (Select [DATASET] FROM [xxx].[dbo].[EPA_Geocoding_Progress] Where [INT] = #Counter)
SET #STATE = (Select [STATE] FROM [xxx].[dbo].[EPA_Geocoding_Progress] Where [INT] = #Counter)
SET #sql = '
UPDATE [xxx].[dbo].[EPA_Geocoding_Progress]
Set [Geocoded] = (Select COUNT (*) FROM [xxx].[' + #STATE + '].[' + #DATASET + '])
Where [STATE] = [' + #STATE + '] AND [DATASET] = [' + #DATASET + ']'
exec sp_executesql #sql;
SET #Counter = #Counter + 1;
END

If you will code with print like this:
declare #sql varchar(max)
declare #STATE varchar(50)
declare #DATASET varchar(50)
set #STATE = 'dbo'
set #DATASET = 'test'
Set #sql = '
UPDATE [dbo].[EPA_Geocoding_Progress]
Set [Geocoded] = (Select COUNT (*) FROM [' + #STATE + '].[' + #DATASET + '])'
print #sql;
you will see what's wrong.

SQL server Version
it seems no problem
check ; before Set
i try it:
CREATE TABLE EPA_Geocoding_Progress(
Geocoded int
);
CREATE TABLE TEST(
ID int
);
Declare #sql nvarchar(max) = ''
,#STATE nvarchar(max) = 'dbo'
,#DATASET nvarchar(max) = 'test'
Set #sql = '
UPDATE [dbo].[EPA_Geocoding_Progress]
Set [Geocoded] = (Select COUNT (*) FROM [' + #STATE + '].[' + #DATASET + '])'
select #sql
exec sp_executesql #sql; -- Run Success
DEMO SQL Fiddle

Related

Getting OUTPUT from Nested Dynamic SQL with a Remote Server

I am trying to execute some logic on a remote server using dynamic SQL, but when I set the dynamic SQL and try to call it nothing happens.. If I call the execution without making the execution dynamic it works without issue.
Not sure if what I am trying to do is allowed when passing OUTPUT values but figured I would see if anyone has any thoughts
DECLARE #sqlserver NVARCHAR(MAX) = ''
DECLARE #DBName NVARCHAR(MAX) = ''
DECLARE #parms NVARCHAR(MAX) = N'#output INT OUT', #output INT, #sql NVARCHAR(MAX) = '
;WITH DuplicateStatusCodes AS (
SELECT CodeTypeID FROM EDDSDBO.Code WHERE Name = ''Master'' OR Name = ''Unique'' OR Name = ''Duplicate''
)
SELECT ROW_NUMBER() OVER (ORDER BY CodeTypeID) RN, CodeTypeID INTO #temp
FROM DuplicateStatusCodes
GROUP BY CodeTypeID
HAVING COUNT(CodeTypeID) = 3
DECLARE #count INT = (SELECT COUNT(1) FROM #temp)
DECLARE #ctr INT = 1;
IF #count > 0
BEGIN
WHILE #ctr <= #count BEGIN
DECLARE #parms NVARCHAR(MAX) = N''#inneroutput INT OUT'';
DECLARE #inneroutput INT
DECLARE #codeartifact INT = (SELECT CodeTypeID FROM #temp WHERE RN <= 1 * #ctr and RN > 1 * (#ctr - 1))
DECLARE #duplicatestatuscheck NVARCHAR(MAX) = ''SELECT #inneroutput = COUNT(1) FROM eddsdbo.codeartifact_''+CAST(#codeartifact AS VARCHAR)+''''
EXEC sys.sp_executesql #duplicatestatuscheck, #parms, #inneroutput OUT
SELECT #output = #inneroutput
IF #inneroutput > 0
BREAK;
SET #ctr = #ctr + 1;
END
END
ELSE
BEGIN
SELECT #output = ''0''
END
'
DECLARE #linksql NVARCHAR(MAX) = '
DECLARE #sql NVARCHAR(MAX)
DECLARE #parms NVARCHAR(MAX) = N''#output INT OUT''
EXEC '+QUOTENAME(#sqlserver)+'.'+QUOTENAME(#DBName)+'.sys.sp_executesql #sql, #parms, #output = #output OUT'
--This does not work
EXEC sp_executesql #linksql, #parms, #output = #output
PRINT #output
--This works fine
EXEC [RemoteServerName].[DatabaseName].sys.sp_executesql #sql, #parms, #output = #output OUT ```
Appreciate any help
you would need to use OPENROWSET. Something like this:
DECLARE #ServerName VARCHAR(255) = '...'
,#DatabaseName VARCHAR(255) = '...'
,#Pwd VARCHAR(255) = '...'
,#UID VARCHAR(255) = '...'
,#Name VARCHAR(255) = 'Master'
DECLARE #connect varchar(max) = '''Server=' + #ServerName + ';database=' + #DatabaseName + ';Uid=' + #UID + ';Pwd=' + #Pwd + ';'''
declare #sqlstring varchar(max) = 'SET ANSI_NULLS OFF; SET ANSI_WARNINGS OFF;
SELECT CodeTypeID FROM EDDSDBO.Code WHERE Name = ''''' + #Name + ''''' '
declare #TheExecutableStr varchar(max) = '
SELECT *
FROM OPENROWSET(''SQLNCLI'', ' + #connect + ',
''' + #sqlstring + ''')'
SELECT #TheExecutableStr
--EXEC(#TheExecutableStr)
Please note you have to count single quote very diligently, hence SELECT #TheExecutableStr. It is for debugging purposes. You can view the query to be executed and actually copy/paste and execute before uncommenting last statement.
Hope it helps.
just noticed, you have sys.sp_executesql within sys.sp_executesql which might be problematic. you might need to find a way to refactor the code.

Putting 3 inputs to the Stored Procedure in SQL Server

There is a Student Table, with the column of ID and Name. However,
wanted to use the parameters in the Stored Procedure to get:
select * from Student where ID = value;
While, I used this code. Could not get the outpur. Moreover, I have
got this error message:
select * from [Student] where ID = 2 Msg 203, Level 16, State 2,
Procedure FindTblName, Line 11 [Batch Start Line 28] The name 'select
* from [Student] where ID = 2' is not a valid identifier.
create procedure FindTblName
#tblName varchar(100),
#IDName varchar(10),
#IDValue int
as
begin
declare #sql varchar(max)
set #sql = 'select * from '+ QUOTENAME(#tblName) + ' where ' + #IDName + ' = ' + convert(nvarchar(2),#IDValue)
print #sql
exec #sql
end
exec FindTblName #tblName = Student, #IDName = ID, #IDValue = 2;
IF you must do something like this then properly quote your object names, and parametrise your parameters. Then pass your object names as a nvarchar, not an an unknown "object" type:
CREATE PROC dbo.FindTblName #TblName sysname , #IDName sysname, #IDValue int AS
BEGIN
DECLARE #SQL nvarchar(MAX);
SET #SQL = N'SELECT * FROM dbo.' + QUOTENAME(#TblName) + N' WHERE ' + QUOTENAME(#IDName) + N' = #IDValue;';
EXEC sp_executesql #SQL, N'#IDValue int', #IDValue;
END;
GO
EXEC dbo.FindTblName #TblName = N'Student', #IDName = N'ID', #IDValue = 2;

How to insert varchar variable in dynamic sql query

I have a query with a select statement in a loop and at the same time I want to insert a varchar variable and selected value into a temporary table, but I get an error like:
Msg 207, Level 16, State 1, Line 2
Invalid column name 'SP419001_SID'
This SP419001_SID is the value contained in the varchar variable #dbName.
This is my query:
CREATE TABLE #tempCounter
(
dbName1 varchar(max),
counterNumber1 int
)
DECLARE
#counter INT = 1,
#max INT = 0,
#dbName VARCHAR(100),
#count INT = 0,
#SQLTEXT VARCHAR(MAX),
#counterNumber VARCHAR(10)
SELECT #max = COUNT(id) FROM #tempPnamePadd
WHILE #counter <= #max
BEGIN
SET #dbName='';
-- Do whatever you want with each row in your table variable filtering by the Id column
SELECT #dbName = name
FROM #tempPnamePadd
WHERE Id = #counter
PRINT #dbName
SET #SQLTEXT =
--SELECT distinct PN.NAME_FORMAT_CODE, NAME_BUSINESS, INDIVIDUAL_FIRST, A.ADDRESS_ID, A.ADDR_LINE_1, A.ADDR_LINE_2, A.ADDR_LINE_3, A.CITY, A.STATE
'DECLARE #dbn VARCHAR(200)
SET #dbn ='+ #dbName +';
INSERT INTO #tempCounter
(dbname1, counternumber1)
SELECT #dbn ,
(SELECT count(*)
FROM '+ #dbName +'.dbo.PRELA PR
INNER JOIN '+ #dbName +'.dbo.PNAME PN
ON PR.NAME_ID = PN.NAME_ID
INNER JOIN '+ #dbName +'.dbo.PNALK NK
ON PN.NAME_ID = NK.NAME_ID
INNER JOIN '+ #dbName +'.dbo.PADDR A
ON NK.ADDRESS_ID = A.ADDRESS_ID
WHERE (NAME_FORMAT_CODE=''B'' and NAME_BUSINESS like ''%BN'') OR
(NAME_FORMAT_CODE <> ''B'' and INDIVIDUAL_FIRST = ''John'') OR
(ADDR_LINE_1=''WELLS STREET'' AND CITY=''HOLLYWOOD'' AND STATE=''IA'')
)
'
--PRINT #SQLTEXT
EXEC (#SQLTEXT)
SET #counter = #counter + 1
END
This is very likely not the most efficient way to do this; most likely you should be using STRING_AGG or FOR XML PATH and STUFF to do this.
Anyway, you need to parametrise your variable, and quote your dynamic objects. This results in the below:
CREATE TABLE #tempCounter (dbName1 sysname,
counterNumber1 int);
DECLARE #counter int = 1,
#max int = 0,
#dbName sysname,
#count int = 0,
#SQLTEXT nvarchar(MAX),
#counterNumber varchar(10);
SELECT #max = COUNT(id)
FROM #tempPnamePadd;
WHILE #counter <= #max
BEGIN
SET #dbName = '';
-- Do whatever you want with each row in your table variable filtering by the Id column
SELECT #dbName = name
FROM #tempPnamePadd
WHERE Id = #counter;
PRINT #dbName;
SET #SQLTEXT = N'INSERT INTO #tempCounter
(dbname1, counternumber1)
SELECT #dbn ,
(SELECT count(*)
FROM ' + QUOTENAME(#dbName) + N'.dbo.PRELA PR
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PNAME PN
ON PR.NAME_ID = PN.NAME_ID
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PNALK NK
ON PN.NAME_ID = NK.NAME_ID
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PADDR A
ON NK.ADDRESS_ID = A.ADDRESS_ID
WHERE (NAME_FORMAT_CODE=''B'' and NAME_BUSINESS like ''%BN'') OR
(NAME_FORMAT_CODE <> ''B'' and INDIVIDUAL_FIRST = ''John'') OR
(ADDR_LINE_1=''WELLS STREET'' AND CITY=''HOLLYWOOD'' AND STATE=''IA'')
)
';
--PRINT #SQLTEXT
EXEC sp_executesql #SQLTEXT, N'#dbn sysname', #dbn = #dbName;
SET #counter = #counter + 1;
END;
Note I have also changed some of your data types.
You did not quote around #dbName in your dynamic query.
So instead of
SET #dbn ='SP419001_SID';
you get
SET #dbn =SP419001_SID;
Do
'DECLARE #dbn VARCHAR(200)
SET #dbn ='''+ #dbName +''';
INSERT INTO #tempCounter
...'

Change all empty strings to NULL using one query with loop. SQL

I have table with columns:
[1959], [1960], [1961] ... [2016];
All these columns are type nvarchar(255), some of these have empty strings ''. I want to change empty strings to NULL. I write query:
DECLARE #empty nvarchar(255);
SET #empty='';
DECLARE #cnt INT = 1959;
WHILE #cnt < 2017
BEGIN
declare #sql nvarchar(1000)
set #sql = 'UPDATE [HDProjEtap1Proba1].[dbo].[TESTGDP] SET [' + CAST(#cnt as nvarchar(255)) + '] = null WHERE ['+ CAST(#cnt as nvarchar(255)) +'] = ' + #empty;
EXEC(#sql);
SET #cnt = #cnt + 1;
END;
But dosn't work. Message error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '='.
Can you tell me how do it right?
#empty is empty. It doesn't represent the empty string when you concatenate it.
One simple solution is:
SET #empty = '''';
However, you can do the same thing by passing a parameter using sp_executesql. And I like that approach:
declare #cnt INT = 1959;
while #cnt < 2017
begin
declare #sql nvarchar(1000)
set #sql = 'UPDATE [HDProjEtap1Proba1].[dbo].[TESTGDP] SET [' + CAST(#cnt as nvarchar(255)) + '] = null WHERE ['+ CAST(#cnt as nvarchar(255)) +'] = #empty';
exec sp_executesql #sql, N'#empty nvarchar(255)', #empty = '';
set #cnt = #cnt + 1;
end;
Or event:
declare #cnt INT = 1959;
while #cnt < 2017
begin
declare #sql nvarchar(1000)
set #sql = '
UPDATE [HDProjEtap1Proba1].[dbo].[TESTGDP]
SET [#colname] = null
WHERE [#colname] = #empty';
set #sql = replace(#sql, '#colname', cast(#cnt as varchar(255));
exec sp_executesql #sql, N'#empty nvarchar(255)', #empty = '';
set #cnt = #cnt + 1;
end;
Notice that in this version, the SQL statement is easy to read (and hence to modify and debug). It is defined with parameters that are then subsequently replaced.

T-SQL Create Table with Dynamically Named Database with sp_executesql

I am attempting to create a table in T-SQL using sp_executesql. The name of the database containing the table is dynamic.
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = '[MyDatabase' + CAST(#ID as nvarchar(10)) + '].[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max) = N''
SELECT #CreateTable =
N'
CREATE TABLE #TableName
(
ID int
)
'
EXECUTE sp_executeSQL #CreateTable, N'#TableName nvarchar(max)', #TableName = #TableName
This script results in this error:
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near '#TableName'.
What is the best way to specify the name of the table to create dynamically based on parameters of sp_executeSQL?
You cannot pass Tablename as a parameter even we using sp_executesql procedure. You have to build you own dynamic sql query
SELECT #CreateTable =
N'
CREATE TABLE ' + #TableName + '
(
ID int
)
'
Exec sp_executesql #CreateTable
When you are passing the table name as a parameter to sp_executesql, it treats it as a literal string, to make it treat it as an object name try something like this......
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max);
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable
EDIT
It is good practice to check if an object already exists before you try to create it.
You can check if the object already exists and drop it and then create the new one, you code should look something like.....
DECLARE #ID int = 1031460
DECLARE #TableName nvarchar(max) = QUOTENAME('MyDatabase' + CAST(#ID as nvarchar(10)))
+ '.[dbo].[MyTable]'
DECLARE #CreateTable nvarchar(max), #DropTable nvarchar(max);
-- Drop table if already exists
SET #DropTable = N' IF OBJECT_ID('''+ #TableName +''') IS NOT NULL '
+ N' DROP TABLE ' + #TableName
Exec sp_executesql #DropTable
SET #CreateTable = N' CREATE TABLE ' + #TableName
+ N' (
ID int
)'
Exec sp_executesql #CreateTable