I am making a script that prints tablenames into a temp table.
I need it to place a suffix to the end like this
#temptable1
#temptable2
...
#temptableXXX
My problem is it doesn't increment when I use rank, and identity doesn't work in a cursor.
I have posted both tries. One of them are commented out.
DECLARE #suffix VARCHAR(1000)
DECLARE #crs insensitive CURSOR FOR
SELECT IDENTITY(int, 1, 1) AS ID --rank() over (partition by name order by
name) --as Identity(1,1)
INTO name
FROM sys.tables
FOR READ ONLY
OPEN #crs
FETCH NEXT FROM #crs INTO #suffix
WHLIE ##FETCH_STATUS = 0
BEGIN
DECLARE #TableName VARCHAR(100)
DECLARE #TabName CURSOR
SET #TabName = CURSOR FOR
SELECT NAME + #suffix
FROM sys.tables
ORDER BY name
OPEN #TabName
PRINT '--- Her skal header printes '
FETCH NEXT FROM #TabName INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #TableName
----------------------------------------------------------------- start loop tabel
----------------------------------------------------------------- slut loop tabel
Fetch next from #TabName into #TableName
END
CLOSE #TabName;
DEALLOCATE #TabName;
END
CLOSE #crs
DEALLOCATE #crs
I think you are just looking for
SELECT CONCAT(Name, ROW_NUMBER() OVER(ORDER BY Name)) TableName
FROM Sys.Tables;
First, don't use a cursor :) I'd do something like this:
DECLARE
#Table_Name As Varchar(200)
, #Message As VarChar(Max)
, #Suffix As Int = 1
, #Temp_Table_Name As Varchar(100)
Select Distinct
name
, 0 As Processed
Into #Temp_Names
from sys.tables
While Exists (Select Top 1 1
FROM #Temp_Names
WHERE Processed = 0)
BEGIN
Select Top 1
#Table_Name = name
From #Temp_Names
WHERE Processed = 0
Set #Temp_Table_Name = 'TempTable' + Cast(#Suffix As Varchar(100))
/*
your code here
*/
Update #Temp_Names
Set Processed = 1
Where name = #Table_Name
Set #Suffix = #Suffix + 1
End
You may want to adjust the Varchar sizes - I was shooting from the hip.
Try this-
SELECT NAME+CAST(RANK() OVER(ORDER BY NAME) AS VARCHAR) AS NEW_NAME
FROM SYS.TABLES
Another solution to the problem is this.
declare #nr int = 0;
set #nr = #nr +1 ;
#TmpTab_'+CONVERT(nvarchar(3), #nr)+'
Related
I am writing an exe string in sql 2012 and I am getting the following error.
Incorrect syntax near Group By. Any assistance would be much appreciated in advance.
declare #counter int = (select count(1) from #temp) SELECT * FROM #temp
declare #tab_name varchar(100)
declare #col_name varchar(100)
while (#counter > 0)
begin
set #tab_name = (select table_name from #temp where rn = #counter)
set #col_name = (select field_name from #temp where rn = #counter)
exec ('select
'''+#tab_name+''','''+#col_name+''',max(len('+#col_name+')),'''+#col_name+'''
from [x3v7].[LIVE].'+#tab_name+'''Group By'''+#col_name+'''Having
max(len('+#col_name+'))>12''')
set #counter -= 1
end
Here's a the basic structure of a cursor loop with dynamic SQL to get you started.
The string concatenation is still a mess. Clean it up using the CONCAT and QUOTENAME functions to generate the query.
declare #tab_name varchar(100)
declare #col_name varchar(100)
declare c cursor local for
select table_name, field_name
from #temp
open c;
fetch next from c into #tab_name, #col_name;
while ##FETCH_STATUS = 0
begin
declare #sql nvarchar(max) = 'select
'''+#tab_name+''','''+#col_name+''',max(len('+#col_name+')),'''+#col_name+'''
from [x3v7].[LIVE].'+#tab_name+'''Group By'''+#col_name+'''Having
max(len('+#col_name+'))>12'''
print #sql
--exec(#sql);
fetch next from c into #tab_name, #col_name
end
close c;
deallocate c;
How do I write the below code in SQL? The query would update each column in the table from the result.
DECLARE #table_list NVARCHAR -- What data type do I use to hold a list?
DECLARE #column_list NVARCHAR
SET #table_list = (SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO) -- there are more than one results
SET #column_list = (SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO) -- there are more than one results
foreach(#table IN #table_list)
{
foreach(#column IN #column_list)
{
UPDATE #table
SET #column = '101211'
WHERE #column = '10120'
}
}
You can use CURSORs to act like a foreach loop:
DECLARE #table NVARCHAR(255)
DECLARE #column NVARCHAR(255)
DECLARE OUTER_CURSOR CURSOR
FOR SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO
OPEN OUTER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO #table
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE INNER_CURSOR CURSOR
FOR SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO
OPEN INNER_CURSOR
FETCH NEXT FROM INNER_CURSOR INTO #column
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE #strQuery NVARCHAR(MAX)
SET #strQuery = 'UPDATE [' + #table + '] SET [' + #column + '] = ''101211'' WHERE [' + #column + '] = ''10120'';'
EXEC(#strQUERY)
FETCH NEXT FROM INNER_CURSOR INTO #column
END
CLOSE INNER_CURSOR
DEALLOCATE INNER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO #table
END
CLOSE OUTER_CURSOR
DEALLOCATE OUTER_CURSOR
T-SQL doesn't have a FOR loop, perhaps it has a WHILE (Transact-SQL)
Use SQL like below:
DECLARE #table_list NVARCHAR -- What data type do I use to hold a list?
DECLARE #column_list NVARCHAR
SET #table_list = (SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO) -- there are more than one results
SET #column_list = (SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO) -- there are more than one results
WHILE #column_list > #table_list
BEGIN
UPDATE #table
SET #column = '101211'
WHERE #column = '10120'
END;
Basically I'm looking to loop through a temp table which lists certain table names which need updated, I take each table name use it to populate another temporary table of all the ID's which are to be updated..
I can select the data in each table needing updated using this structure, but cannot seem to get the inner cursor to run as it isn't picking up the temp table..
Any help would be greatly appreciated as this has been doing my nut in for the past few hours..
Cheers,
DECLARE #table INT
DECLARE #prefix nvarchar(3)
DECLARE #TableName nvarchar(50)
DECLARE #TableIdName nvarchar(50)
DECLARE #getTable CURSOR
SET #getTable = CURSOR FOR
SELECT DISTINCT(id)
FROM #t
OPEN #getTable
FETCH NEXT
FROM #getTable INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #TableName = name FROM #t WHERE id = #table
SET #TableIdName = #TableName + 'Id'
SELECT #prefix = prefix FROM #t WHERE name = #TableName
--PRINT #table
PRINT #TableName
--PRINT #TableIdName
--PRINT #prefix
DECLARE #temptable table(rid int, rTableName nvarchar(50), rprefix nvarchar(3), rpk nvarchar(50))
EXEC ('INSERT INTO ' + #temptable + ' SELECT ' + #TableIdName + ', ' + #TableName + ', ' + #prefix + #TableIdName + ' FROM ' + #TableName)
DECLARE #rTableName nvarchar(50)
DECLARE #rpk nvarchar(50)
DECLARE #rprefix nvarchar(3)
DECLARE #row INT
DECLARE #getRow CURSOR
SET #getRow = CURSOR FOR
SELECT DISTINCT(rid)
FROM #temptable
OPEN #getRow
FETCH NEXT
FROM #getRow INTO #row
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #row
SELECT #rTableName = rTableName FROM #temptable WHERE rid = #row
SELECT #rpk = rpk FROM #temptable WHERE rid = #row
SELECT #rprefix = rprefix FROM #temptable WHERE rid = #row
EXEC ('UPDATE ' + #rTableName + ' SET CoiRef = ' + #rprefix + '_' + #row + ' WHERE ' + #rpk + ' = ' + #row)
FETCH NEXT
FROM #getRow INTO #row
END
CLOSE #getRow
DEALLOCATE #getRow
FETCH NEXT
FROM #getTable INTO #table
END
CLOSE #getTable
DEALLOCATE #getTable
I have also tried another solution using sp_executesql but get similar errors there, this was using the below code instead on the first EXEC..
DECLARE #sqlCommand nvarchar(500)
SET #sqlCommand = 'INSERT INTO #temptable SELECT TableIdName, TableName, prefix, TableIdName FROM' + #TableName
EXECUTE sp_executesql #sqlCommand, N'#temptable nvarchar(50) output', #temptable OUTPUT
Again, Any help would be greatly appreciated..
Thanks..
Gerry
I think the error is coming from the fact that you're trying to use a table variable inside of dynamic sql. This is not something that is supported because the table variable is out of scope for the dynamic sql. You should make your #temptable into a temporary table using the create table command.
In the unsolicited advice category, I'd suggest attempting to recreate this without using cursors if at all possible, as cursors go against the concept of set based processing which is the foundation of sql server.
I have the following code which works fine for one table but I am trying to figure out how to make it loop.
DECLARE #sql NVARCHAR(2000)
DECLARE #table VARCHAR(100)
DECLARE #command NVARCHAR(1000)
SELECT #table = ( VV.SRC_CD )
FROM VV
SET #sql = 'SELECT [CD],[SRC_CD],[SRC_CD_DESC],[DSC],[REFRESH_DT],[GEN_DSC] = CAST(null as VARCHAR(50)) INTO dbo.vv_' + #table
+
' FROM [vv] A WHERE A.SRC_CD <> ''GEN'' AND A.DSC <> ''NO DATA'' AND A.DSC <> ''(BLANK) NO'' AND A.src_cd = '''
+ #table + ''''
EXEC Sp_executesql
#stmt = #sql
The code that populates the #table variable returns one row. What I am trying to do is get this procedure to loop one time for each distinct value in the table for that row. The distinct clause doesn't work here and I have tried a basic table array with no luck.
Do I need to modify this to use a cursor?
It sounds like you're in need of a cursor, something like:
DECLARE #Iterator NVARCHAR(100)
,#sql NVARCHAR(MAX)
DECLARE xyz CURSOR
FOR
--Select stuff to iterate over
SELECT DISTINCT SRC_CD
FROM w
OPEN xyz
FETCH NEXT FROM xyz
INTO #Iterator
WHILE ##FETCH_STATUS = 0
BEGIN
--Do stuff
SET #sql = 'SELECT [CD],[SRC_CD],[SRC_CD_DESC],[DSC],[REFRESH_DT],[GEN_DSC] = CAST(null as VARCHAR(50))
INTO dbo.vv_' + #Iterator +'
FROM [vv] A
WHERE A.SRC_CD <> ''GEN''
AND A.DSC <> ''NO DATA''
AND A.DSC <> ''(BLANK) NO''
AND A.src_cd = ''' + #Iterator + ''''
PRINT (#sql)
FETCH NEXT FROM xyz
INTO #Iterator
END
CLOSE xyz
DEALLOCATE xyz
GO
I left PRINT in there so you can ensure the output is as desired before executing.
I was wondering if someone could help me with creating a while loop to iterate through several databases to obtain data from one table from two columns. this is was I have done so far. nothing works because i do not know how to make the select statement work through each database with regards to the table that I am querying from each database (dbo.tbldoc)
DECLARE #Loop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
DECLARE #tableName VARCHAR(255)
SET #Loop = 1
SET #DBName = ''
WHILE #Loop = 1
BEGIN
SELECT [name] FROM sys.databases
WHERE [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
SET #Loop = ##ROWCOUNT
IF #Loop = 0
BREAK
SET #SQL = ('USE ['+ #DBNAME +']')
IF EXISTS(SELECT [name] FROM sys.tables WHERE name != 'dbo.tbldoc' )
BEGIN
SELECT SUM(PGCOUNT), CREATED FROM **dbo.tbldoc**
END
ELSE
--BEGIN
PRINT 'ErrorLog'
END
I would consider sp_MSForEachDB which is a lot easier...
Edit:
EXEC sp_MSForEachDB 'USE [?]; IF DB_NAME() LIKE ''Z%%''
BEGIN
END
'
CREATE TABLE #T
(dbname sysname NOT NULL PRIMARY KEY,
SumPGCOUNT INT,
CREATED DATETIME)
DECLARE #Script NVARCHAR(MAX) = ''
SELECT #Script = #Script + '
USE ' + QUOTENAME(name) + '
IF EXISTS(SELECT * FROM sys.tables WHERE OBJECT_ID=OBJECT_ID(''dbo.tbldoc''))
INSERT INTO #T
SELECT db_name() AS dbname, SUM(PGCOUNT) AS SumPGCOUNT, CREATED
FROM dbo.tbldoc
GROUP BY CREATED;
'
FROM sys.databases
WHERE state=0 AND user_access=0 and has_dbaccess(name) = 1
AND [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
IF (##ROWCOUNT > 0)
BEGIN
--PRINT #Script
EXEC (#Script)
SELECT * FROM #T
END
DROP TABLE #T
My code to search for data from more than one database would be:
use [master]
go
if object_id('tempdb.dbo.#database') is not null
drop TABLE #database
go
create TABLE #database(id INT identity primary key, name sysname)
go
set nocount on
insert into #database(name)
select name
from sys.databases
where name like '%tgsdb%' --CHANGE HERE THE FILTERING RULE FOR YOUR DATABASES!
and source_database_id is null
order by name
Select *
from #database
declare #id INT, #cnt INT, #sql NVARCHAR(max), #currentDb sysname;
select #id = 1, #cnt = max(id)
from #database
while #id <= #cnt
BEGIN
select #currentDb = name
from #database
where id = #id
set #sql = 'select Column1, Column2 from ' + #currentDb + '.dbo.Table1'
print #sql
exec (#sql);
print '--------------------------------------------------------------------------'
set #id = #id + 1;
END
go
DECLARE #Loop int
DECLARE #MaxLoop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
SET #Loop = 1
SET #DBName = ''
set nocount on
SET #MaxLoop = (select count([name]) FROM sys.databases where [name] like 'Z%')
WHILE #Loop <= #MaxLoop
BEGIN
SET #DBName = (select TableWithRowsNumbers.name from (select ROW_NUMBER() OVER (ORDER by [name]) as Row,[name] FROM sys.databases where [name] like 'Z%' ) TableWithRowsNumbers where Row = #Loop)
SET #SQL = 'USE [' + #DBName + ']'
exec (#SQL)
...
...
set #Loop = #Loop + 1
END
***Note: I didn't add the check if exists here.
I ended up writing one last week on the fly for some stuff I was doing.
Blog post here:
http://tsells.wordpress.com/2012/02/14/sql-server-database-iterator/
Here is the code.
SET NOCOUNT ON
GO
use master
go
Declare
#dbname nvarchar(500),
#variable1 int,
#variable2 int,
#variable3 int,
#totaldb int = 0,
#totaldbonserver int = 0,
#totaldbwithmatches int = 0
-- Get non system databases
Declare mycursor CURSOR for select name, database_id from SYS.databases where database_id > 4 order by name desc
open mycursor
fetch next from mycursor into #dbname, #variable1
while (##FETCH_STATUS <> -1)
BEGIN
DECLARE #ParmDefinition NVARCHAR(500)
Declare #mysql nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].INFORMATION_SCHEMA.TABLES where Upper(TABLE_NAME) like ''MyTable''';
SET #ParmDefinition = N'#variable2OUT int OUTPUT'
set #totaldbonserver = #totaldbonserver + 1
Execute sp_executesql #mysql, #ParmDefinition, #variable2 OUTPUT
if #variable2 = 1
BEGIN
DECLARE #ParmDefinition2 NVARCHAR(500)
Declare #mysql2 nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].dbo.MyTable';
SET #ParmDefinition2 = N'#variable2OUT int OUTPUT'
Execute sp_executesql #mysql2, #ParmDefinition2, #variable3 OUTPUT
set #totaldb = #totaldb + 1
if #variable3 > 1
BEGIN
Print #dbname + ' matched the criteria'
set #totaldbwithmatches = #totaldbwithmatches + 1
END
ELSE
Select 1
END
fetch next from mycursor into #dbname, #variable1
END
PRINT 'Total databases on server: '
Print #totaldbonserver
PRINT 'Total databases tested () : '
Print #totaldb
PRINT 'Total databases with matches: '
Print #totaldbwithmatches
CLOSE mycursor
DEALLOCATE mycursor
This doesn't use a loop. Hope this helps!
Note that "TABLE_OWNER" is that same as "SCHEMA Owner" and "TABLE_TYPE" will identify if the item is a table OR view.
--This will return all tables, table owners and table types for all database(s) that are NOT 'Offline'
--Offline database information will not appear
Declare #temp_table table(
DB_NAME varchar(max),
TABLE_OWNER varchar(max),
TABLE_NAME varchar(max),
TABLE_TYPE varchar(max),
REMARKS varchar(max)
)
INSERT INTO #temp_table (DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE,REMARKS)
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_tables'
SELECT DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE
FROM #temp_table
--Uncomment below if you are seaching for 1 database
--WHERE DB_NAME = '<Enter specific DB Name>'
--For all databases other than 'System Databases'
WHERE DB_NAME not in ('master','model','msdn','tempdb')
order by 1,2,3
You don't have to use a "USE DATABASE" statement. You can select from the particular database table by using a 3 part identifier as in:
select * from MyDatabase.dbo.MyTable