how to dynamically select database inside stored procedure? - sql

Create PROC spABC
#dbname varchar(20)
As
Use [#dbname] /*NOT ALLOWED*/
BEGIN
...
END

I was able to achieve my solution in the following way. The script was run inside BEGIN...END
DECLARE #sql NVARCHAR(max)
SET #sql = N'Use ' + #dbName +N'
Select DISTINCT S.name Name,
S.create_date DOC,
S.modify_date DOM ,
P.rows ROWCNT,
MAX(C.column_id) COLCNT,
SUM(a.total_pages) * 8 AS TotalSpaceKB,
SUM(a.used_pages) * 8 AS UsedSpaceKB
From sys.tables AS S
LEFT JOIN sys.partitions P
ON S.object_id = P.object_id
LEFT JOIN sys.columns C
ON S.object_id = C.object_id
INNER JOIN sys.allocation_units a
ON p.partition_id = a.container_id
Group BY S.name , S.create_date , S.modify_date , P.rows '
EXEC sp_executesql #sql

Related

Find text in my tables, stored procedures, and views in SQL Server

I am able to search for specific text in my views and stored procedure, but I'm not able to search through my tables at the same time.
Here is what I have:
DECLARE #cmd VARCHAR(1000),
#search_string VARCHAR(200)
CREATE TABLE #temp
(
[Database_Name] sysname,
[Schema_Name] sysname,
[Object_Name] sysname,
[Object_Type] nvarchar(60)
)
-- Set the search string
SET #search_string = 'text'
SET #cmd = 'INSERT INTO #temp SELECT DISTINCT ''?'', s.name AS Schema_Name, o.name AS Object_Name, o.type_desc FROM [?].sys.sql_modules m INNER JOIN [?].sys.objects o ON m.object_id = o.object_id INNER JOIN [?].sys.schemas s ON o.schema_id = s.schema_id WHERE m.definition Like ''%' + #search_string + '%'''
-- Uncomment the following if you have problems with your command and want to see the command
--PRINT #cmd
-- Run for every database on the server
EXEC sp_MSforeachdb #cmd
-- Retrieve your results from the temp table
SELECT *
FROM #temp
ORDER BY [Database_Name], [Object_Name], [Object_Type]
-- If you want to omit certain databases from your results, simply add
-- the appropriate WHERE clause, as in the following:
--SELECT *
--FROM #temp
--WHERE db NOT IN ('DB1', 'DB4', 'DB7')
--ORDER BY db, obj_type, obj_name
DROP TABLE #temp
Please try this query for column search
SELECT
t.[name] TableName
, c.[name] ColumnName
FROM sys.columns c
INNER JOIN sys.tables t on t.object_id = c.object_id
WHERE t.[type] = 'U'
AND c.[name] LIKE '%Text%'
Below script will get result for all the databases for both Tables and other obejcts. Hope this will help.
DECLARE #command varchar(1000)
DECLARE #SearchWord VARCHAR(20) = 'Text'
CREATE TABLE #Search (DatabaseName VARCHAR(255),SchemaName VARCHAR(50),ObjectName VARCHAR(255),ObjectType VARCHAR(50))
SET #command = 'USE ? INSERT INTO #Search
SELECT DB_NAME(), SCHEMA_NAME(t.schema_id),t.[name] TableName, ''Table'' FROM sys.columns c INNER JOIN sys.tables t on t.object_id = c.object_id WHERE t.[type] = ''U'' AND c.[name] LIKE ' + '''%' + #SearchWord + '%'''
EXEC sp_MSforeachdb #command;
SET #command = 'USE ? INSERT INTO #Search
SELECT DISTINCT DB_Name(),s.name AS Schema_Name, o.name AS Object_Name, o.type_desc FROM sys.sql_modules m INNER JOIN sys.objects o ON m.object_id = o.object_id INNER JOIN sys.schemas s ON o.schema_id = s.schema_id WHERE m.definition Like ''%' + #SearchWord + '%'''
EXEC sp_MSforeachdb #command
SELECT * FROM #Search;
DROP TABLE #Search
There is an easy way
select
object= object_name(c.id), o.name , o.type
from sys.syscomments as c
join sys.objects as o on c.id = o.object_id
where c.text like '%Id%'
All compiled objects are in sys.comments, the name changed a few times depending on the version of SQL you have, the sample is from the current version.
Now, one doesn't need to join sys.object as the TSQL is in the text column.
You can look for any string that you have used, table names, field names or code comments. the sample shows %ID% looking for all function, trigger, views procedures that have something that contains the letters ID.
You know that when clicking on an object in SSMS you can select show Dependencies right?

Relate Database Names With Metadata from SQL Server System Catalogue

I want to produce a report that shows metadata about the tables and columns across databases on a server.
Ideally I would like to have the databases themselves included as a column in the report but cannot find a suitable relationship between the various sys objects on SQL Server.
So far I have:
DECLARE #R VARCHAR(50)
SET #R = 'Test1'
DECLARE #T VARCHAR(50)
SET #T = 'TESTSTUFF'
SELECT AC.[name] AS [COLUMN_NAME], T.[name] AS [TABLE_NAME], #R AS [DATABASE], '' AS [DESCRIPTION]
FROM Test1.sys.[tables] AS T
INNER JOIN Test1.sys.[all_columns] AC ON T.[object_id] = AC.[object_id] `
WHERE T.[is_ms_shipped] = 0
UNION ALL
SELECT AC.[name] AS [column_name],
T.[name] AS [table_name], #T AS [DATABASE], '' AS [DESCRIPTION]
FROM TESTSTUFF.sys.[tables] AS T
INNER JOIN TESTSTUFF.sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
WHERE T.[is_ms_shipped] = 0
By making parameters of the database name, I'm introducing a high degree of maintainability that I feel is unnecessary. Ideally I'd want this as a view because it will update itself automatically each time database objects are added.
The goal is to achieve something like this:
DECLARE #D VARCHAR(50)
SET #D = (SELECT NAME FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') )
SELECT AC.[name] AS [COLUMN_NAME], T.[name] AS [TABLE_NAME], #D AS [DATABASE], '' AS [DESCRIPTION]
FROM sys.[tables] AS T
INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
INNER JOIN sys.databases d ON ?????
WHERE T.[is_ms_shipped] = 0
Is it possible to do this?
Although you can't use a view, you could use a script or stored procedure that generates a dynamic SQL statement. The example below generates a UNION ALL query of the catalog views of each database, each qualified with the database name.
DECLARE #SQL nvarchar(MAX);
SELECT #SQL = STUFF(
(SELECT 'UNION ALL
SELECT AC.[name] COLLATE Latin1_General_100_CI_AS_KS_WS_SC AS [COLUMN_NAME], T.[name] COLLATE Latin1_General_100_CI_AS_KS_WS_SC AS [TABLE_NAME], N''' + name + N''' AS [Database], '''' AS [DESCRIPTION]
FROM ' + QUOTENAME(name) + '.sys.[tables] AS T
INNER JOIN ' + QUOTENAME(name) + '.sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
WHERE T.[is_ms_shipped] = 0 '
FROM sys.databases
WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')
FOR XML PATH, TYPE).value('.', 'nvarchar(MAX)'),1,11,'') + N';';
EXEC(#SQL);
If you use [INFORMATION_SCHEMA].[COLUMNS] instead of the sys view, it exposes the [TABLE_CATALOG] column which can be used to join to sys.databases.
You need to use
sp_MSforeachdb stored procedure to go around all DB on your server
The link between DB-Table-Schema can be made with this t-sql script
SELECT DB_NAME () as DataBaseName,
s.Name as SchemaName,
t.NAME as TableName
FROM sys.tables t
JOIN sys.indexes i ON t.object_id = i.object_id
JOIN sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.partition_id = a.container_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.is_ms_shipped = 0 and t.NAME NOT LIKE 'dt%'
GROUP BY t.Name, s.Name, p.Rows,t.create_date
ORDER BY DB_NAME(),s.Name,t.Name

SQL Server 2014 Dynamic SQL

Please take a look at the code and help me on the last part, --put all together = fail !!!
I wanted to generate a string for executing sp_executesql but I'm getting an error at the end. I also tried open cursor but it error out too.
Basically I'm trying to get actual row count per column per table for all tables
because general rowcount want give you if new column added and populated.
USE AdventureWorks2014
GO
-- Create view to hold the dataset
Alter view vColumnSchema
AS
with myColumnName
As
(
Select TOP (100) PERCENT
GetDate() As create_date,
##SERVERNAME As Server_Name,
DB_Name() AS database_name,
c.[object_id],
s.name AS [schema_name],
t.name as table_name,
c.name as column_name,
p.rows AS NUM_ROWS,
c.[precision]
from sys.tables as t
INNER JOIN sys.columns as c with(nolock) on t.[object_id] = c.[object_id]
INNER JOIN sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.schemas AS s ON s.schema_id = t.schema_id
WHERE t.name NOT LIKE 'dt%'
AND i.object_id > 255
AND i.index_id <= 1
And s.name is not null
Order by s.name,
t.name
)
Select Top 100 percent
create_date,
Server_Name,
database_name,
[schema_name],
table_name,
column_name,
NUM_ROWS,
case when precision = 0 then
'Select Count('+column_name+')'+' from ' +[schema_name]+'.'+table_name+ ' where '+column_name+'<> '''' '
else
'Select Count(' +column_name+')'+' from ' +[schema_name]+ '.'+table_name+' where '+column_name+'> 0'
END as ColumnCount,
case when precision = 0
then ' <> '''' '
Else '> 0'
END As WhereClause
from myColumnName
Order by [schema_name],
table_name
GO
select * from vColumnSchema
where table_name = 'ProductCostHistory'
go
select * from Production.ProductCostHistory -- 395 records
--pick one record and test it = pass
Select Count(EndDate) from Production.ProductCostHistory where EndDate<> '' --200 records
GO
--test = pass on both whereClause
Declare #Column_name nvarchar(50) = 'EndDate'
Declare #Schema_Name nvarchar(20) = 'Production'
declare #table_name nvarchar(50) = 'ProductCostHistory'
declare #whereClause nvarchar(5) = '<> '''' '
declare #sqltext nvarchar(max) ='
select count('+#Column_name+') as ColumnCount from ' +#Schema_Name+'.'+#table_name+' where '+#Column_name+' '+#WhereClause+'
'
EXECUTE sp_executesql #sqltext
GO
--examine each column = pass
Declare #Column_name nvarchar(50) = 'select Column_name from vColumnSchema'
EXECUTE sp_executesql #Column_name
GO
Declare #schema_name nvarchar(50) = 'select schema_name from vColumnSchema'
EXECUTE sp_executesql #schema_name
GO
declare #table_name nvarchar(50) = 'select table_name from vColumnSchema'
EXECUTE sp_executesql #table_name
GO
declare #WhereClause nvarchar(50) = 'select WhereClause from vColumnSchema'
EXECUTE sp_executesql #WhereClause
GO
--put all together = fail !!!
declare #Column_name nvarchar(50) = 'select Column_name from vColumnSchema'
declare #schema_name nvarchar(50) = 'select schema_name from vColumnSchema'
declare #table_name nvarchar(50) = 'select table_name from vColumnSchema'
declare #WhereClause nvarchar(5) = 'select WhereClause from vColumnSchema';
declare #sqltext nvarchar(max) ='
select count('+#Column_name+') as ColumnCount from ' +#Schema_Name+'.'+#table_name+' where '+#Column_name+' '+#WhereClause+'
'
EXECUTE sp_executesql #sqltext
go
If you want the number of rows per column per table:
DECLARE #sql NVARCHAR(MAX) = '';
SELECT #sql = #sql +
N'SELECT '''
+ t.name + ''' AS TableName, '''
+ c.name + ''' AS ColName, COUNT(' + QUOTENAME(c.name) + ') AS [RowCount] FROM '
+ QUOTENAME(t.name) + ' UNION ALL' + CHAR(10)
FROM sys.tables t
INNER JOIN sys.columns c
ON c.object_id = t.object_id
WHERE
t.type = 'U'
AND c.system_type_id <> 35
SELECT #sql = LEFT(#sql, LEN(#sql) - 11)
PRINT #sql
EXECUTE sp_executesql #sql
Not Sure what your end game is But this might help and does not use dynamic sql ...
You can put the number of columns in your original query without a CTE
This puts the col count in the original select
Select TOP (100) PERCENT
GetDate() As create_date,
##SERVERNAME As Server_Name,
DB_Name() AS database_name,
c.[object_id],
s.name AS [schema_name],
t.name as table_name,
c.name as column_name,
p.rows AS NUM_ROWS,
c.[precision] ,
(Select COUNT(c2.object_id)
FROM sys.columns c2
INNER JOIN sys.tables t2 ON t2.object_id = c2.object_id
WHERE t2.object_id = t.object_id
GROUP BY c2.object_id) as ColCountThisTbl
from sys.tables as t
INNER JOIN sys.columns as c with(nolock) on t.[object_id] = c.[object_id]
INNER JOIN sys.indexes AS i ON t.object_id = i.object_id
INNER JOIN sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN sys.schemas AS s ON s.schema_id = t.schema_id
WHERE t.name NOT LIKE 'dt%'
AND i.object_id > 255
AND i.index_id <= 1
And s.name is not null
Order by s.name,
t.name `enter code here`

How to find the database name and table name by using Column name

I need a query in Sql server 2005. I have a column name. Having that, I need to find a database name and table name. Is there any way to find it?
From SO's sister site, "StackExchange":
https://dba.stackexchange.com/questions/511/how-to-list-search-all-columns-in-a-sql-server-2008-databases
SELECT t.name AS table_name,
SCHEMA_NAME(schema_id) AS schema_name,
c.name AS column_name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
WHERE c.name LIKE '%EmployeeID%'
ORDER BY schema_name, table_name;
Possible, this script will be helpful for you -
DECLARE #SearchColumnName SYSNAME
SELECT #SearchColumnName = 'EmployeeID'
IF EXISTS(
SELECT 1
FROM tempdb.dbo.sysobjects
WHERE id = OBJECT_ID('tempdb.dbo.#DB')
) DROP TABLE #DB
CREATE TABLE #DB
(
[DB_NAME] SYSNAME
, [OBJECT_NAME] SYSNAME
, [COLUMN_NAME] SYSNAME
)
DECLARE #SQL NVARCHAR(500)
SELECT #SQL = 'USE [?]
INSERT INTO #DB
(
[DB_NAME]
, [OBJECT_NAME]
, [COLUMN_NAME]
)
SELECT
DB_NAME()
, s.name + ''.'' + o.name
, c.name
FROM (
SELECT
c.[object_id]
, c.name
FROM sys.columns c WITH (NOWAIT)
WHERE c.name LIKE ''%'' + ''' + #SearchColumnName+ ''' + ''%''
) c
JOIN sys.objects o WITH (NOWAIT) ON c.[object_id] = o.[object_id]
JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
WHERE o.type = ''U'''
EXEC sys.sp_MSforeachdb #SQL
SELECT *
FROM #DB
ORDER BY [DB_NAME], [OBJECT_NAME]

How to count empty tables in database?

Is there any way to count tables with no rows in my database with using T-SQL statement?
There you go... using a derived table.
SELECT * FROM
(
SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
) sub
WHERE sub.[RowCount] = 0
I use the following:
SELECT t.NAME AS TableName, sum(p.rows) as RowCounts
FROM sys.tables t
INNER JOIN sys.indexes i
ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p
ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
WHERE
i.name IS NULL AND i.index_id <= 1
GROUP BY
t.NAME, i.object_id, i.index_id, i.name
HAVING SUM(p.rows) = 0
from khtan # SQL Server Forums, this is used to drop all empty tables, maybe you could adapt it to output a count?
declare #name varchar(128), #sql nvarchar(2000), #i int
select #name = ''
while #name < (select max(name) from sysobjects where xtype = 'U')
begin
select #name = min(name) from sysobjects where xtype = 'U' and name > #name
select #sql = 'select #i = count(*) from [' + #name + ']'
exec sp_executesql #sql, N'#i int out', #i out
if #i = 0
begin
select #sql = 'drop table [' + #name + ']'
print #sql
-- unmask next to drop the table
-- exec (#sql)
end
end
I don't have SQLServer here but I could take a stab at it if you like.