Create view must be the first statement in the batch - sql

I'm running a set of script files from a .NET based windows application. One of the files has the following script -
IF EXISTS(SELECT * FROM SYS.VIEWS WHERE NAME = 'TP_LEAVEDATA') EXEC SP_RENAME 'TP_LEAVEDATA', 'TP_LEAVEDATA_BKP_EXPORT_TEST1'
CREATE VIEW TP_LEAVEDATA AS
SELECT USERNAME, Dept, LeaveType, LeaveFrom, LeaveUpto FROM LeaveRequest_DATA
When I execute the script I get an error create view must be the first statement in the batch
I can not use GO keyword here because I'm running the scripts through my application, I can not use execute sp_executesql because there are similar files for creating stored procedures as well (which contain single inverted commas inside the query itself). What are the options that i have now ??
PS: The issue doesn't occur with create table command though.

You can use put GO before it:
IF EXISTS(SELECT * FROM SYS.VIEWS WHERE NAME = 'TP_LEAVEDATA') BEGIN
EXEC SP_RENAME 'TP_LEAVEDATA', 'TP_LEAVEDATA_BKP_EXPORT_TEST1' ;
END;
GO
CREATE VIEW TP_LEAVEDATA AS
SELECT USERNAME, Dept, LeaveType, LeaveFrom, LeaveUpto
FROM LeaveRequest_DATA;
Another option is to use dynamic SQL for the view creation.

Related

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

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'

Creating a view in tempdb in SQL Server through a post request

Since I need to send the query statement through a http post request there are certain limitations.
1. It should be a one liner
2. it should be created in tempdb since i am going to drop it afterwards.
since SQL server takes CREATE VIEW statement only in new line I am feeding new line characters to the statement. here is the statement:
DECLARE #NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10); ('USE tempdb;' +#NewLineChar + 'GO' +#NewLineChar +'CREATE VIEW temp_view AS select name from sys.databases')
This query gives me following error:
Msg 102, Level 15, State 1.
Incorrect syntax near 'USE tempdb;'. (Line 1)
what could be the problem ?
Thanks
edit: The same query works like this
USE tempdb;
GO
CREATE VIEW temp_view AS select name from sys.databases
where is the syntax error?
Since SQL server takes CREATE VIEW statement only in new line I am feeding new line characters to the statement.
I have never heard of such a requirement. What the documentation does state is: The CREATE VIEW must be the first statement in a query batch.
The statement you have in your question doesn't make sense. You can't just drop a VARCHAR in SSMS and expect SQL Server to just execute it.
What you probably want is something like the following:
USE tempdb;
DECLARE #stmt NVARCHAR(MAX)=N'CREATE VIEW temp_view AS SELECT name FROM sys.databases;';
EXECUTE sp_executesql #stmt;
Or in one line:
USE tempdb;DECLARE #stmt NVARCHAR(MAX)=N'CREATE VIEW temp_view AS SELECT name FROM sys.databases;';EXECUTE sp_executesql #stmt;
This is a bit long for a comment.
You can create a view in the current database with a name like _temp_<something>. You can even include session information if you want to emulate temporary tables.
Or, create a temporary table with no rows:
select top 0 *
into #temp
from <whatever>;
You can access the structure of this table.
If you are using a very recent version of SQL Server, use sp_describe_first_result_set (see here).

How to get results from "exec sp_showpendingchanges" into a table

