Incorrect syntax near sp_refreshview - sql-server

One of our tables is loosing a column and related views need to be refreshed. I ran the procedure sp_refreshview ok on it's own for one view, although I had to pick the actual database, even though I had the DB.dbo.View_name extension.
I am now wanting to run a few of these update view statements in one script that does the table update too, but keep getting this error message saying incorrect syntax near sp_refreshview. I have tried putting go after the statement to contain it, with the USE [DB_Name] statement before each update. Like below:
use [DB1]
sp_refreshview 'DB1.dbo.View1'
go
use [DB2]
sp_refreshview 'DB2.dbo.View1'
go
It keep failing for some reason. Granted this is the first time I have set a batch script to update multiple views in different DBs so if there is a better way to do this I am open to suggestions.

To fix your syntax error, I believe all you are missing is an "EXEC" before your sp_refreshview's:
USE [DB1]
EXEC sp_refreshview 'DB1.dbo.View1'
GO
USE [DB2]
EXEC sp_refreshview 'DB2.dbo.View1'
GO

Related

SQL Server 2008R2: Linked server stored procedure to alter view failing

Our product inserts application data into a table utilizing two different databases [DB1],[DB2]. I've been asked to implement a high availability purge without having the Development Team update connection strings in code to point to a single database, as would be best practice. I have attempted the following:
Create a view on both [DB1] and [DB2] pointing to a primary table.
Created a secondary table that is identical.
Created stored procedures on both [DB1] and [DB2] to alter their respective views (Why can't SQL Server alter a view in a stored procedure?)
Create a job on [DB2] utilizing stored procedures to alter where the view points so while data is being purged from the primary table, inserts will still continue into the secondary.
The above works great on [DB2] and alters the view, changing where data is inserted. However, when the job (running on [DB2]) runs the step to update the view on [DB1] the following is thrown:
Subquery returned more than 1 value. This is not permitted when the
subquery follows = != < <= > >= or when the
subquery is used as an expression. [SQLSTATE 21000] (Error 512) The
statement has been terminated. [SQLSTATE 01000] (Error 3621). The
step failed.,00:00:00,16,3621,,,,0
I've attempted two different ways -
EXEC sp_executesql N'ALTER VIEW [dbo].[ApplicationEvent]
AS [some sql]'
and
DECLARE #sql varchar(max);
SET #sql = 'ALTER VIEW [dbo].[ApplicationEvent]
AS [some sql]'
exec(#sql);
both return the same error.
The views need to be pointed away at the same time, and only pointed back once the purge process is complete on the primary table. This is the reason for running both steps from the same job.
Is there away around the error that only occurs against the linked server execute call?
Thank you in advance for any assistance!
Additional Thoughts:
I've already attempted to disable all triggers on the tables to see if that was the issue per another thread I saw here.
Both created SP's work fine if run from their home Databases. Linked calls throw the error.
EDIT: while I still do not know why this error is being thrown... I've found a workaround for now.
After running a job that does as much as it can on [DB2] I have the job call another job on [DB1] that completes the tasks on DB that were erring out.
EXEC Server2.msdb.dbo.sp_start_job #job_name = N'Job2';
Doing this back and forth a few times got me to the result I wanted. I still would prefer to do this all in one job if possible as this seems a little hackish.
Stored Proc for altering View:
/****** Object: StoredProcedure [dbo].[AlterApplicaitonMessageViewSecondary] Script Date: 11/18/2014 4:01:00 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[AlterApplicaitonMessageViewSecondary]
AS
DECLARE #sql11 varchar(max);
Set #sql11 = 'ALTER VIEW [dbo].[ApplicationMessage2]
AS
--Select from local member table.
SELECT [Id]
,[EventId]
,[Timestamp]
,[Message]
,[Severity]
,[MerchantId]
,[ProviderId]
,[VisitId]
,[UserId]
,[Server]
,[Process]
,[ReferenceId]
FROM [DB1].[ApplicationEvent].[dbo].[ApplicationMessageSecondary]
with (nolock)';
exec(#sql11);

Can I recreate a temp table after dropping it?

Given:
code inside a stored proc:
select bleh
into #tblTemp
from FunctionThatReturnsTable('some','params')
-- do some stuff
drop table #tblTemp
-- Error on this command:
-- 'There is already an object named '#tblTemp' in the database.'
select bleh
into #tblTemp
from FunctionThatReturnsTable('some','other params')
Problem:
I can't recreate this temp table. My work around is to use #tmpTable1, #tmpTable2, #tempTable3 etc. Is there a way I can get around this? It would be nice just use one temp table each time.
If not, what is the reason for this?
As my comment reflected, I'm going to suggest that the answer is that you use a different #temp table name for each object that you create. It's kind of like saying to the doctor, "it hurts when I do this." His likely response is going to be, "stop doing that!"
The reason this is a problem is that SQL Server's parser attempts to parse the entire batch in one shot. It can clearly see that you are trying to create the same #temp table multiple times, but ignores the DROP command in between (I can't tell you exactly why that is, as I don't have access to the source code). This is the same reason you can't do this:
IF (1=1)
CREATE TABLE #foo(i INT);
ELSE
CREATE TABLE #foo(i VARCHAR(32));
The parser sees the two identical names, but can't really follow the IF/ELSE logic.
In addition to avoiding the problems multiple identically-named #temp tables causes the parser, another benefit to using unique names is that they can be re-used if you don't explicitly drop them. This will lighten the load on tempdb in terms of metadata / locking.
I ran into this problem with deleting+inserting column. The problem is probably with the parser, that it 'recognizes' the table on first create, and cannot see it was deleted.
I'd suggest using exec sp_executesql 'create table'
This is a feature by design and is clarified by Microsoft against Microsoft Connect Bug ID 666430
Please see a case study on the same at
temporary-table-could-not-be-re-created

SQL Server 2008 - sp_refreshview bombing out on some views

I've inherited a fairly substantial project, which makes extensive use of SQL Server (2005 and 2008) views.
One step in the build process is the call the sp_refreshviews system stored procedure, to make sure, no changes on any tables have broken our views. This works fine .... except for about three or four (out of 200+) views....
With those, it just bombs out - gives odd error messages like
Msg 15165, Level 16, State 1,
Procedure
sp_refreshsqlmodule_internal, Line 55
Could not find object
'vYourViewNameHere' or you do not
have permission.
which is dead wrong - that view does exist, and I definitely can select from it.
I cannot seem to find any good concise information about why this happens, what triggers it... any ideas? Is there anything I could do to detect such problematic views? Can I change their definitino so that they'd be refreshable again?
Update: I logged a bug report on Microsoft Connect for this - if you agree this seems odd and needs to be fixed, please vote for it!
https://connect.microsoft.com/SQLServer/feedback/details/676728/sp-refreshview-crashes-with-misleading-error-on-views-with-schemabinding
I noticed in the comments you mention it has SCHEMABINDING. I can almost guarantee that is the issue. Books online specifically says this is for use on non-schema bound views.
A scheme-bound view wouldn't allow a breaking change to occur so updating the meta-data is un-necessary. You can safely skip it.
You can identify all the schemabound views like this:
SELECT * FROM sys.views WHERE OBJECTPROPERTY(object_id, 'IsSchemaBound')=1
I ran into the same error when using sp_helptext. In my case the cause was using sp_rename to rename the view. The following code reproduces this error.
create view demo as select dummy = 1
go
exec sp_rename 'demo', 'new_demo'
go
exec sp_refreshview 'new_demo'
go
The only solution is to manually alter the view. Apply this fix to the above solution and you get:
create view demo as select dummy = 1
go
exec sp_rename 'demo', 'new_demo'
go
-- This statement fixes the problem
alter view new_demo as select dummy = 1
go
exec sp_refreshview 'new_demo'
go
My incarnation of this error was:
Msg 8116, Level 16, State 1, Procedure sp_refreshsqlmodule_internal,
Line 75 Argument data type int is invalid for argument 1 of substring
function.
This error message was being reported at various places in the db script. I would say wrong places. If I commented out the SQL this error was reported at, the same error would be reported elsewhere.
I commented out the following call in my script as a workaround, and the script would complete successfully.
-- EXECUTE sp_refreshview #viewName;
Note: My database didn't report having an schemabound views when running the query suggested in RThomas' adjacent answer https://stackoverflow.com/a/6460532/179972
UPDATE - SOLUTION:
After our database script ran successfully with the sp_refreshview command commented out (shown above), we then ran the view refresh code on its own, and it was successful too.
--
This answer doesn't make sense to me as to how it was able to work successfully, however I've documenting it here in case it proves helpful to somebody else.
To find which view is your problem add a print to the normal sppRefreshViews. Nothing earth shattering here, but i thought I would share.
CREATE procedure sppRefreshViews2
as
declare #t varchar (1024)
declare tbl_cur cursor for
select TABLE_NAME from INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'VIEW' and table_name like 'sp%'
OPEN tbl_cur
FETCH NEXT from tbl_cur INTO #t
WHILE ##FETCH_STATUS = 0
BEGIN
print #t
exec ('sp_refreshview ''' + #t + '''')
FETCH NEXT from tbl_cur INTO #t
END
CLOSE tbl_cur
DEALLOCATE tbl_Cur

What is the use of GO in SQL Server Management Studio & Transact SQL?

SQL Server Management Studio always inserts a GO command when I create a query using the right click "Script As" menu. Why? What does GO actually do?
It is a batch terminator, you can however change it to whatever you want
Since Management Studio 2005 it seems that you can use GO with an int parameter, like:
INSERT INTO mytable DEFAULT VALUES
GO 10
The above will insert 10 rows into mytable. Generally speaking, GO will execute the related sql commands n times.
The GO command isn't a Transact-SQL statement, but a special command recognized by several MS utilities including SQL Server Management Studio code editor.
The GO command is used to group SQL commands into batches which are sent to the server together. The commands included in the batch, that is, the set of commands since the last GO command or the start of the session, must be logically consistent. For example, you can't define a variable in one batch and then use it in another since the scope of the variable is limited to the batch in which it's defined.
For more information, see http://msdn.microsoft.com/en-us/library/ms188037.aspx.
GO is not a SQL keyword.
It's a batch separator used by client tools (like SSMS) to break the entire script up into batches
Answered before several times... example 1
Just to add to the existing answers, when you are creating views you must separate these commands into batches using go, otherwise you will get the error 'CREATE VIEW' must be the only statement in the batch. So, for example, you won't be able to execute the following sql script without go
create view MyView1 as
select Id,Name from table1
go
create view MyView2 as
select Id,Name from table1
go
select * from MyView1
select * from MyView2
Go means, whatever SQL statements are written before it and after any earlier GO, will go to SQL server for processing.
Select * from employees;
GO -- GO 1
update employees set empID=21 where empCode=123;
GO -- GO 2
In the above example, statements before GO 1 will go to sql sever in a batch and then any other statements before GO 2 will go to sql server in another batch. So as we see it has separated batches.
I use the GO keyword when I want a set of queries to get committed before heading on to the other queries.
One thing I can add is, when you have some variables declared before the GO command you will not be able to access those after the GO command. i.e
DECLARE #dt DateTime = GETDATE();
UPDATE MyTable SET UpdatedOn = #dt where mycondition = 'myvalue';
GO
-- Below query will raise an error saying the #dt is not declared.
UPDATE MySecondTable SET UpdatedOn = #dt where mycondition = 'myvalue'; -- Must declare the scalar variable "#dt".
GO
Update
I see, people requesting when to use the Go command, so I thought, I should add why I use the Go command in my queries.
When I have huge updates in the tables and I usually run these updates while going off from work (which means, I wouldn't be monitoring the queries), since it is convenient to come the next day and find the tables ready for other operations.
I use Go command when I need to run long operations and want to separate the queries and complete part of the transactions such as:
-- First Query
Update MyBigTable1 SET somecol1='someval1' where somecol2='someval2'
GO
-- Second Query
Update MyBigTable2 SET somecol1='someval1' where somecol2='someval2'
GO
-- Third Query
Update MyBigTable3 SET somecol1='someval1' where somecol2='someval2'
Executing above queries will individually commit the modifications without resulting in huge roll-back logs formation. Plus if something fails on third query, you know first 2 queries were properly executed and nothing would be rolled-back. So you do not need to spend more time updating/deleting the records again for the previously executed queries.
To sum it up in just one sentence, "I use the GO command as a check point as in the video games." If you fail after the check point (GO command), you do not need to start over, rather your game starts from the last check point.
Use herDatabase
GO ;
Code says to execute the instructions above the GO marker.
My default database is myDatabase, so instead of using myDatabase GO and makes current query to use herDatabase
One usage that I haven't seen listed is Error Resilience.
Since only the commands between two GOs are run at a time, that means a compile error in one command can be separated from others. Normally any compile errors in a batch cause the entire thing to not be executed.
exec do.Something
GO
sel from table
print 'here'
GO
print 'there'
In above, 'here' will not be printed because of the error in the 'sel' statement.
Now, adding a GO in the middle:
exec do.Something
GO
sel from table
GO
print 'here'
GO
print 'there'
You get an error for 'sel' as before, but 'here' does get output.
tldr; In most cases nowadays GO is mostly IMO optional. Using GO is best in LARGE transaction batches where you would have compiled many different scripts together in a large script and don't want errors where similar variables are used and so that parts of the transaction is committed to the server when desired instead of all of the script being rolled back due to an error.
LARGE TRANSACTION 1 --> Runs Successfully
GO; --> Is in the server
LARGE TRANSACTION 2 --> Runs Successfully
GO; --> Is in the server
LARGE TRANSACTION 3 --> Errors
GO; --> Without the other GO statements this would rollback Transaction 1 & 2
Not sure the best way to provide this SO wise however I do feel like what I've read so far doesn't really sum it all up and include an example that I've come across.
As stated many times before GO simply "commits" a batch of commands to the server.
I think understanding sessions also helps with understanding the necessity (or optionality) of the GO statement.
(This is where my technicality may fail but the community will point it out and we can make this answer better)
Typically developers are working in a single session and typically just executing simple statements to the database. In this scenario GO is optional and really...all one would do is throw it at the end of their statements.
Where it becomes more helpful is probably an option given by Jamshaid K. where you would have many large transactions that you would want committed in turn instead of all transactions being rolled back when one fails.
The other scenario where this also becomes helpful (which is the only other spot I've experienced it) is where many small transactions are compiled into one large script. For example
Dev 1 makes script 1
Dev 2 makes script 2
Dev 1 makes script 3
In order to deploy them a python script is written to combine the scripts so Script Master = script1 + script 2 + script 3.
GO statements would be required in the 3 scripts otherwise there could be errors where the scripts use conflicting variables or if script 3 fails the transactions from scripts 1 and 2 would be rolled back.
Now this process is probably archaic given current CI/CD solutions out there now but that would probably be another scenario where I could see GO being helpful/expected.
GO means asking SQL repeat this whatever number you add next to it. Just like saying in English; "Hey GO there 3 times.". Try below in SQL and the result will be rendering table 3 times.
SELECT * FROM Table
GO 3
It is a command to separate queries. If you are doing multiple selects it doesn't make a huge difference, the main use for me for example is when I am creating scripts and you need to create stored procedures and after give access or execute them. For example:
CREATE OR ALTER PROCEDURE dbo.select1
AS
BEGIN
SET NOCOUNT ON
SELECT 1
END
EXEC dbo.select1
This one it will create the stored procedure with everything on it, including the EXEC and it would end-up in a loop.
So that GO it will say that after end create the stored proc and after execute it.
CREATE OR ALTER PROCEDURE dbo.select1
AS
BEGIN
SET NOCOUNT ON
SELECT 1
END
GO
EXEC dbo.select1

Disappearing Stored Procedure

So, not sure what is happening. But I have stored procedure and it keeps disappearing out of my DB in SQL 2k.
I can add it again and then try to execute it from my web app and i get an exception saying the stored procedure cant be found. So then ill go back to management and refresh and its gone again !?!
here is the config for the stored proc:
set ANSI_NULLS OFF
set QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[USP_Equipment_Delete]
#EquipmentID int
AS
DELETE FROM [dbo].[Equipment]
WHERE
[EquipmentID] = #EquipmentID
None of my other stored procedure disappear. This is the only one. I have easily 100 in there. They all use the same SQLHelper class. This one just keeps disappearing!!!??!!
Any help or suggestions are appreciated!
Thanks so much!
You were creating this or another stored proc and at the end of your code, maybe after a comment, where you did not see it you have a drop of this proc.
Take a look at your db using:
select syo.name
from syscomments syc
join sysobjects syo on
syo.id = syc.id
where syc.[text] like '%DROP PROC%'
I had the same problem and I just fixed it:
In the script file it was missing the "GO" statement between the end of the stored procedure and the beginning of the next "IF EXIST THEN DROP" statement.
So what happened was that the drop statement was getting appended to the end of whatever stored procedure was above it in the script. So when the software ran the stored procedure it would drop whatever stored procedure was below it in the script.
It seems so obvious to us now but didn't make any sense at the time. We found it running the SQL profiler against a customer's database that was having the problem in the field.
Are you using the correct database?
Try
using [database name]
prior to executing your stored procedure, just to make sure.
Do you have a CREATE PROCEDURE anywhere? You can't ALTER a procedure if it doesn't exist.
Perhaps the code to access the stored procedure is using a different context other than dbo. Make sure to add dbo.USP_Equipment_Delete to the code using it.
I was facing the problem that all Stored Procedures with a create statement disappeared from the database after execution.
The Solution was: The database user should have the rights to drop,create and alter on the database in which the "Stored Procedures" are going to be created.
Perhaps there's a job thats restoring an old backup periodically?
Check if the "Initial Catalog" in your connection string is set to the correct database.
Put the database in single user mode (and make sure you're the single user) and check if the procedure still disappears every hour?
If it's there, then this query must return a record:
SELECT * FROM sysobjects
WHERE id = OBJECT_ID('USP_Equipment_Delete')
AND OBJECTPROPERTY(id, N'IsProcedure') = 1

Resources