Issue with executing SQL Procedure - sql-server-2008

I have an issue executing below piece of code:
DECLARE #CUTOFFDAYS_i INT
DECLARE #SQL NVARCHAR(MAX)
DECLARE #SQL1 NVARCHAR(MAX)
SET #CUTOFFDAYS_i = 750
CREATE TABLE #TMP(
EMPID INT,
EMPNAME VARCHAR(35)
)
SET #SQL = 'SELECT EMPID, EMPNAME INTO #TMP FROM EMPDB..EMPTABLE
WHERE DATEDIFF(DAY, CREATEDDATE, GETDATE()) > #CUTOFFDAYS_i
AND ERRORMESSAGE = '''''
SET #SQL1 = 'SELECT * FROM #TMP'
EXEC SP_EXECUTESQL #SQL
EXEC SP_EXECUTESQL #SQL1
Even then I don't get any result upon
SELECT * FROM #TMP

Your usage of # is wrong. #TMP is a temporary table that's only availble to the connection that makes it. I think what you're looking for is ##TMP.
But if you need such a temporary table, I would advice you to make a proper table instead as it's much easier to manage and keep track off and keeps less strain on your tempdb.

First of all you should declare #SQL and #SQL1 as a fixed maximum length varchar not exceeded 8000 (I guess it's not the restriction for the current MS SQL version???):
DECLARE #SQL NVARCHAR(1000)
DECLARE #SQL1 NVARCHAR(1000)
Then you shouldn't use () when call SP_EXECUTESQL
EXEC SP_EXECUTESQL #SQL
EXEC SP_EXECUTESQL #SQL1
And the finally you should use global temp table ##TMP in SP_EXECUTESQL for INSERT and then SELECT or you should declare local #Tmp table before the first SP_EXECUTESQL call
DECLARE #CUTOFFDAYS_i INT
DECLARE #SQL NVARCHAR(1000)
DECLARE #SQL1 NVARCHAR(1000)
SET #CUTOFFDAYS_i = 750
SET #SQL = 'SELECT EMPID, EMPNAME INTO ##TMP FROM EMPDB..EMPTABLE
WHERE DATEDIFF(DAY, CREATEDDATE, GETDATE()) > #CUTOFFDAYS_i
AND ERRORMESSAGE = '''''
SET #SQL1 = 'SELECT * FROM ##TMP'
EXEC SP_EXECUTESQL #SQL
EXEC SP_EXECUTESQL #SQL1

Related

How to Update values in sql by Muliple Column name in Sql

