I have a stored procedure which is supposed to truncate specific tables based on their names.
Tables which do not have "A" as the first character in their names must be truncated.
The problem is that this code doesn't work! Please help
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[return_data]
#DBName varchar(100)
AS
declare #i int, #tc int
set #i = 1
DECLARE #sql NVARCHAR(100)
SET #sql = 'USE ' + QUOTENAME(#DBName) + '
DECLARE cur CURSOR FOR SELECT TABLE_NAME FROM information_schema.tables
'
EXECUTE(#sql)
OPEN cur
declare #tbl_name nvarchar(100)
declare #first_char char(1)
FETCH NEXT FROM cur INTO #tbl_name
WHILE ##FETCH_STATUS = 0 BEGIN
set #first_char = SUBSTRING(#tbl_name, 0, 1)
set #sql = 'DELETE FROM ' + QUOTENAME(#tbl_name)
if (#first_char != 'A')
begin
EXECUTE(#sql)
end
FETCH NEXT FROM cur INTO #tbl_name
END
CLOSE cur
DEALLOCATE cur
return
The problem is with the SUBSTRING function. The starting position is a 1-based ordinal, not 0-based. Try
SUBSTRING(#tbl_name, 1, 1)
or
LEFT(#tbl_name, 1)
Also, I suggest you make it a habit of schema-qualifying table names to avoid ambiguity.
Related
I have a table with 2 columns QueryName and Query. I am trying the execute the queries stored in the Query column of the table.
I want to display anything that has more than record count of zero, we need to print to output with queryname and count. I am using the following cursor, I was able to display rowcount but anyone please suggest me how to display the QueryName:
DECLARE #Sql NVARCHAR(MAX);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
(SELECT Query
FROM VWLetterTYB )
OPEN Cur
FETCH NEXT FROM Cur INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
--Exec sp_executesql #Sql
EXEC ('SELECT COUNT(*) AS Rowcounts FROM (' + #sql + ') AS t HAVING COUNT(*) > 0 ')
FETCH NEXT FROM Cur INTO #Sql
END
CLOSE Cur
DEALLOCATE Cur;
DECLARE #Sql NVARCHAR(MAX);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
(SELECT Query
FROM VWLetterTYB )
OPEN Cur
FETCH NEXT FROM Cur INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
--Exec sp_executesql #Sql
EXEC ('SELECT [sql] = ''' + #Sql + ''', COUNT(*) AS Rowcounts FROM (' + #sql + ') AS t HAVING COUNT(*) > 0 ')
FETCH NEXT FROM Cur INTO #Sql
END
CLOSE Cur
DEALLOCATE Cur;
If I understand you correctly, you have two fields in the table but you only managed to get one using the cursor. In that case, the solution is easy, you can fetch more than one value with a cursor (each one to a different variable), then just put that value in the dynamic SELECT:
DECLARE #Sql NVARCHAR(MAX), #QueryName NVARCHAR(MAX);
DECLARE Cur CURSOR LOCAL FAST_FORWARD FOR
(SELECT Query, QueryName
FROM VWLetterTYB )
OPEN Cur
-- variables are filled in the order used in the SELECT (first column to first variable,
-- second column to second variable, etc.)
FETCH NEXT FROM Cur INTO #Sql, #QueryName
WHILE (##FETCH_STATUS = 0)
BEGIN
-- when using single quotes inside a string you have to double it
EXEC ('SELECT '''+ #QueryName+''' AS QueryName, COUNT(*) AS Rowcounts FROM (' + #sql + ') AS t HAVING COUNT(*) > 0 ')
FETCH NEXT FROM Cur INTO #Sql, #QueryName
END
CLOSE Cur
DEALLOCATE Cur;
I don't have an answer, but a further refinement of the question. The examples here are using the stored SQL as a standalone command. Can a snippet of SQL stored in a table's column be used as an item in a SELECT list?
I have a situation where I have a table of code/name lookup pairs. Most codes lead to a single name. But something logic needs to be applied to determine the name. I would like to have this seamless in my master SQL statement. I have to apply this logic from the same lookup table in many scripts. I don't want to have to embed complex logic in each script or maintain a convoluted stored procedure.
I have this stored procedure which executes a lot of SQL queries and returns the results. How do i go about returning only the results from the queries that returns rows?
BEGIN
DECLARE #Query varchar(4000)
DECLARE cur CURSOR FOR SELECT SQLSyntax FROM tblChecks
OPEN cur
FETCH NEXT FROM cur INTO #Query
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC (#Query)
FETCH NEXT FROM cur INTO #Query
END
CLOSE cur
DEALLOCATE cur
END
Please help me...
To avoid returning empty result sets, you have to conditionally run each query. For instance:
declare #query varchar(4000)
declare cur cursor local for
select 'if exists (' + SQLSyntax + ') ' + SQLSyntax from tblChecks
open cur
fetch next from cur into #query
while ##fetch_status = 0
begin
exec(#query)
fetch next from cur into #query
end
close cur
deallocate cur
Or, if every result set is identical, you could create a temp table first, and then insert all values into the temp table, and then do a single select statement at the end from the temp table:
create #temp (field1 type null, field2 type null, field3 type null)
declare #query varchar(4000)
declare cur cursor local for
select 'insert into #temp ' + SQLSyntax from tblChecks
open cur
fetch next from cur into #query
while ##fetch_status = 0
begin
exec(#query)
fetch next from cur into #query
end
close cur
deallocate cur
select * from #temp
drop table #temp
If possible, the 2nd option is better, because it will only run each query one time. The 1st option will run each query twice (that returns data), once to test if there are any results and once to return the data. This is not efficient! Hopefully all queries return the same fields in the results and you can use the 2nd option.
You can also execute and evaluate the results using the If exists strategy.
IF EXISTS(exec(#query))
BEGIN
exec(#query)
END
I'm trying to get this cursor loop to work, so I could copy data from linked server to another server. However it seems that the cursor is in a loop and does nothing. What am I doing wrong?
/* For testing purposes I'm fetching data from
1 company only. The result should be one row.*/
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
convert(nvarchar(100),[Nro])
,convert(nvarchar(100),'+#tmp_key+' )
FROM [Linked_server_name].TK'+#tmp_key+'.[dbo].[cominfo]
where [rule1] <> 0 and acc = 1777';
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
while (##fetch_status = 0)
begin
EXEC sp_sqlexec #sql
end;
CLOSE #db
DEALLOCATE #db
You should put the dynamic SQL inside the WHILE loop. Make sure to call FETCH NEXT inside to avoid infinite loop.
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
WHILE(##FETCH_STATUS = 0) BEGIN
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
CONVERT(NVARCHAR(100), [Nro])
,CONVERT(NVARCHAR(100),' + #tmp_key +')
FROM [Linked_server_name].TK' + #tmp_key + '.[dbo].[cominfo]
WHERE [rule1] <> 0 AND acc = 1777';
EXEC sp_sqlexec #sql
FETCH NEXT FROM #db INTO #tmp_key
END;
CLOSE #db
DEALLOCATE #db
I'm trying to create a SQL Server script that applies some operations to all the tables in all the databases. I need to rename some tables if some conditions are respected, truncate the tables otherwise.
This is my script
EXEC sp_MSforeachdb
#command1 = '
IF not exists(select 1 where ''?'' in (''master'',''model'',''msdb'',''tempdb''))
EXEC [?].dbo.sp_MSforeachtable
#command1 = ''
IF(substring(&, 1, 3)=pv_ and right(&, 5) != _data and right(&, 4) != _BCK)
exec sp_RENAME & , &_BCK''
ELSE IF (right(&, 4) != _BCK)
TRUNCATE TABLE &
#replacechar = ''&'''
I got some errors but I'm new to SQL Server and I have not idea how to fix this script.
Any suggestions?
Many thanks
Here is a solution for start. It won't be quick, but it loops all tables of all databases on the server. Inside in the second cursor you can deceide what to do with the table.
(The query is not optimalized, just a quick solution)
DECLARE #DBName NVARCHAR(50)
DECLARE #TableName NVARCHAR(100)
DECLARE #DynamicSQL NVARCHAR(300)
DECLARE #DBCursor CURSOR
SET #DBCursor = CURSOR FOR
SELECT NAME FROM SYS.DATABASES
WHERE NAME NOT IN ('master','tempdb','model','msdb')
OPEN #DBCursor
FETCH NEXT FROM #DBCursor INTO #DBName
WHILE ##FETCH_STATUS = 0
BEGIN
CREATE TABLE #TempTableDatas
(
name varchar(100),
objectID int
)
SET #DynamicSQL = 'INSERT INTO #TempTableDatas
SELECT name, object_id FROM [' + #DBName + ']' + '.sys.Tables '
EXEC SP_EXECUTESQL #DynamicSQL
DECLARE #TableCursor CURSOR
SET #TableCursor = CURSOR FOR
SELECT name FROM #TempTableDatas
OPEN #TableCursor
FETCH NEXT FROM #TableCursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #TableName, #DBName
FETCH NEXT FROM #TableCursor INTO #TableName
END
CLOSE #TableCursor
DEALLOCATE #TableCursor
DROP TABLE #TempTableDatas
FETCH NEXT FROM #DBCursor INTO #DBName
END
CLOSE #DBCursor
DEALLOCATE #DBCursor
Say I want to run the following:
update users set age = 10
on databases:
db1, db2, db3
All on the same server, I want to loop through and perform the same action.
Currently I am doing this manually using management studio via the dropdown.
Hoping there is a better way.
You could probably do it with dynamic SQL. Something like so:
create table #dbs (db_name sysname not null)
insert into #dbs values ('db1'),('db2'),('db3')
declare curs cursor for
select db_name from #dbs
declare #db sysname, #sql nvarchar(max)
open curs
while(1=1)
begin
fetch next from curs into #db
if (##fetch_status <> 0)
break
set #sql = 'update ' + quotename(#db) + '.dbo.users set age = 10'
exec(#sql)
end
close curs
deallocate curs
drop table #dbs
Not sure about doing it 'dynamically', i.e. a FOR-EACH style loop on all the databases in a server, but this should work:
USE db1
update users set age = 10
GO
USE db2
update users set age = 10
GO
USE db3
update users set age = 10
Designate a server as a central management server and then add the other servers to the server group. Then you can run the update on all databases within the group. http://msdn.microsoft.com/en-us/library/bb934126.aspx
use [WWAUTHxxx__] -- a db containing active databases.
set nocount on
declare #Catalog as nvarchar(32)
declare #LibraryName as varchar(255)
declare #dbtable as varchar(50)
declare #retval as nvarchar(50)
declare #sSQL as nvarchar(max)
declare #parmdef as nvarchar(500)
declare #retvalout as nvarchar(50)
Declare Library_Cursor Cursor for
select top(1000) xCatalog, xLibraryName
from Active_DBs
order by xcatalog
Open Library_Cursor;
Fetch Next from Library_Cursor into #Catalog, #LibraryName
while ##Fetch_status = 0
begin
set #dbTable = #Catalog + '.dbo.las_circperiods'
set #ParmDef = N'#retvalOUT int OUTPUT';
set #sSQL = N'Select #retvalout = count(*) from ' + #dbtable
+ ' where xlastcircdate is null'
exec sp_executesql #ssql,#parmdef,#retvalout=#retval output
if #retval > 0 -- check/print Sql and then activate.
-- I like checking to see the potentially affected databases.
begin
print #Catalog + ',' + #LibraryName + ',' + #retval
set #ssql = N'update ' + #dbTable
+ ' set xlastcircdate = '''' '
+ ' where xlastcircdate is null'
-- print #ssql -- View what you might will do
exec sp_executesql #ssql -- Do it.
end
Fetch Next from Library_Cursor into #Catalog, #LibraryName
end;
close Library_cursor
Deallocate Library_cursor