How to drop and re-create a view on all DB's on a server - sql

I recently had a need to drop and recreate a view across all DB's on a server. Our original script used a cursor which we found to be a bit inefficient. In an earlier qution that I asked on here, the sys.sp_MSforeachdb prcedure was brought to my attention. I was able to use it to do exactly what was needed.
You just have to be mindful of the length of the exec statement. Apparently there is a length limit, the exact scripts I had were throwing errors until I removed all the aliases and bunched up the select statement. I had about 80 columns in it on separate lines.There were some aliases that were necessary, so I obviously left those where needed.

This is the script I ended up with:
USE [Master]
EXECUTE master.sys.sp_MSforeachdb
'USE [?]; IF db_name() NOT IN (''master'',''model'',''msdb'',''ReportServer'',''ReportServerTempDB'',''tempdb'')
BEGIN USE ?
IF EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N''[ViewName]''))
DROP VIEW [ViewName]
EXEC(''
CREATE VIEW ViewName AS
SELECT
db_name() DBName, a.Col1,a.Col2,a.Col3,t.Col1
FROM Activity a
LEFT OUTER JOIN TerminologyCache t ON a.ActivityTypeName = t.TerminologyKeyName
WHERE
a.activityProviderName = ''''Parm1''''
and (ISNULL(t.TerminologyCultureName,''''en-US'''') = ''''en-US'''')
'')
END'

Related

How to avoid showing result-window if there are no results to show?

I have a script which searches through all the available databases (those I have access to) for a specific text in a procedure.
In my server, there are many databases (in my case about 150 databases), meaning that I get shown the results for all databases eventhough there are no results for most of them (about 90%).
Is there any way to avoid getting these empty result-queries?
You can use below code to check whether stored procedure contains a text in each database. If there are stored procedures in a database only, you will have resultset.
CREATE TABLE ##DatabasesContainingSP(dbname sysname, SPName SYSNAME);
EXECUTE master.sys.sp_MSforeachdb 'USE [?];
INSERT INTO ##DatabasesContainingSP
SELECT DISTINCT
db_name() as dbname, o.name AS Object_Name
FROM sys.sql_modules m
INNER JOIN
sys.objects o
ON m.object_id = o.object_id
WHERE m.definition Like ''%ABC%'';
'
IF EXISTS(SELECT * FROM ##DatabasesContainingSP )
begin
SELECT * FROM ##DatabasesContainingSP
end
GO
IF OBJECT_ID('tempdb..##DatabasesContainingSP' , 'U') IS NOT NULL
drop TABLE ##DatabasesContainingSP;
Thank you for the quick responses.
I managed to solve it by creating a table and adding insert into this table in the beginning of my generated and concatenated code, which solved the problem since when reading the table in the end, it only shows the inserted results.
With kind regards,
Alexander

Drop view if exists

I have script where I want to first drop view and then create it.
I know how to drop table:
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'table1' AND type = 'U') DROP TABLE table1;
so I did the same for views:
IF EXISTS (SELECT * FROM sys.views WHERE name = 'view1' AND type = 'U') DROP VIEW view1;
create view1 as(......)
and then I got error:
'CREATE VIEW' must be the first statement in a query batch.
your exists syntax is wrong and you should seperate DDL with go like below
if exists(select 1 from sys.views where name='tst' and type='v')
drop view tst;
go
create view tst
as
select * from test
you also can check existence test, with object_id like below
if object_id('tst','v') is not null
drop view tst;
go
create view tst
as
select * from test
In SQL 2016,you can use below syntax to drop
Drop view if exists dbo.tst
From SQL2016 CU1,you can do below
create or alter view vwTest
as
select 1 as col;
go
Regarding the error
'CREATE VIEW' must be the first statement in a query batch.
Microsoft SQL Server has a quirky reqirement that CREATE VIEW be the only statement in a batch. This is also true of a few other statements, such as CREATE FUNCTION. It is not true of CREATE TABLE, so go figure …
The solution is to send your script to the server in small batches. One way to do this is to select a single statement and execute it. This is clearly inconvenient.
The more convenient solution is to get the client to send the script in small isolated batches.
The GO keyword is not strictly an SQL command, which is why you can’t end it with a semicolon like real SQL commands. Instead it is an instruction to the client to break the script at this point and to send the portion as a batch.
As a result, you end up writing something like:
DROP VIEW IF EXISTS … ;
GO
CREATE VIEW … AS … ;
GO
None of the other database servers I have encountered (PostgreSQL, MySQL, Oracle, SQLite) have this quirk, so the requirement appears to be Microsoft Only.
DROP VIEW if exists {ViewName}
Go
CREATE View {ViewName} AS
SELECT * from {TableName}
Go
To cater for the schema as well, use this format in SQL 2014
if exists(select 1 from sys.views V inner join sys.[schemas] S on v.schema_id = s.schema_id where s.name='dbo' and v.name = 'someviewname' and v.type = 'v')
drop view [dbo].[someviewname];
go
And just throwing it out there, to do stored procedures, because I needed that too:
if exists(select 1
from sys.procedures p
inner join sys.[schemas] S on p.schema_id = s.schema_id
where
s.name='dbo' and p.name = 'someprocname'
and p.type in ('p', 'pc')
drop procedure [dbo].[someprocname];
go

How to check if a view exists that uses a table

Is it possible to check if a table is part of a view in same or different database using SQL Server Management Studio?
If it can be done through some plugins, that would be fine too.
Like this:
SELECT *
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
WHERE TABLE_SCHEMA = 'dbo' --(or whatever your Schema name is)
AND TABLE_NAME = 'YourTableName'
Should work on any ISO SQL compliant database, not just SQL Server.
Note that cross-database dependencies are another matter. In theory, they should show up here however, in practice this may be inconsistent because SQL Server does allow deferred resolution, even for Views, when it comes to cross-database references.
SELECT QUOTENAME(OBJECT_SCHEMA_NAME([object_id]))
+ '.' + QUOTENAME(OBJECT_NAME([object_id]))
FROM sys.sql_dependencies
WHERE referenced_major_id = OBJECT_ID(N'dbo.your_table_name');
Or:
SELECT referencing_schema_name, referencing_entity_name
FROM sys.dm_sql_referencing_entities(N'dbo.your_table_name', N'OBJECT');
However note that some of these methods, including sp_depends, INFORMATION_SCHEMA, sysdepends etc. are all prone to falling out of sync. More information here:
Keeping sysdepends up to date in SQL Server 2008
A quick example:
CREATE TABLE dbo.table1(id INT);
GO
CREATE VIEW dbo.view1
AS
SELECT id FROM dbo.table1;
GO
SELECT QUOTENAME(OBJECT_SCHEMA_NAME([object_id]))
+ '.' + QUOTENAME(OBJECT_NAME([object_id]))
FROM sys.sql_dependencies
WHERE referenced_major_id = OBJECT_ID('dbo.table1');
-- returns 1 row
GO
DROP TABLE dbo.table1;
GO
CREATE TABLE dbo.table1(id INT);
GO
SELECT QUOTENAME(OBJECT_SCHEMA_NAME([object_id]))
+ '.' + QUOTENAME(OBJECT_NAME([object_id]))
FROM sys.sql_dependencies
WHERE referenced_major_id = OBJECT_ID('dbo.table1');
-- returns 0 rows!!!!
If you execute the following, it will return rows again:
EXEC sp_refreshsqlmodule N'dbo.view1';
But who wants to be refreshing every view in the system, every time you want to check the metadata?
So you may want to combine this method with brute force parsing of the text for all your views:
SELECT name FROM sys.views
WHERE OBJECT_DEFINITION([object_id])
LIKE N'%your_table_name%';
That is liable to get some false positives depending on the name of your table, but it's probably a good cross-check.
To avoid this kind of issue, I've tried to get into the habit of creating my views WITH SCHEMABINDING (or just avoiding views as much as possible). Sure, that can become a pain when you need to change the table in a way that doesn't affect the view, but table changes should be taken seriously anyway.
For same databse, you can check dependencies for that table and see what other objects uses it.
EXEC sp_depends #objname = N'your_table_name' ;

Drop all temporary tables for an instance

I was wondering how / if it's possible to have a query which drops all temporary tables?
I've been trying to work something out using the tempdb.sys.tables, but am struggling to format the name column to make it something that can then be dropped - another factor making things a bit trickier is that often the temp table names contain a '_' which means doing a replace becomes a bit more fiddly (for me at least!)
Is there anything I can use that will drop all temp tables (local or global) without having to drop them all individually on a named basis?
Thanks!
The point of temporary tables is that they are.. temporary. As soon as they go out of scope
#temp create in stored proc : stored proc exits
#temp created in session : session disconnects
##temp : session that created it disconnects
The query disappears. If you find that you need to remove temporary tables manually, you need to revisit how you are using them.
For the global ones, this will generate and execute the statement to drop them all.
declare #sql nvarchar(max)
select #sql = isnull(#sql+';', '') + 'drop table ' + quotename(name)
from tempdb..sysobjects
where name like '##%'
exec (#sql)
It is a bad idea to drop other sessions' [global] temp tables though.
For the local (to this session) temp tables, just disconnect and reconnect again.
The version below avoids all of the hassles of dealing with the '_'s. I just wanted to get rid of non-global temp tables, hence the '#[^#]%' in my WHERE clause, drop the [^#] if you want to drop global temp tables as well, or use a '##%' if you only want to drop global temp tables.
The DROP statement seems happy to take the full name with the '_', etc., so we don't need to manipulate and edit these. The OBJECT_ID(...) NOT NULL allows me to avoid tables that were not created by my session, presumably since these tables should not be 'visible' to me, they come back with NULL from this call. The QUOTENAME is needed to make sure the name is correctly quoted / escaped. If you have no temp tables, #d_sql will be the empty string still, so we check for that before printing / executing.
DECLARE #d_sql NVARCHAR(MAX)
SET #d_sql = ''
SELECT #d_sql = #d_sql + 'DROP TABLE ' + QUOTENAME(name) + ';
'
FROM tempdb..sysobjects
WHERE name like '#[^#]%'
AND OBJECT_ID('tempdb..'+QUOTENAME(name)) IS NOT NULL
IF #d_sql <> ''
BEGIN
PRINT #d_sql
-- EXEC( #d_sql )
END
In a stored procedure they are dropped automatically when the execution of the proc completes.
I normally come across the desire for this when I copy code out of a stored procedure to debug part of it and the stored proc does not contain the drop table commands.
Closing and reopening the connection works as stated in the accepted answer. Rather than doing this manually after each execution you can enable SQLCMD mode on the Query menu in SSMS
And then use the :connect command (adjust to your server/instance name)
:connect (local)\SQL2014
create table #foo(x int)
create table #bar(x int)
select *
from #foo
Can be run multiple times without problems. The messages tab shows
Connecting to (local)\SQL2014...
(0 row(s) affected)
Disconnecting connection from (local)\SQL2014...

Stored procedures and the tables used by them

Is there a way to know what are the tables used by one stored procedure by doing an SQL query?
Best regards, and thanks for the help.
P.S.: I'm using SQL Server 2005.
This article on TechRepublic
Finding dependencies in SQL Server 2005
describes a way to do that:
This tutorial will show how you can
write a procedure that will look up
all of the objects that are dependent
upon other objects.
Here is the code to create the system stored procedure for finding object dependencies:
USE master
GO
CREATE PROCEDURE sp_FindDependencies
(
#ObjectName SYSNAME,
#ObjectType VARCHAR(5) = NULL
)
AS
BEGIN
DECLARE #ObjectID AS BIGINT
SELECT TOP(1) #ObjectID = object_id
FROM sys.objects
WHERE name = #ObjectName
AND type = ISNULL(#ObjectType, type)
SET NOCOUNT ON ;
WITH DependentObjectCTE (DependentObjectID, DependentObjectName, ReferencedObjectName, ReferencedObjectID)
AS
(
SELECT DISTINCT
sd.object_id,
OBJECT_NAME(sd.object_id),
ReferencedObject = OBJECT_NAME(sd.referenced_major_id),
ReferencedObjectID = sd.referenced_major_id
FROM
sys.sql_dependencies sd
JOIN sys.objects so ON sd.referenced_major_id = so.object_id
WHERE
sd.referenced_major_id = #ObjectID
UNION ALL
SELECT
sd.object_id,
OBJECT_NAME(sd.object_id),
OBJECT_NAME(referenced_major_id),
object_id
FROM
sys.sql_dependencies sd
JOIN DependentObjectCTE do ON sd.referenced_major_id = do.DependentObjectID
WHERE
sd.referenced_major_id <> sd.object_id
)
SELECT DISTINCT
DependentObjectName
FROM
DependentObjectCTE c
END
This procedure uses a Common Table
Expression (CTE) with recursion to
walk down the dependency chain to get
to all of the objects that are
dependent on the object passed into
the procedure. The main source of data
comes from the system view
sys.sql_dependencies, which contains
dependency information for all of your
objects in the database.
Try sp_depends, although you should probably recompile the stored procedure to update the statistics in the database.
Look up sp_depends system stored proc.
I think that as long as the stored procedure and the tables are all in the same database then you can right click on the procedure in SSMS and click "View Dependencies". I don't know the query behind the dialog though...
As others indicated you can use the Dependancies stored procedures; however, in my experience and this was back on SQL Server 2000, the depandancies were not always reliable. In some cases they weren't being updated. You can always go to the sysComments table assuming your schema is not encrypted.
declare #crlfSearch varchar(max),#objectSearch varchar(max),#escapeSearch varchar(max)
set #crlfSearch=('%bid' + char(13)+'%')
set #objectSearch='%bid %'
set #escapeSearch ='%[[]Bid]%'
select distinct so.name
from syscomments sc
inner join sysobjects so
on sc.id=so.id
where text like #objectSearch or text like #crlfSearch
or text like #escapesearch
This query looks for three common cases you might have to add some but basically we find where the table name has a space after it, (This helps to limit cases where the table name is part of another table name), Has a return at the end of it, or is escaped within brackets.