sp_MSForeachdb inserting into declared virtual table issue - tsql

I am having issues getting information to insert into the #TBL2 Table.
what am i doing wrong?
DECLARE #command varchar(1000)
DECLARE #SQLStatment varchar(1000)
DECLARE #TBL2 table (
Database_Name nvarchar(max),
SI_SITE nvarchar(max),
SI_DB_USER nvarchar(max)
)
SELECT #command = 'IF ''?'' NOT IN(''master'', ''model'', ''msdb'', ''tempdb'') BEGIN USE ? insert into #tbl2 EXEC('+ #SQLStatment +') END'
set #SQLStatment = 'select top 1 Db_Name() as Database_Name, SI_SITE, SI_DB_USER from t_site'
EXEC master.. sp_MSForeachdb #command
select * from #TBL2

Try This:
There are several issues with the approach you are taking:
I don't think the "USE" statement can be dynamic (could be wrong)
The SQL is declared after you are trying to use it.
sp_msforeachdb is undocumented and shouldn't be relied on, even though it can work in many circumstances.
My approach uses the sys.databases and string concatenation to generate the appropriate SQL string to get the data you want from each table in all databases except the system databases, then executes the results into a temp table. The approach also assumes dbo schema. Adjust if necessary.
declare #SQL nvarchar(max)
set #SQL = ''
Create Table #TBL2 (
Database_Name nvarchar(max),
SI_SITE nvarchar(max),
SI_DB_USER nvarchar(max)
)
Select #SQL = #SQL + 'INSERT INTO #TBL2 (Database_Name, SI_SITE, SI_DB_USER) select top 1 ''' + name + ''' as Database_Name, SI_SITE, SI_DB_USER from ' + name + '..t_site;' + char(13)
From sys.databases
Where name not in ('master', 'model', 'msdb', 'tempdb')
print #SQL
exec sp_executesql #SQL
Select * From #TBL2
drop table #TBL2

I still have some issues to work out but this is what it may look like
declare #SQL nvarchar(max)
set #SQL = ''
Create Table #TBL3 (
Server_Name nvarchar(max),
Database_Name nvarchar(max),
DB_Owner nvarchar(max),
SI_SITE nvarchar(max),
SI_DB_USER nvarchar(max),
DB_Creation_date nvarchar(max),
DB_state nvarchar(max),
DB_SQL_version nvarchar(max)
)
Select #SQL = #SQL + 'INSERT INTO #TBL3
(
Server_Name
,[Database_Name]
,[DB_Owner]
,[DB_Creation_Date]
,[DB_State]
,[DB_SQL_Version]
,[SI_SITE]
,[SI_DB_USER]
)
SELECT
Server_Name
,quotename(''' + name + ''')
,[DB_Owner]
,[DB_Creation_date]
,[DB_state]
,[DB_SQL_version]
,[SI_SITE]
,[SI_DB_USER]
From( SELECT TOP 1
[SI_SITE]
,[SI_DB_USER]
From [' + name + ']..[t_site]) Q1,
( SELECT
##SERVERNAME as [Server_Name]
,suser_sname(owner_sid) as [DB_Owner]
,[Create_Date] as [DB_Creation_date]
,[state_desc] as [DB_state]
,case [compatibility_level]
when 80 then ''SQL Server 2000'' when 90 then ''SQL Server 2005'' when 100 then ''SQL Server 2008'' when 110 then ''SQL Server 2012'' when 120 then ''SQL Server 2014'' when 130 then ''SQL Server 2016'' when 140 then ''SQL Server 2017'' else cast(compatibility_level as varchar(100)) end as DB_SQL_version
from [sys].[databases]
where [name] = ''' + name + '''
) Q2;' + char(13)
From sys.databases
Where name not in ('master', 'model', 'msdb', 'tempdb')
and name not in ('DBX') -- where [T_site] table does not exist
and name not in ('DBY') -- offline, need offline clause added
print #SQL
exec sp_executesql #SQL
Select * From #TBL3
DROP TABLE #TBL3

Related

How to Get output from nested SP_executeSQL