EDIT: The things I've tried below came directly from the alleged duplicate. The solutions actually do work fine with a user defined sp (and probably most system sp's), but for whatever reason it doesn't work with this one.
I can run exec sp_showpendingchanges on the distribution publication database without any issues. However I want to capture the results in a table
I've tried:
SELECT * INTO #tmpTable
FROM OPENROWSET('SQLNCLI', 'Server=SERVER; Trusted_Connection=yes;',
'EXEC sp_showpendingchanges')
and:
SELECT * INTO #tmpTable
FROM OPENQUERY(SERVER, 'exec sp_showpendingchanges')
Both of these statements return an error that says: Invalid object name 'sysmergepublications'.
I tried to specify the initial catalog in the connection string and even tried adding a USE statement in the last parameter of each statement (i.e. I used an embedded EXEC statement with double-single quotes and all that). But I still end up with the same error.
So how can I get the results from exec sp_showpendingchanges into a temporary table, and preferably without having to define the table myself? If all else fails I will make a program in C#, but really hoping there's a simpler way to just do this with just SQL.
Here is a working example
You create a table
DECLARE #result_table TABLE
(
destination_server SYSNAME ,
pub_name SYSNAME ,
destination_db_name SYSNAME ,
is_dest_subscriber BIT ,
article_name SYSNAME ,
pending_deletes INT ,
pending_ins_and_upd INT
)
execute the script
INSERT INTO #result_table
EXEC sp_showpendingchanges
view the results
SELECT * FROM #result_table
I read your question but definetly cannot understand what the problem to create temp table. Anyway, if you can execute SP but get an error when you do it through linkedserver or openrowset - than problem is in permissions.
Check permissions on sysmergepublications table. If user, which you use for linked server or openrowset, has no grant on do select this table you need to add this permission to user.
I hope it will help you.

What's the scoping rule for temporary tables within exec within stored procedures?

Compare the following stored procedures:
CREATE PROCEDURE testProc1
AS
SELECT * INTO #temp FROM information_schema.tables
SELECT * FROM #temp
GO
CREATE PROCEDURE testProc2
AS
EXEC('SELECT * INTO #temp FROM information_schema.tables')
SELECT * FROM #temp
GO
Now, if I run testProc1, it works, and #temp seems to only exist for the duration of that call. However, testProc2 doesn't seem to work at all, since I get an Invalid object name '#temp' error message instead.
Why the distinction, and how can I use a temp table to SELECT * INTO if the source table name is a parameter to the stored procedure and can have arbitrary structure?
Note that I'm using Microsoft SQL Server 2005.
From BOL:
Local temporary tables are visible
only in the current session... ...
Temporary tables are automatically
dropped when they go out of scope,
unless explicitly dropped using DROP
TABLE
The distinction between your first and second procedures is that in the first, the table is defined in the same scope that it is selected from; in the second, the EXEC() creates the table in its own scope, so the select fails in this case...
However, note that the following works just fine:
CREATE PROCEDURE [dbo].[testProc3]
AS
SELECT * INTO #temp FROM information_schema.tables
EXEC('SELECT * FROM #temp')
GO
And it works because the scope of EXEC is a child of the scope of the stored procedure. When the table is created in the parent scope, it also exists for any of the children.
To give you a good solution, we'd need to know more about the problem that you're trying to solve... but, if you simply need to select from the created table, performing the select in the child scope works just fine:
CREATE PROCEDURE [dbo].[testProc4]
AS
EXEC('SELECT * INTO #temp FROM information_schema.tables; SELECT * FROM #temp')
GO
You could try using a global temp table (named ##temp not #temp). However be aware that other connections can see this table as well.

How to DROP a version of a Stored Procedure in SQL Server

We have some legacy stored procedures that use the now deprecated feature of SQL Server that allowed you to create multiple versions of a procedure within a procedure.
For instance we have..
[up_MyProc]
[up_MyProc];2
You can still create these "versions" by appending the version on the end of the name. However without dropping the procedure we'd like to drop the internal versions.
You cant seem to do
DROP PROC [up_MyProc];2
DROP PROC [up_MyProc;2]
Is there a way to drop the internal versions?
Unfortunately, no.
I've just tried sp_rename which failed too.
The new system views do not detect them either
CREATE PROC DBO.FOO;1
AS
SELECT 1
go
CREATE PROC DBO.FOO;2
AS
SELECT 2
go
--Can't find using new system views
SELECT * FROM sys.objects WHERE name LIKE '%foo%'
SELECT * FROM sys.sql_modules WHERE definition LIKE '%dbo.foo%SELECT%'
GO
--Found using legacy "system tables"
SELECT * FROM sysobjects WHERE name LIKE '%foo%'
SELECT * FROM syscomments WHERE text LIKE '%dbo.foo%SELECT%'
GO