I am trying to firstly check if the function exists then create it, if it doesn't exist.
I'm getting this error from the function:
IF NOT EXISTS (SELECT * FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[GetRelativeExpiry]') AND type in (N'U'))
BEGIN
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE FUNCTION [dbo].[GetRelativeExpiry]
(
#Date DATE,
#N INT
)
RETURNS DATE
AS
BEGIN
-- Declare the return variable here
DECLARE #Expiry as DATE;
IF #N > 0
BEGIN
SELECT #Expiry = MAX(E2.Expiry)
FROM (SELECT TOP(#N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry >= #date
ORDER BY E1.Expiry) AS E2
END
ELSE
BEGIN
SELECT #Expiry = MIN(E2.Expiry)
FROM (SELECT TOP(-#N) Expiry
FROM ExpiryDates E1
WHERE E1.Expiry <= #date
ORDER BY E1.Expiry DESC) AS E2
END
RETURN #Expiry
END
END
I am not sure why I am getting this error, could someone please help?
I am using Microsoft SQL Server Management Studio 2014
CREATE statements, whether they are for TYPE, PROCEDURE, FUNCTION, ... should always be the first statement in a batch.
To work around this in batches like yours execute the CREATE statement using sp_executesql like this:
EXEC sp_executesql N'
-- your CREATE statement here
';
If you are trying to do this in regular window within MS SQL Server Management Studio 2014 (or any prior version), where you would normally write all other queries, then your definition of function must be very first statement that is not commented.
See image below. If statement USE PTCRMstaging_test; was not commented, SQL Server Management Studio would give that same error.
Related
I have an existing sql server stored procedure, that I'm trying to update. Every time I run Alter Procedure on it, I get the following error:
SQL Error: Must declare the scalar variable "#varOne".
I've Googled around but nothing that I can find helps out with how to get past this error... :/ Procedure below:
ALTER PROCEDURE [dbo].[sp_test] (
-- Declare
#varOne tinyint,
#varTwo numeric(17,0)
) As
Set NoCount On
-- Select
Select *
Into #t
From SQL_Test.dbo.trans with (nolock)
Where test>=123
And Case #varOne When 1 Then rNo When 2 Then iNo When 3 Then sNo End = #varTwo
Union
Select *
From SQL_Test.dbo.trsave with (nolock)
Where date_time > DateAdd(dd, -60, GetDate())
And Case #varOne When 1 Then rNo When 2 Then iNo When 3 Then sNo End = #varTwo
EDIT: I solved the problem by dropping the original procedure, and recreating it. Still curious why the alter would not work. Guessing it is caused by the client using SQL Server 2012.
I solved the problem by dropping the original procedure, and recreating it. Still curious why the alter would not work. Guessing it is caused by the client using SQL Server 2012.
I have the following script in SQL Server 2014 for creating a scalar function named GetFiscalPeriod. The script must check for the existence of the function by its name before creating it.
USE [DatabaseName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS (select * from dbo.sysobjects where
id = object_id(N'[dbo].[GetFiscalPeriod]')
and OBJECTPROPERTY(id, N'IsScalarFunction') = 1)
--want to terminate the whole batch
RETURN --doesn't work the way I want
--seems to terminate IF batch only
GO
CREATE FUNCTION [dbo].[GetFiscalPeriod] ()
Returns INT
AS
BEGIN
RETURN (select MAX(Id) from dbo.__FiscalPeriod__);
END
I want it to terminate the whole thing as it reaches inside IF body. (RETURN)
The problem is no matter how I change the code, either it jumps to CREATE FUNCTION giving this error:
There is already an object named 'GetFiscalPeriod' in the database.
Or giving this syntax error (when I try to put CREATE FUNCTION in the IF clause):
'CREATE FUNCTION' must be the first statement in a query batch.
Question is:
Is there anyway to tell SQL to ignore the rest of the script when the object name exists?
Note:
I used to drop the function beforehand, and it works. But I don't want to drop and recreate everything every time.
...
IF EXISTS (select * from dbo.sysobjects where
id = object_id(N'[dbo].[GetFiscalPeriod]')
and OBJECTPROPERTY(id, N'IsScalarFunction') = 1)
DROP FUNCTION [dbo].[GetFiscalPeriod] --works
GO
CREATE FUNCTION [dbo].[GetFiscalPeriod] ()
...
You can check for existence, if existed ALTER else CREATE:
you must exec query as string.
IF not EXISTS (select * from dbo.sysobjects where id = object_id(N'[dbo].[GetFiscalPeriod]') and OBJECTPROPERTY(id, N'IsScalarFunction') = 1)
execute sp_executesql N'
CREATE FUNCTION [dbo].[GetFiscalPeriod] ()
Returns INT
AS
BEGIN
RETURN (select MAX(Id) from dbo.__FiscalPeriod__);
END'
else
N'
ALTER FUNCTION [dbo].[GetFiscalPeriod] ()
Returns INT
AS
BEGIN
RETURN (select MAX(Id) from dbo.__FiscalPeriod__);
END'
Without dynamic SQL, you'll need to raise an error to stop the calling application from running the remainder of the script. This can be done with the -b command-line argument in the case of SQLCMD:
SQLCMD -S YourServer -d YourDatabase -E -iYourScript.sql -I -b
The T-SQL within the executed script to raise the error and terminate execution:
IF OBJECT_ID(N'dbo.GetFiscalPeriod', 'FN') IS NOT NULL
RAISERROR('Function GetFiscalPeriod already exists', 16, 1);
If you are using SQL Server 2016 SP1 or later, you can use CREATE OR ALTER to avoid dropping the object beforehand. It seems to me you would want to recreate the function even if it exists since it may be different.
You can do that check in the following way using dynamic sql.
declare #var nvarchar(max)
='CREATE FUNCTION [dbo].[GetFiscalPeriod] ()
Returns INT
AS
BEGIN
RETURN (select MAX(Id) from dbo.__FiscalPeriod__);
END'
IF Not EXISTS (funname) --function name for which the existence should be
begin --checked
exec sp_executesql #var
end
GO
CREATE FUNCTION IF NOT EXISTS
Create the function first with this key phrase
I'm checking the validity of existing stored procedures, by obtaining their definition and running the ALTER statement on them.
The problem I have is that any stored procedure which doesn't compile (because a dependency has gone) isn't being flagged as such.
If I try to run the same ALTER command in SSMS I do get the error message.
EDIT: No, I don't....
DECLARE #def nvarchar(MAX)
BEGIN TRY
-- refresh the stored procedure
SELECT #def = REPLACE(definition,'CREATE PROCEDURE ','ALTER PROCEDURE ')
FROM sys.sql_modules
WHERE ... -- selecting/limiting clause
EXEC (#def);
END TRY
BEGIN CATCH
PRINT 'Validation failed : ' + ERROR_MESSAGE()
END CATCH
What do I have to do to trap the non-compile error? Thanks
SQL Server stored procedures use deferred name resolution:
When a stored procedure is created, the statements in the procedure are parsed for syntactical accuracy. If a syntactical error is encountered in the procedure definition, an error is returned and the stored procedure is not created. If the statements are syntactically correct, the text of the stored procedure is stored in the sys.sql_modules catalog view.
When a stored procedure is executed for the first time, the query processor reads the text of the stored procedure from the sys.sql_modules catalog view and checks that the names of the objects used by the procedure are present. This process is called deferred name resolution because table objects referenced by the stored procedure need not exist when the stored procedure is created, but only when it is executed.
So the behavior you observe is intentional. What you need is to find out what procedures depend on your missing tables. For this, see View the Dependencies of a Stored Procedure and the proper answer depends on your SQL Server version. SQL Server 2016 is somehow better at tracking this information and offers better views. Before that the process was notoriously difficult unreliable, read Keeping sysdepends up to date in SQL Server 2008.
Forget this - barking up the wrong tree ;-((
The stored proc will compile OK even if its dependencies have gone.
The editor in SSMS highlights the missing items, but doesn't stop the ALTER statement from working.
This query will identify all stored procs with missing dependencies:
-- table variable to store procedure names
DECLARE #v TABLE (RecID INT IDENTITY(1,1), spname sysname)
-- retrieve the list of stored procedures
INSERT INTO #v(spname)
SELECT
'[' + s.[name] + '].[' + sp.name + ']'
FROM sys.procedures sp
INNER JOIN sys.schemas s ON s.schema_id = sp.schema_id
WHERE is_ms_shipped = 0
AND sp.name like 'Get%'
-- counter variables
DECLARE #cnt INT, #Tot INT
SELECT #cnt = 1
SELECT #Tot = COUNT(*) FROM #v
DECLARE #spname sysname
DECLARE #ref nvarchar(MAX)
-- start the loop
WHILE #Cnt <= #Tot BEGIN
SELECT #spname = spname
FROM #v
WHERE RecID = #Cnt
BEGIN
SELECT #ref = referenced_entity_name
FROM sys.dm_sql_referenced_entities (#spname, 'OBJECT')
WHERE referenced_id IS NULL;
END
SET #Cnt = #cnt + 1
END
I have a stored procedure called myStoredProcedure in SQL Server 2008 including a code block like this:
...
declare #tempTable table
(
Id int,
Name varchar(100),
Category varchar(50),
Volume int
)
while #startTime<#endTime
begin
insert into #tempTable
EXEC R52_Calculations #param1, #param2, #param3
set #startTime = DATEADD(YEAR,1,#startTime)
end
select * from #tempTable
In this way, the stored procedure is working very well. I can connect to a table to this stored procedure in the SSRS 2008 without any warning or error. However, when I change #tempTable variable into #tempTable like below, I am getting a TimeOut error when I try to connect a table on SSRS 2008 to the updated stored procedure, even though the stored procedure is working very well again in SQL Server.
...
create table #tempTable
(
Id int,
Name varchar(100),
Category varchar(50),
Volume int
)
while #startTime<#endTime
begin
insert into #tempTable
EXEC R52_Calculations #param1, #param2, #param3
set #startTime = DATEADD(YEAR,1,#startTime)
end
select * from #tempTable
This is the error:
Timeout expired. The timeout period elapsed prior to completion of
the operation or the server is not responding. Warning: Null value is
eliminated by an aggregate or other SET operation.
Some more points:
when I remove the "while" loop and do the process only 1 time, there is no error occurring when I use #tempTable.
if I use #temptable (variable one), there is no error occurring at all.
Note that both queries are working fine in SQL Server, the errors are occurring when I try to connect a table on SSRS 2008 to the stored procedure
.
I could not find the reason why #temptable is causing an error. Any clue or help I will appreciate. Thanks.
When I'm trying to update some data like
if Exists(select * from sys.columns where Name = N'Enabled'
and Object_ID = Object_ID(N'SLBPool'))
begin
update SLBPool set SLBPool.Enabled=1
End
GO
it shows error "Invalid column name 'Enabled'" in SQL 2012,however ,not happened with 2008 R2
how come ?
The only way this should work on any version of SQL Server (certainly as far back as 2000, IIRC) is if you prevent the statement from being compiled until after you've evaluated the if condition - which would indicate dynamic SQL:
if Exists(select * from sys.columns where Name = N'Enabled'
and Object_ID = Object_ID(N'SLBPool'))
begin
exec sp_executesql 'update SLBPool set SLBPool.Enabled=1'
End
GO
Possibly this is because of collation prefs of server instance, check if this works, or produces some other error:
IF EXISTS(SELECT * FROM sys.columns WHERE name = N'Enabled'
AND object_id = OBJECT_ID(N'SLBPool'))
BEGIN
UPDATE SLBPool SET SLBPool.Enabled = 1
END
GO