Can you tell me how to insert executed variable #name in my table?
I had some coding and this is what i managed to do but I do not know whats next:
DECLARE #Name nvarchar(200);
DECLARE #dbcatalog nvarchar(128);
declare #sql nvarchar(4000)
select #name = N' select ID from ' + #DbCatalog + '.dbo.Table2 ';
SET #sql = 'insert into Table2(Name) values (#name)'
exec Sp_executeSQL #sql
Are you trying to copy ID values from one table into another? If so, then:
INSERT INTO Table2 (Name)
EXEC(#Name)

How to script out all databases objects for all databases at the instance level

I tried to query my instance to get list of all database objects of n databases using cursor with no avail
DROP TABLE IF EXISTS #temp
SELECT * into #temp from ( select DB_NAME() AS [database_name], sys.schemas.name + '.' + sys.objects.name as [object_name],
type as [schema_name], type_desc as [Object_Description]
FROM    sys.objects 
INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id 
where type in 
( 
'p', 'pc', -- stored procs 
'v', -- views 
'tf', 'if', 'ft', -- table-valued functions 
'fn', 'fs', -- scalar-valued functions 
'af' -- aggregate functions 
) )as [SomeAlias]
--select *from #temp
DECLARE #name sysname;
DECLARE #sql nvarchar(max) =
'select databse_name , schema_name ,object_name , Object_Description from #temp'
DECLARE #theSQL nvarchar(max);
DECLARE #results TABLE (
[database_name] sysname,
[object_name} sysname,
[schema_name] sysname,
[Object_Description] sysname
);
DECLARE dbs CURSOR STATIC LOCAL FORWARD_ONLY READ_ONLY
FOR
SELECT name
FROM sys.databases;
-- you may want to exclude system databases here
-- WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb', 'distribution')
OPEN dbs;
FETCH NEXT FROM dbs INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #theSQL = 'EXEC ' + QUOTENAME(#name) + '.sys.sp_executesql #sql';
INSERT #results
EXEC sys.sp_executesql #theSQL, N'#sql nvarchar(max)', #sql
FETCH NEXT FROM dbs INTO #name;
END
CLOSE dbs;
DEALLOCATE dbs;
SELECT *
FROM #results;
There are a number of ways to get the object details that you're looking for in all databases. I have included two solutions below, one using the cursor method that was attempted in the question, and another that is simpler us the sp_msforeachdb stored procedure.
Cursor Method:
declare #db_nm varchar(250)
, #sql varchar(1000)
DECLARE #results TABLE (
[database_name] sysname,
[object_name] sysname,
[schema_name] sysname,
[Object_Description] sysname
);
declare db cursor local
fast_forward for
select db.name
from master.sys.databases as db
where db.name not in ('master', 'tempdb', 'model', 'msdb') --system db you're probably not looking for info in
open db
fetch next from db into #db_nm;
while ##fetch_status = 0
begin
set #sql =
'select ''' + #db_nm + ''' AS [database_name]
, s.name + ''.'' + o.name as [object_name]
, type as [schema_name]
, type_desc as [Object_Description]
FROM [' + #db_nm + '].sys.objects as o
INNER JOIN [' + #db_nm + '].sys.schemas as s ON o.schema_id = s.schema_id
where type in (''p'', ''pc'', -- stored procs
''v'', -- views
''tf'', ''if'', ''ft'', -- table-valued functions
''fn'', ''fs'', -- scalar-valued functions
''af'' -- aggregate functions
)
'
insert into #results
exec (#sql)
fetch next from db into #db_nm;
end
close db
deallocate db
select *
from #results
sp_msforeachdb Method:
This method comes with the warning that the procedure is un-documented.
declare #sql varchar(1000) =
'
if ''?'' not in (''master'', ''tempdb'', ''model'', ''msdb'') --system db youre probably not looking for info in
begin
select ''?'' AS [database_name]
, s.name + ''.'' + o.name as [object_name]
, type as [schema_name]
, type_desc as [Object_Description]
FROM [?].sys.objects as o
INNER JOIN [?].sys.schemas as s ON o.schema_id = s.schema_id
where type in (''p'', ''pc'', -- stored procs
''v'', -- views
''tf'', ''if'', ''ft'', -- table-valued functions
''fn'', ''fs'', -- scalar-valued functions
''af'' -- aggregate functions
)
end
'
DECLARE #results TABLE (
[database_name] sysname,
[object_name] sysname,
[schema_name] sysname,
[Object_Description] sysname
);
insert into #results
exec master.dbo.sp_msforeachdb #sql
select *
from #results

