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
Related
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
In my Stored procedure, I have added a command to create a hash temp table #DIR_CAT. But every time I execute the procedure I get this error:
"There is already an object named '#DIR_Cat' in the database."
Even when I have already created an Exists clause at the start of SP to check and drop the table if it is present. Any help is much appreciated.
The code goes like this.
if exists (select * from dbo.sysobjects where id = object_id(N'#DIR_Cat') )
drop table #DIR_Cat
/* some lines of code*/
CREATE TABLE #DIR_Cat (XMLDta xml)
/* some lines of code*/
INSERT #DIR_Cat exec (#stmt)
/* some lines of code*/
drop table #DIR_Cat
Main issue is you're not fully qualifying your objects. Your temp table lives in tempdb, whereas the system views use whatever database you're currently connected to by default. So essentially you're looking for the temp table, but you're looking in whatever database your currently connected to (which I'm guessing is not tempdb).
I'm assuming you're using SQL Server here, although you did also mention mysql in the tags. If that's what you're using, this code may not apply.
Here's the snippet I use for temp table drop/create
if object_id('tempdb.dbo.#<TableName, sysname, >') is not null drop table #<TableName, sysname, >
create table #<TableName, sysname, >
(
)
Side note, don't use dbo.sysobjects. That's a really old compatibility view. If you want to use objects, use sys.objects instead.
temp table does not exists in local DB sys.objects, it is in tempdb
you need to query tempb.sys.objects
the name of the temp table does not appear exactly as it is in the tempdb.sys.objects.
You can't query it just like
select *
from tempdb.sys.objects
where name = '#DIR_Cat' -- This does not works
you need to use object_id()
select *
from tempdb.sys.objects
where object_id = object_id('tempdb..#DIR_Cat')
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'
do you know why below code is wrong on ms sql server?
DROP TABLE [IF EXISTS] database.table1,
create table table1 (...)
That's SQL Server 2016 syntax.
For earlier versions, you can use the EXISTS function to check whether your table exists in the sys.tables list and drop it if it does. Then create a new table.
Somewhat like this:
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'table1' AND type = 'U') DROP TABLE table1;
CREATE TABLE table1
(
...
...
);
This syntax is only valid on SQL Server 2016, which is not released yet.
Are you sure that you are using that version?
Otherwise you could use the IF Exists that #pradeep-kumar suggests.
I am running a SELECT INTO statement like this so I can manipulate the data before finally dropping the table.
SELECT colA, colB, colC INTO #preop FROM tblRANDOM
However when I run the statement and then, without dropping the newly created table, I then run either of the following statements, the table isn't found? Even scanning through object explorer I can't see it. Where should I be looking?
SELECT [name] FROM sysobjects WHERE [name] = N'#preop'
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '#preop'
Temp tables aren't stored in the local database, they're stored in tempdb. Also their name isn't what you named them; it has a hex code suffix and a bunch of underscores to disambiguate between sessions. And you should use sys.objects or sys.tables, not the deprecated sysobjects (note the big warning at the top) or the incomplete and stale INFORMATION_SCHEMA views.
SELECT name FROM tempdb.sys.objects WHERE name LIKE N'#preop[_]%';
If you are trying to determine if such an object exists in your session, so that you know if you should drop it first, you should do:
IF OBJECT_ID('tempdb.dbo.#preop') IS NOT NULL
BEGIN
DROP TABLE #preop;
END
In modern versions (SQL Server 2016+), this is even easier:
DROP TABLE IF EXISTS #preop;
However if this code is in a stored procedure then there really isn't any need to do that... the table should be dropped automatically when the stored procedure goes out of scope.
I'd prefer to query tempdb in such manner:
IF EXISTS (SELECT * FROM tempdb.sys.objects
WHERE object_id = OBJECT_ID(N'tempdb.[dbo].[#MyProcedure]')
AND type in (N'P', N'PC'))
BEGIN
print 'dropping [dbo].[#MyProcedure]'
DROP PROCEDURE [dbo].[#MyProcedure]
END
GO
Below is how I got the columns for a temporary table:
CREATE TABLE #T (PK INT IDENTITY(1,1), APP_KEY INT PRIMARY KEY)
SELECT * FROM tempdb.INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME LIKE '#T%'