Can I execute rows returned by select? - sql

I'm wondering if I can make a script to execute returned rows. I have 2 rows returned by select designed by me and it looks like
alter table zamestnanci drop DF__zamestnan__datum__2E1BDC42 go sp_bindefault 'abc','zamestnanci.datum_pridania'
I'm droping default and making binded default.
Thanks for help.

If you can run all of your statements in a single batch, and they are already correctly terminated with a semicolon, you could build a single SQL string and execute the whole thing at once.
DECLARE #sql NVARCHAR(MAX) = (SELECT SomeColumn
FROM [Table]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
EXECUTE sp_executesql #sql;
Of if you wanted to execute the statements one by one you could use a cursor:
DECLARE sqlCursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT SomeStatement
FROM [Table];
DECLARE #sql NVARCHAR(MAX);
OPEN sqlCursor;
FETCH NEXT FROM sqlCursor INTO #sql;
WHILE ##FETCH_STATUS = 0
BEGIN
EXECUTE sp_executesql #sql;
FETCH NEXT FROM sqlCursor INTO #sql;
END

Related

##ROWCOUNT shows as 0 when deleting using dynamic query 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());

Execution of Stored Procedure for every row of table using string variable

I want to execute a stored procedure for every row of a table without using cursor or loop.
Lets say my table dbo.User contains name for following users:
create table dbo.test_User (
Name varchar(50) )
insert into dbo.test_User
values ('Deepanshu'),('IronMan'),('DoctorStrange')
I created a stored procedure which will only display the name of users (Although my real stored procedure has to do a lot of stuff)
create procedure dbo.usp_TestSP ( #name varchar(50) )
as
BEGIN
select #name
END
Now i want the stored procedure to run for all names like:
EXEC dbo.usp_TestSP 'Deepanshu';
EXEC dbo.usp_TestSP 'IronMan';
EXEC dbo.usp_TestSP 'DoctorStrange';
I created a string variable #Query which will store the t-sql query i want to execute
DECLARE #Query varchar(200);
select #Query=STUFF(
(select 'dbo.usp_TestSP '''+Name+''';'
from dbo.test_user
FOR XML PATH('')
),1,0,''
)
EXEC #Query
When i try to execute this #Query it gives me an error saying:
Could not find server 'dbo' in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.
How can i execute the stored procedure for all the names using the string variable #Query?
You could use CURSOR to simulate FOR-EACH with stored procedure call:
DECLARE db_cursor CURSOR LOCAL FAST_FORWARD FOR
SELECT *FROM dbo.tesT_User;
DECLARE #name NVARCHAR(50);
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC dbo.usp_TestSP #name = #name;
FETCH NEXT FROM db_cursor INTO #name;
END
CLOSE db_cursor;
DEALLOCATE db_cursor;
DBFiddle Demo
Warning:
If it would be simple function then CROSS/OUTER APPLY is a way to go.
SELECT *
FROM dbo.Test_User tu
OUTER APPLY (SELECT dbo.usp_TestSP(tu.name)) s(a);
DBFiddle Demo2
EDIT
i want to execute this without cursor or loop, using the same logic as displayed above
DECLARE #x NVARCHAR(MAX) =
(SELECT string_agg(FORMATMESSAGE('EXEC dbo.usp_TestSP #name=''%s'';', name)
,CHAR(13)) AS r FROM dbo.test_User);
PRINT #x;
EXEC(#x);
DBFiddle Demo3
And finally your code:
DECLARE #Query varchar(MAX);
select #Query=STUFF((SELECT 'EXEC dbo.usp_TestSP #name=' +QUOTENAME(Name,'''')
+ ';' from dbo.test_user
FOR XML PATH('')),1,0,'');
EXEC(#Query);
DBFiddle Demo4
What I did:
using semicolons (;) it's very good practice
changed datatype to VARCHAR(MAX)
added EXEC inside SQL
wrapped #Query with ()

Query that will apply to EVERY SQL Server database

I'm testing a drop database query for all databases that begin with a specific prefix. However, because that can easily lead to horrific things I'm taking my drop database query
declare #dbname nvarchar (200);
declare #query nvarchar (max);
DECLARE db_cursor CURSOR FOR
select name from sys.databases
where name like 'PREFIX%'
Open db_cursor
fetch next from db_cursor into #dbname
while ##FETCH_STATUS = 0
BEGIN
set #query = 'Drop Database ['+ #dbname + ']'
Exec(#query)
FETCH NEXT FROM db_cursor INTO #dbname
END
Close db_cursor
deallocate db_cursor
and want to change the Drop Database part to something that is less scary.
So MAIN QUESTION is there a simple SQL query that I could put in there that would always apply to any SQL Server database? So I know that this query will only affect the databases I want it to before switching it back to Drop Database?
EDIT: Better yet, a query that will return the names of the databases.
Like select name from sys.databases but one that will work with ['+ #dbname + '] to return only the names of databases with that prefix to ensure that this query affects the appropriate databases.
Instead of Exec(#query), just call PRINT #query. That will show you the SQL that you intend to run.
PRINT Documentation
First of all just execute the following query and it will tell you what databases will it bring forward in the rest of the code
select name from sys.databases
where name like 'PREFIX%'
Finally add a PRINT statement to see the final DROP DATABASE statements dynamically build inside the cursor.
Some minor improvement in your code:
declare #dbname SYSNAME;
declare #query nvarchar (max);
DECLARE db_cursor CURSOR LOCAL FORWARD_ONLY FOR
select name from sys.databases
where name like 'PREFIX%'
Open db_cursor
fetch next from db_cursor into #dbname
while (##FETCH_STATUS = 0)
BEGIN
set #query = 'Drop Database '+ QUOTENAME(#dbname)
--Exec sp_executesql #query --<-- For execution
-- PRINT #query --<-- For debugging
FETCH NEXT FROM db_cursor INTO #dbname
END
Close db_cursor
deallocate db_cursor

Execute dynamic select query stored in a table

I have stored select statements in a table column named RuleSql. In the future the table size will go large, so how can I execute all the stored select statements at the same time to get the result?
I have used:
EXEC sp_executesql
But it is not helpful for me.
It's very poor practice storing SQL code in a table. Have you looked at views, stored procedures or inline table-valued functions?
Anyway, to execute the stored SQL in a table you would do something like this....
DECLARE #Sql NVARCHAR(MAX);
SELECT TOP 1 #Sql = RuleSql
FROM TableName --<-- table where sql is stored
WHERE <Some Condition>
Exec sp_executesql #Sql
Just saw your edit. To execute all the queries at once you would use a cursor something like.....
DECLARE #Sql NVARCHAR(MAX);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
SELECT RuleSql
FROM TableName --<-- table where sql is stored
OPEN Cur
FETCH NEXT FROM Cur INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
Exec sp_executesql #Sql
FETCH NEXT FROM Cur INTO #Sql
END
CLOSE Cur
DEALLOCATE Cur;
If you want this same information but for the whole database (all tables of a database) and create a table wit results you can use followin

How can I set a cursor to a dynamically created SQL query in stored procedure

I want to create a dynamic command using #sqlQuery variable. I've also declared a cursor (example: #myCursor). How can I "SET #myCursor = CURSOR FOR #sqlQuery". The syntax I just noted doesn't work. I am using SQL 2000.
You should take a look at The Curse and Blessings of Dynamic SQL
You can do it using sp_executesql. Just be sure to open the cursor within the dynamic SQL.
CREATE PROCEDURE OpenCursor (#query nvarchar(max), #cur cursor VARYING OUTPUT)
AS
DECLARE #sql nvarchar(max)
SET #sql = N'SET #cur = CURSOR STATIC FOR ' + #query + '; OPEN #cur'
EXEC sp_executesql #sql, N'#cur cursor OUTPUT', #cur OUTPUT
GO
DECLARE #cur cursor
EXEC OpenCursor 'SELECT * FROM sysobjects', #cur OUTPUT
FETCH NEXT FROM #cur