Using a Cursor to Create Triggers for all tables in a database

I am using SQL Server 2005
I am trying to create a trigger for each table contained within a database and keep getting an error which I do not understand and can not fix
If anyone has an idea of why I am getting this error or how I can resolve it that would be brilliant.
DECLARE #TableName AS VARCHAR(100)
DECLARE #audit_action as varchar(100)
DECLARE RDS_cusor CURSOR FOR
SELECT TABLE_NAME FROM [RawDataStorage].INFORMATION_SCHEMA.Tables WHERE TABLE_NAME LIKE 't_%' AND TABLE_NAME NOT LIKE 'tbl_%'
OPEN RDS_cursor
FETCH NEXT FROM RDS_cursor INTO #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
CREATE TRIGGER dbo.After_Insert_Trig
ON [dbo].[t_Agent]
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO RawDataStorage_Audit
(TableName,Audit_Action,Audit_Timestamp)
VALUES('TableName','audit_action',getdate());
END
GO
FETCH NEXT FROM RDS_cursor INTO #TableName
END
CLOSE RDS_cursor
DEALLOCATE RDS_cursor
This is the error I am getting:
Msg 156, Level 15, State 1, Line 15
Incorrect syntax near the keyword 'TRIGGER'.
Msg 102, Level 15, State 1, Line 26
Incorrect syntax near 'END'.
Msg 137, Level 15, State 2, Line 2
Must declare the scalar variable "#TableName".
any help would be greatly appreachiated
I managed to put this together, its a dynamic query that builds the sql to create the triggers using a cursor to grab the table names from the sysobjects.
CREATE TABLE [dbo].[RawDataStorage_Audit](
ID INT IDENTITY(1,1) NOT NULL,
TableName VARCHAR(50) NULL,
audDateLastChanged DATETIME null
)
Declare #TableName nvarchar(100)
Declare #SQL nvarchar(1000)
declare tables_cursor CURSOR FOR
select [name] from sysobjects
where xtype = 'U'
and [name] not like 'sys%'
order by [name]
Open tables_cursor
fetch next from tables_cursor into #TableName
WHILE ##FETCH_STATUS = 0
Begin
--create trigger for insert on each table
print #SQL
set #SQL = 'create trigger trg_u_'+#TableName+'_Inserted '
set #SQL = #SQL + ' on '+#TableName
set #SQL = #SQL + ' for insert '
set #SQL = #SQL + ' as '
set #SQL = #SQL + ' begin '
set #SQL = #SQL + ' insert into [dbo].[RawDataStorage_Audit] '
set #SQL = #SQL + ' select ''' + #TableName +''', getdate()'
set #SQL = #SQL + ' from inserted'
set #SQL = #SQL + ' end'
exec (#SQL)
print #SQL
fetch next from tables_cursor into #TableName
end
CLOSE tables_cursor
DEALLOCATE tables_cursor

Altering Multiple Tables at once

I'm trying to alter multiple SQL Server 2008 R2 tables at one time.
This is my code:
use DatabaseName
go
Declare #SchemaUsed varchar(20) = 'dbo'
create table #Tables
(
TableName varchar(100), Processed int
)
insert into #Tables
select top 1 table_name, 0
from INFORMATION_SCHEMA.TABLES
where TABLE_SCHEMA = #SchemaUsed
and table_type = 'Base Table'
and (TABLE_NAME like 'PM%' )
ORDER BY TABLE_NAME
DECLARE #TableName varchar(max)
DECLARE #SQL varchar(max)
WHILE EXISTS (select top 1 'x' from #Tables where Processed = 0)
BEGIN
SET #TableName = (select top 1 TableName from #Tables where Processed = 0)
Set #SQL = 'ALTER TABLE ' + #SchemaUsed + '.' + #TableName + ' ADD [identityID] bigint IDENTITY(1, 1) NOT NULL '
-- Set #SQL = '''' + #SQL + ''''
Print #SQL
EXEC #SQL;
update #Tables
set Processed = 1
where TableName = #TableName
END
drop table #Tables
I can't get this to work to save my life and get the following error:
Lookup Error - SQL Server Database Error: The name 'ALTER TABLE
dbo.PM1GTVLV ADD [identityID] bigint IDENTITY(1, 1) NOT NULL ' is not
a valid identifier.
I've also tried multiple string variations and using sp_executesql as well.
Can someone point out where I've gone wrong?
Try
DECLARE #SQL NVARCHAR(MAX);
EXEC sp_executesql #SQL;
Instead of EXEC #sql.
As an aside, this is a much more usable version of the same code IMHO:
DECLARE #SchemaUsed VARCHAR(20) = 'dbo';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + N'ALTER TABLE '
+ QUOTENAME(#SchemaUsed) + '.'
+ QUOTENAME(name) + ' ADD [identityID]
BIGINT IDENTITY(1,1) NOT NULL;'
FROM sys.tables
WHERE SCHEMA_NAME([schema_id]) = #SchemaUsed
AND name LIKE 'PM%';
PRINT #sql;
--EXEC sp_executesql #sql;
Or even better:
DECLARE #SchemaUsed VARCHAR(20) = 'dbo';
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += CHAR(13) + CHAR(10) + N'ALTER TABLE '
+ QUOTENAME(#SchemaUsed) + '.'
+ QUOTENAME(name) + ' ADD [identityID]
BIGINT IDENTITY(1,1) NOT NULL;'
FROM sys.tables AS t
WHERE SCHEMA_NAME([schema_id]) = #SchemaUsed
AND name LIKE 'PM%'
AND NOT EXISTS (SELECT 1 FROM sys.columns AS c
WHERE [object_id] = t.[object_id]
AND c.is_identity = 1);
PRINT #sql;
--EXEC sp_executesql #sql;
To execute a character string, EXEC requires parenthesis around the string (or character variable) as shown in the BOL syntax:
EXEC (#SQL);

Stored Procedure Create Prob

Ok I don't know much about stored procedures, but does anyone know how I could write this as an SP. I think it's kinda getting there but not quite. basically what would I need to paste into my query to create it!:)
CREATE PROCEDURE sp_executesql
as
DECLARE
#cols AS NVARCHAR(MAX),
#y AS INT,
#sql AS NVARCHAR(MAX);
-- Construct the column list for the IN clause
SET #cols = STUFF(
(SELECT N',' + QUOTENAME(w) AS [text()]
FROM (SELECT DISTINCT WeekNo AS W FROM dbo.Items) AS W
ORDER BY W
FOR XML PATH('')),
1, 1, N'');
-- Construct the full T-SQL statement
-- and execute dynamically
SET #sql = N'SELECT *
FROM (SELECT ItemNo, WeekNo, Value
FROM dbo.Items) AS I
PIVOT(SUM(Value) FOR WeekNo IN(' + #cols + N')) AS P;';
EXEC sp_executesql #sql;
GO
Assuming the query statement is correct and you need just a SP structure it will be like this:
CREATE PROCEDURE SP_NAME
#variable1 type [input/output]
as
begin
--query
end
//to execute SP
EXEC SP_NAME 'valueForVariable1'
hope this helps
Got it. Just don't name provedure sp_executesql, name it get_items or something else.
new procedure:
CREATE PROCEDURE get_items
as
declare #cols AS NVARCHAR(MAX),
#y AS INT,
#sql AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT N',' + QUOTENAME(w) AS [text()]
FROM (SELECT DISTINCT week_no AS W FROM weekly_items) AS W
ORDER BY W
FOR XML PATH('')),1, 1, N'');
SET #sql = N'SELECT *
FROM (SELECT item_no, week_no, totval
FROM weekly_items) AS I
PIVOT(SUM(totval) FOR week_no IN(' + #cols + N')) AS P;';
EXEC sp_executesql #sql
GO