I want add values to multiple columns
ALTER PROCEDURE DynamicInsertQuery
#ColumnName VARCHAR(MAX),
#RiD VARCHAR(50)
AS
BEGIN
DECLARE #DynamicQuery NVARCHAR(MAX)
SET #DynamicQuery = 'UPDATE tbl_route_info SET ('+ #ColumnName +') = (1) WHERE RouteId=('+#RiD+')'
EXEC(#DynamicQuery)
END
This is the code I tried.
I run this procedure like this
DynamicInsertQuery '(1,2)','10'
I suspect you want something like this:
ALTER PROCEDURE DynamicInsertQuery (
#ColumnName VARCHAR(MAX),
#RiD VARCHAR(50)
) AS
BEGIN
DECLARE #DynamicQuery NVARCHAR(MAX);
SET #DynamicQuery = 'update tbl_route_into set #ColumnName = 1 where RouteId = #RiD';
SET #DynamicQuery = REPLACE(#DynamicQuery, '#ColumnName', #ColumnName);
EXEC sp_executesql #DynamicQuery, N'#RiD VARCHAR(50)', #RiD = #RiD;
END;
Notes:
You have too many parentheses in your version.
If you are learning to use dynamic SQL, then learn sp_executesql -- and how to use it to pass parameters.
You cannot pass names of things (columns, tables, etc.) as parameters, so that has to be placed directly in the string.
You can pass values into the string, such as #RiD.

dynamic query returning parameter giving hard time

I have the following SQL:
DECLARE #SQL NVARCHAR(500)
DECLARE #Count INT
SET #SQL = 'SELECT #Count = COUNT(*) FROM customers WHERE lastname = ''alex'''
print #sql
EXECUTE sp_executesql #SQL, N'#Count int OUTPUT'
SELECT #Count
When I run it, I get following error. Any idea what I am doing wrong?
Msg 8178, Level 16, State 1, Line 1
The parameterized query '(#Count int OUTPUT)SELECT #Count = COUNT(*) FROM customers WHERE ' expects the parameter '#Count', which was not supplied.
You missed to supply #Count parameter as a part of sp_executesql call (note that in this case it should be marked OUTPUT as well):
...
EXECUTE sp_executesql #SQL, N'#Count int OUTPUT', #Count OUTPUT
SELECT #Count
The second pararmeter in the sp_executesql call is the query parameters definition, or so called formal parameters (in your case there is single parameter N'#Count int OUTPUT'). If query is parameterized, then what should go after (the third and subsequent parameters) are so called actual parameters.
Below samples may explain better:
-- sample query #1
-- will fail, because of query is pararmeterized,
-- and actual pararmeter is not provided
EXEC sp_executesql N'SELECT #Num', N'#Num int';
-- sample query #2
-- formal parameter is #Num of type int
-- actual parameter is literal constant 153
EXEC sp_executesql N'SELECT #Num', N'#Num int', 153;
-- sample query #3
-- formal parameter is #Num of type int
-- actual parameter is variable #p
DECLARE #p int;
SET #p = 1;
EXEC sp_executesql N'SELECT #Num', N'#Num int', #p;
-- sample query #4
DECLARE #p int;
SET #p = 15;
EXEC sp_executesql N'SELECT #Num=#Num*2', N'#Num int output', #p output
select #p;

Transform Dynamic statement from SQL-Server into Mysql

Can anybody help me to find a mysql corespondent to the following MS SQL syntax?
CREATE PROCEDURE testsp #COLUMN_NAME VARCHAR(20), #COLUMN_VALUE VARCHAR(20)
AS
DECLARE #SQL VARCHAR(40)
SET #SQL = 'UPDATE TableX set ''+#COLUMN_NAME+ ''=''+#COLUMN_VALUE+'' '
PRINT (#SQL)
EXEC (#SQL)
Is it possible to translate this code into Mysql?
Thanks!
CREATE PROCEDURE testsp (COLUMN_NAME VARCHAR(20), COLUMN_VALUE VARCHAR(20))
BEGIN
SET #SQL_COMMAND = CONCAT('UPDATE TableX SET ', COLUMN_NAME, ' = ?');
SELECT #SQL_COMMAND; /* prints the command */
PREPARE SQL_STMT FROM #SQL_COMMAND;
EXECUTE SQL_STMT USING COLUMN_VALUE;
DEALLOCATE SQL_STMT;
END

dynamic sql error: 'CREATE TRIGGER' must be the first statement in a query batch

As part of some administrative tasks, we have many tables that each need a trigger created. The trigger will set a flag and the date in the Audit database when an object has been modified. For simplicity, I have a table with all the objects that need triggers created.
I am trying to generate some dynamic sql to do this for each object, but I am getting this error:
'CREATE TRIGGER' must be the first statement in a query batch.
Here is the code to generate the sql.
CREATE PROCEDURE [spCreateTableTriggers]
AS
BEGIN
DECLARE #dbname varchar(50),
#schemaname varchar(50),
#objname varchar(150),
#objtype varchar(150),
#sql nvarchar(max),
#CRLF varchar(2)
SET #CRLF = CHAR(13) + CHAR(10);
DECLARE ObjectCursor CURSOR FOR
SELECT DatabaseName,SchemaName,ObjectName
FROM Audit.dbo.ObjectUpdates;
SET NOCOUNT ON;
OPEN ObjectCursor ;
FETCH NEXT FROM ObjectCursor
INTO #dbname,#schemaname,#objname;
WHILE ##FETCH_STATUS=0
BEGIN
SET #sql = N'USE '+QUOTENAME(#dbname)+'; '
SET #sql = #sql + N'IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'''+QUOTENAME(#schemaname)+'.[Tiud_'+#objname+'_AuditObjectUpdates]'')) '
SET #sql = #sql + N'BEGIN DROP TRIGGER '+QUOTENAME(#schemaname)+'.[Tiud_'+#objname+'_AuditObjectUpdates]; END; '+#CRLF
SET #sql = #sql + N'CREATE TRIGGER '+QUOTENAME(#schemaname)+'.[Tiud_'+#objname+'_AuditObjectUpdates] '+#CRLF
SET #sql = #sql + N' ON '+QUOTENAME(#schemaname)+'.['+#objname+'] '+#CRLF
SET #sql = #sql + N' AFTER INSERT,DELETE,UPDATE'+#CRLF
SET #sql = #sql + N'AS '+#CRLF
SET #sql = #sql + N'IF EXISTS(SELECT * FROM Audit.dbo.ObjectUpdates WHERE DatabaseName = '''+#dbname+''' AND ObjectName = '''+#objname+''' AND RequiresUpdate=0'+#CRLF
SET #sql = #sql + N'BEGIN'+#CRLF
SET #sql = #sql + N' SET NOCOUNT ON;'+#CRLF
SET #sql = #sql + N' UPDATE Audit.dbo.ObjectUpdates'+#CRLF
SET #sql = #sql + N' SET RequiresUpdate = 1'+#CRLF
SET #sql = #sql + N' WHERE DatabaseName = '''+#dbname+''' '+#CRLF
SET #sql = #sql + N' AND ObjectName = '''+#objname+''' '+#CRLF
SET #sql = #sql + N'END' +#CRLF
SET #sql = #sql + N'ELSE' +#CRLF
SET #sql = #sql + N'BEGIN' +#CRLF
SET #sql = #sql + N' SET NOCOUNT ON;' +#CRLF
SET #sql = #sql + #CRLF
SET #sql = #sql + N' -- Update ''SourceLastUpdated'' date.'+#CRLF
SET #sql = #sql + N' UPDATE Audit.dbo.ObjectUpdates'+#CRLF
SET #sql = #sql + N' SET SourceLastUpdated = GETDATE() '+#CRLF
SET #sql = #sql + N' WHERE DatabaseName = '''+#dbname+''' '+#CRLF
SET #sql = #sql + N' AND ObjectName = '''+#objname+''' '+#CRLF
SET #sql = #sql + N'END; '+#CRLF
--PRINT(#sql);
EXEC sp_executesql #sql;
FETCH NEXT FROM ObjectCursor
INTO #dbname,#schemaname,#objname;
END
CLOSE ObjectCursor ;
DEALLOCATE ObjectCursor ;
END
If I use PRINT and paste the code to a new query window, the code executes without any problem.
I have removed the GO statements as this was also giving errors.
What am I missing?
Why am I getting an error using EXEC(#sql); or even EXEC sp_executesql #sql;?
Is this something to do with the context within EXEC()?
Many thanks for any help.
If you use SSMS (or other similar tool) to run the code produced by this script, you will get exactly the same error. It could run all right when you inserted batch delimiters (GO), but now that you don't, you'll face the same issue in SSMS too.
On the other hand, the reason why you cannot put GO in your dynamic scripts is because GO isn't a SQL statement, it's merely a delimiter recognised by SSMS and some other tools. Probably you are already aware of that.
Anyway, the point of GO is for the tool to know that the code should be split and its parts run separately. And that, separately, is what you should do in your code as well.
So, you have these options:
insert EXEC sp_execute #sql just after the part that drops the trigger, then reset the value of #sql to then store and run the definition part in its turn;
use two variables, #sql1 and #sql2, store the IF EXISTS/DROP part into #sql1, the CREATE TRIGGER one into #sql2, then run both scripts (again, separately).
But then, as you've already found out, you'll face another issue: you cannot create a trigger in another database without running the statement in the context of that database.
Now, there are 2 ways of providing the necessary context:
1) use a USE statement;
2) run the statement(s) as a dynamic query using EXEC targetdatabase..sp_executesql N'…'.
Obviously, the first option isn't going to work here: we cannot add USE … before CREATE TRIGGER, because the latter must be the only statement in the batch.
The second option can be used, but it will require an additional layer of dynamicity (not sure if it's a word). It's because the database name is a parameter here and so we need to run EXEC targetdatabase..sp_executesql N'…' as a dynamic script, and since the actual script to run is itself supposed to be a dynamic script, it, therefore, will be nested twice.
So, before the (second) EXEC sp_executesql #sql; line add the following:
SET #sql = N'EXEC ' + #dbname + '..sp_executesql N'''
+ REPLACE(#sql, '''', '''''') + '''';
As you can see, to integrate the contents of #sql as a nested dynamic script properly, they must be enclosed in single quotes. For the same reason, every single quotation mark in #sql must be doubled (e.g. using the REPLACE() function, as in the above statement).
a trigger creation must be done on its own execution batch. You are inside a procedure so you wont be able to create it.
I suggest adding the #sql into a temp table and then once the proc is finish generating all of the statements, loop this temp table to execute them and create the triggers
This approach is a much better approach when using dynamic sql within dynamic sql - side effect: no need to replace quotes and a like:
DECLARE
#originalsql NVARCHAR(4000) = N' ..... '
, #stmt NVARCHAR(200) = 'otherdatabase.dbo.sp_executesql #stmt = #sql'
, #params NVARCHAR(200) = '#sql NVARCHAR(4000)'
EXECUTE sp_executesql #stmt=#stmt, #params=#params, #sql = #originalsql

SQL Server: Can you help me with this query?

I want to run a diagnostic report on our SQL Server 2008 database server.
I am looping through all of the databases, and then for each database, I want to look at each table. But, when I go to look at each table (with tbl_cursor), it always picks up the tables in the database 'master'.
I think it's because of my tbl_cursor selection :
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
How do I fix this?
Here's the entire code:
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #db_cursor VARCHAR(100)
DECLARE database_cursor CURSOR FOR
SELECT name FROM sys.databases where name<>N'master'
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #db_cursor
WHILE ##Fetch_status = 0
BEGIN
PRINT #db_cursor
SET #table_count = 0
DECLARE #table_cursor VARCHAR(100)
DECLARE tbl_cursor CURSOR FOR
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor INTO #table_cursor
WHILE ##Fetch_status = 0
BEGIN
DECLARE #table_cmd NVARCHAR(255)
SET #table_cmd = N'IF NOT EXISTS( SELECT TOP(1) * FROM ' + #table_cursor + ') PRINT N'' Table ''''' + #table_cursor + ''''' is empty'' '
--PRINT #table_cmd --debug
EXEC sp_executesql #table_cmd
SET #table_count = #table_count + 1
FETCH NEXT FROM tbl_cursor INTO #table_cursor
END
CLOSE tbl_cursor
DEALLOCATE tbl_cursor
PRINT #db_cursor + N' Total Tables : ' + CAST( #table_count as varchar(2) )
PRINT N'' -- print another blank line
SET #table_count = 0
FETCH NEXT FROM database_cursor INTO #db_cursor
END
CLOSE database_cursor
DEALLOCATE database_cursor
SET NOCOUNT OFF
The problem is because you're actually always running the INFORMATION_SCHEMA.TABLES query under the master db context.
You'd need to convert the tbl_cursor block into dynamic SQL in order to fully qualify the query with the DB name.
e.g.
SELECT table_name FROM YourDatabase.INFORMATION_SCHEMA.TABLES WHERE....
is essentially what you need to be executing for that cursor.
It's easier to use table variables so you can add rows to #tablist using another dynamic SQL statement
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #dblist TABLE (DBName VARCHAR(100))
DECLARE #tablist TABLE (TableName VARCHAR(100))
DECLARE #dbname varchar(100), #tabname varchar(100)
INSERT #dblist
SELECT name FROM sys.databases where name<>N'master'
SELECT TOP 1 #dbname = DBName FROM #dblist
WHILE ##ROWCOUNT <> 0
BEGIN
INSERT #tablist (tableName)
EXEC ('SELECT table_name FROM ' + #dbname + '.information_schema.tables WHERE table_type = ''base table'' ')
SELECT TOP 1 #tabname = tableName FROM #tablist
WHILE ##ROWCOUNT <> 0
BEGIN
--do my stuff
DELETE #tablist WHERE tableName = #tabname
SELECT TOP 1 #tabname = tableName FROM #tablist
END
DELETE #dblist WHERE DBName = #dbname
SELECT TOP 1 #dbname = DBName FROM #dblist
END
You might have to create dynamic SQL. because information_schema will fetch objects only from the current active database against which you are running this query.
you can try sys.objects