##ROWCOUNT shows as 0 when deleting using dynamic query SQL - sql

I am facing a trouble when using dynamic query and when trying to get the number of deleted records using ##ROWCOUNT
Here is my QUery
declare #query nvarchar(max)='delete from '+ #table_name + ' where kfh_id=' + cast(#kfh_id as varchar)
--print #query
exec (#query)
print #query
insert into tbl_cleanup_log (tablename,kfh_id,rows_affected,remark,deletiontime)
values(#table_name,#kfh_id,##ROWCOUNT,#query,getdate())
Here after the dyanimic delete query (inside my cursor) I am trying to store the number of deleted records into another table using ##ROWCOUNT. But it shows as 0.
I didnt understand what I did wrong.
My SQL version is 2012

##ROWCOUNT is working correctly. From the documentation:
Returns the number of rows affected by the last statement. If the number of rows is more than 2 billion, use ROWCOUNT_BIG.
The prior statement to the statement you use ##ROWCOUNT in is print #query and that returns no rows, and hence ##ROWCOUNT returns 0.
To fix this I would suggest PRINTing your dynamic statement first. Also you need to fix your dynamic statement so it isn't open to injection. Don't use the syntax EXEC (#SQL), use a parametrised call to sys.sp_executesql and ensure you properly delimit identify your dynamic object with QUOTENAME:
DECLARE #table_name sysname,
#kfh_id int; --Guessed data type
DECLARE #query nvarchar(MAX) = N'delete from dbo.' + QUOTENAME(#table_name) + N' where kfh_id= #kfh_id;'; --Schema is guessed.
PRINT #query;
EXEC sys.sp_executesql #query, N'#kfh_id int', #kfh_id; --Reminder, guessed #kfh_id data type
INSERT INTO tbl_cleanup_log (tablename,
kfh_id,
rows_affected,
remark,
deletiontime)
VALUES (#table_name, #kfh_id, ##ROWCOUNT, #query, GETDATE());

##ROWCOUNT should be the used immediately after statement, here the PRINT is between and it's changing the result:
DECLARE #row_cnt INT;
EXEC (#query);
SET #row_cnt = ##ROWCOUNT;
print #query;
insert into tbl_cleanup_log (tablename,kfh_id,rows_affected,remark,deletiontime)
values(#table_name,#kfh_id,#row_cnt ,#query,getdate());

Related

EXEC sp_executesql will work with Integers but not VarChars

I'm using EXEC sp_executesql for a dynamic query in SQL Server 2017.
I've tried various testing scenarios, and I can get results in my query (for other parameters) as long as the values passed in are Integers. So, that means, Location and Department testing works. However, I can't figure out if there's something I need to do differently for when I'm sending a NVARCHAR or DateTime.
Here's my stored procedure, with the NVARCHAR param. Do you see anything I'm doing wrong?
(
#tktitle NVARCHAR(200)
)
AS
BEGIN
Declare #SQL NVARCHAR(MAX)
Set #SQL = 'SELECT timekeep.tkinit, timekeep.tkfirst, timekeep.tklast,
timekeep.tkemdate, timekeep.tktitle, timekeep.tkloc, timekeep.tkdept
FROM abc.xyz'
IF #tktitle IS NOT NULL
Select #SQL = #SQL + 'AND ([tktitle] = #tktitle)'
EXEC sp_executesql #SQL, N'#tktitle varchar', #tktitle
END
I can identify at least three issues:
You need to specify a length for varchar when passing it as a parameter.
You also need a space before the AND and the AND should be a WHERE.
You need to assign the parameter in the execute call.
So:
IF #tktitle IS NOT NULL
Select #SQL = #SQL + ' WHERE ([tktitle] = #tktitle)';
-------------------------^ separator
EXEC sp_executesql #SQL, N'#tktitle varchar(200)', #tktitle=#tktitle;

EXEC sp_executesql #sql limitation

I am having problem with executing dynamic SQL Server code.
I have an insert into temp table and the number of chars is more than 4000.
I tried to split into two variables and then concatenated them but problem is
EXEC sp_executesql #sql,
N'#DimStartDate int, #DimEndDate bigint',
#DimStartDate, #DimEndDate;
I found on net that EXEC(#sql1+#sql2) is solution but I really need input parameters. How can I solve this?
I have dealt with a similar issue before, like below. Basically you need to separate your main query into pieces, then combine them in the end and use sp_EXECUTESQL to run your dynamic query.
DECLARE #SQL_Part1 varchar(4000);
DECLARE #SQL_Part2 varchar(4000);
DECLARE #SQL_Part3 varchar(4000);
DECLARE #SQL_Part4 varchar(4000);
DECLARE #SQL_Part5 varchar(4000);
DECLARE #SQL_FullQuery nvarchar(MAX);
.. set your queries...
SET #SQL_FullQuery = CAST(#SQL_Part1 + #SQL_Part2 + #SQL_Part3 + #SQL_Part4 + #SQL_Part5 as nvarchar(MAX));
EXEC sp_EXECUTESQL #SQL_FullQuery;
I have had no problem with sp_executesql on strings very long strings. You simply need to declare the query to be long enough:
declare #sql nvarchar(max);
You can have an error inserting into a table if the row length is too long for the table. That would have nothing to do with the dynamic statement. The maximum length of a row is limited in SQL Server -- although you can use long strings and blobs to work around that.
Not sure exactly where the problem is. SQL Server will happily execute more than 4,000 characters, so your SQL must be getting truncated somewhere else. Here is an example where I've manually built up a batch that is more than 4,000 characters total so you can see that all three SELECT statements run and if you copy and paste the middle result you'll see it has the y at the end:
DECLARE #sql nvarchar(max) = N'SELECT 1;'
+ N'SELECT ''' + CONVERT(nvarchar(max), REPLICATE('x', 4096)) + N'y'';';
+ N'SELECT 2;';
EXEC sys.sp_executesql #sql;
Results:

Run SQL statements that are saved in a table

I have a table dbo.usp_table with the following records:
EXEC USP_one
EXEC USP_two
EXEC USP_three
I want to execute these 3 or more stored procedures.
I could do this with a cursor.
However is there an easier way to solve this?
You can try this:
DECLARE #SQL NVARCHAR(MAX) = '';
SELECT #SQL = #SQL + YourColumn + '; '
FROM YourTable;
EXECUTE sp_executesql #SQL;
Where the column YourColumn contains the SQL command.
Declare a variable and store all the values(exec procedurename) inside the table into that variable appended with space at the end and execute the variable. Try this
declare #exec_proc nvarchar(max)=''
select #exec_proc += proc_name+' ' from dbo.usp_table
-- print #exec_proc
exec sp_executesql #exec_proc
Note : This will not work if your procedure accepts parameters

Declare variable and use in query

Please consider the following
declare #MyField varchar(255);
set #MyField = 'MyDatabaseField';
select distinct Table.#MyField
from Table
This results in the error Incorrect syntax near #MyField. Then I tried:
select distinct Table.['+#MyField+']
from Table
However, this results in an Incorrect column name error.
How do I correctly use the #MyField in this query? I'm on SQL Server 2008.
Please try executing by building a string.
declare #MyField varchar(255);
set #MyField = 'MyDatabaseField';
exec ('select distinct Table.'+#MyField+' from Table')
Refer sp_executesql (Transact-SQL), Using sp_executesql
You should use dynamic SQL to achieve that. You can use sp_executesql stored proc to do that. Please not that I changed your variable declaration to **N**VARCHAR.
declare #MyField nvarchar(255)
set #MyField = N'MyDatabaseField'
declare #sql nvarchar(max) = N'select distinct ' + #MyField + N' from TableName'
exec sp_executesql #sql

Why SCOPE_IDENTITY returns NULL?

I have stored procedure that take #dbName and insert record in that DB.
I want to get the id of the last inserted record. SCOPE_IDENTITY() returns NULL and ##IDENTITY returns correct id, why it happens? As I read, so it's better to use SCOPE_IDENTITY() in case there are some triggers on the table.
Can I use IDENT_CURRENT? Does it return the id in the scope of the table, regardless of trigger?
So what is the problem and what to use?
EDITED
DECALRE #dbName nvarchar(50) = 'Site'
DECLARE #newId int
DECLARE #sql nvarchar(max)
SET #sql = N'INSERT INTO ' + quotename(#dbName) + N'..myTbl(IsDefault) ' +
N'VALUES(0)'
EXEC sp_executesql #sql
SET #newId = SCOPE_IDENTITY()
Like Oded says, the problem is that you're asking for the identity before you execute the insert.
As a solution, it's best to run scope_identity as close to the insert as you can. By using sp_executesql with an output parameter, you can run scope_identity as part of the dynamic SQL statement:
SET #sql = N'INSERT INTO ' + quotename(#dbName) + N'..myTbl(IsDefault) ' +
N'VALUES(0) ' +
N'SET #newId = SCOPE_IDENTITY()'
EXEC sp_executesql #sql, N'#newId int output', #newId output
Here's an example at SE Data showing that scope_identity should be inside the sp_executesql.