473,416 Members | 1,797 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,416 software developers and data experts.

Incorrect syntax in user-defined function

In the script below is the DDL to create some tables and a UDF.

What I'm interested in is the UDF at the end. Specifically, these few
lines:

--CLOSE OTRate
--DEALLOCATE OTRate
ELSE -- @NumRecords <= 0

If I uncommment CLOSE and DEALLOCATE and check the syntax I get a
message:

"Incorrect syntax near keyword ELSE"

Being a good little footsoldier, I want to release resources
explicitly, but clearly I'm putting the CLOSE and DEALLOCATE statements
in the wrong place.

Could someone please tell me where I ought to put them so that the
cursor is CLOSEd and DEALLOCATEd correctly.

By the way, I am not after negative comments on the data design, or the
logic (or lack of it) in the function, just why the syntax error
occurs.

Thanks as ever

Edward
if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[Employee]') and OBJECTPROPERTY(id, N'IsUserTable') =
1)
drop table [dbo].[Employee]
GO

if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[PurchaseOrder]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
drop table [dbo].[PurchaseOrder]
GO

if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[TimesheetItem]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
drop table [dbo].[TimesheetItem]
GO

if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[Work]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Work]
GO

if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[WorkOTRate]') and OBJECTPROPERTY(id, N'IsUserTable')
= 1)
drop table [dbo].[WorkOTRate]
GO

if exists (select * from dbo.sysobjects where id =
object_id(N'[dbo].[WorkOTRateDefaults]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
drop table [dbo].[WorkOTRateDefaults]
GO

CREATE TABLE [dbo].[Employee] (
[EmployeeID] [int] IDENTITY (1, 1) NOT NULL ,
[UserName] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[Title] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[FirstName] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[Surname] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
,
[DepartmentID] [int] NOT NULL ,
[JobDescription] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[StartDate] [smalldatetime] NOT NULL ,
[EndDate] [smalldatetime] NULL ,
[DefaultRatePerHour] [smallmoney] NULL ,
[EmailAddress] [varchar] (100) COLLATE SQL_Latin1_General_CP1_CI_AS
NULL ,
[UserGroupID] [int] NOT NULL ,
[Password] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[LastLogon] [datetime] NULL ,
[PasswordChange] [smalldatetime] NULL ,
[PreviousPassword1] [varchar] (50) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[PreviousPassword2] [varchar] (50) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[PreviousPassword3] [varchar] (50) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[PreviousPassword4] [varchar] (50) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL ,
[PreviousPassword5] [varchar] (50) COLLATE
SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[PurchaseOrder] (
[WorkOrderID] [int] IDENTITY (1, 1) NOT NULL ,
[WorkID] [int] NOT NULL ,
[OrderNo] [varchar] (20) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
,
[OrderDate] [datetime] NOT NULL ,
[OrderValue] [money] NOT NULL ,
[FixedPrice] [bit] NOT NULL ,
[Prepaid] [bit] NOT NULL ,
[AllocatedHours] [int] NULL ,
[RatePerHour] [money] NULL ,
[Summary] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Notes] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[TimesheetItem] (
[ItemID] [int] IDENTITY (1, 1) NOT NULL ,
[EmployeeID] [int] NOT NULL ,
[TypeID] [int] NOT NULL ,
[Start] [smalldatetime] NOT NULL ,
[DurationMins] [int] NOT NULL ,
[WorkID] [int] NULL ,
[WorkComponentID] [int] NULL ,
[WorkItemID] [int] NULL ,
[Notes] [varchar] (256) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[OffSite] [tinyint] NULL ,
[TravelTo] [smalldatetime] NULL ,
[TravelToMins] [int] NULL ,
[TravelFrom] [smalldatetime] NULL ,
[TravelFromMins] [int] NULL ,
[TravelMileage] [int] NULL ,
[NonChargeableMins] [int] NULL ,
[OTAuthorisedID] [int] NULL ,
[OTAuthorisedDate] [smalldatetime] NULL ,
[Abroad] [bit] NULL ,
[InconvAllowance] [char] (1) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
,
[ApprovalID] [int] NULL ,
[AprovalDate] [smalldatetime] NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Work] (
[WorkID] [int] IDENTITY (1, 1) NOT NULL ,
[WorkTypeID] [int] NULL ,
[WorkCode] [varchar] (10) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL ,
[Summary] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
,
[Notes] [varchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL ,
[Chargeable] [bit] NOT NULL ,
[Complete] [bit] NOT NULL ,
[ClientID] [int] NULL ,
[ClientContactID] [int] NULL ,
[Entered] [smalldatetime] NULL ,
[ApprovalRequired] [tinyint] NULL ,
[ColorCode] [varchar] (6) COLLATE SQL_Latin1_General_CP1_CI_AS NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[WorkOTRate] (
[WorkOTRateID] [int] IDENTITY (1, 1) NOT NULL ,
[WorkID] [int] NOT NULL ,
[WorkDay] [int] NOT NULL ,
[TimeFrom] [datetime] NOT NULL ,
[TimeTo] [datetime] NOT NULL ,
[RateMultiplier] [float] NOT NULL
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[WorkOTRateDefaults] (
[PKID] [int] IDENTITY (1, 1) NOT NULL ,
[WorkDay] [int] NOT NULL ,
[TimeFrom] [datetime] NULL ,
[TimeTo] [datetime] NULL ,
[RateMultiplier] [float] NOT NULL
) ON [PRIMARY]
GO

SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS OFF
GO

/*
Function to determine the actual cost, in minutes, of a particular
segment of work. This is what it does, or is supposed to do.
1. From the PARAMETER WorkID, determine the conclusion of the work
block associated with the TimesheetID - i.e. StartTime + DurationMins
2. Establish whether there are records in the WorkOTRate table
corresponding to this particular WorkID, weekday and time period
3. If there are, get the amount of minutes by which the work block
coincides.
4. If there are no such records, get the default values from the
WorkOTRateDefaults table
5. If the block doesn't cross any boundaries then it's just regular
work, so just count the minutes.

25/08/2005 EC
*/
CREATE FUNCTION fnGetWorkCostPerTimesheetItem(@TimesheetID int)

RETURNS float

AS

BEGIN

DECLARE

@OTRateTimeFrom datetime,
@OTRateTimeTo as datetime,
@OTRateMultiplier as float,
@EndTime datetime,
@ReturnValue as float,
@OrderRatePerHour as money,
@EmployeeRatePerHour as smallmoney,
@NumRecords as int,
@WorkID as int,
@EmployeeID as int,
@StartTime as smalldatetime,
@Duration as int,
@Found as int,
@Chargeable as bit

-- Get the various bits and bobs needed for the calculation
SET @ReturnValue = 0
SET @Found = 0

SELECT
@WorkID = WorkID,
@EmployeeID = EmployeeID,
@StartTime = Start,
@Duration = DurationMins
FROM
TimesheetItem
WHERE
ItemID = @TimesheetID

-- If this work is NOT chargeable, return 0
SELECT
@Chargeable = Chargeable
FROM
[Work]
WHERE
WorkID = @WorkID

IF @Chargeable = 1

BEGIN
SET @EndTime = DATEADD(mi, @Duration, @StartTime)

-- Get the rate per hour for this work
SELECT
@OrderRatePerHour = RatePerHour
FROM
PurchaseOrder
WHERE
WorkID = @WorkID

-- Get the rate per hour for the employee
SELECT
@EmployeeRatePerHour = DefaultRatePerHour
FROM
Employee
WHERE
(EmployeeID = @EmployeeID)

-- Find out if there's an OT Rate set up for this WorkID
SELECT
@NumRecords = Count(*)
FROM
WorkOTRate
WHERE
((WorkID = @WorkID) AND
(WorkDay = DATEPART(dd, @StartTime)))

IF @NumRecords > 0
BEGIN

DECLARE OTRate CURSOR FOR
SELECT
TimeFrom,
TimeTo,
RateMultiplier
FROM
WorkOTRate
WHERE
((WorkID = @WorkID) AND
(WorkDay = DATEPART(dw, @StartTime)))

OPEN OTRate
FETCH NEXT FROM OTRate INTO @OTRateTimeFrom, @OTRateTimeTo,
@OTRateMultiplier
WHILE (@@fetch_status=0)
BEGIN

-- Set the two time values so that they match the date under
consideration.
SET @OTRateTimeFrom = DATEADD(dd, DATEDIFF(dd, @OTRateTimeFrom,
@StartTime) ,@OTRateTimeFrom)
SET @OTRateTimeTo = DATEADD(dd, DATEDIFF(dd, @OTRateTimeTo ,
@StartTime) ,@OTRateTimeTo)
-- If the TimeTo part is < TimeFrom, then we know it crosses a
time boundary
IF @OTRateTimeTo < @OTRateTimeFrom
SET @OTRateTimeTo = DATEADD(dd, 1, @OTRateTimeTo)

-- If the time is between midnight and 8 a.m. it's the "next"
day
IF CONVERT(datetime, @OTRateTimeFrom, 108) BETWEEN '00:00' AND
'08:00'
SET @OTRateTimeFrom = DATEADD(dd, 1, @OTRateTimeFrom)

IF CONVERT(datetime, @OTRateTimeTo, 108) BETWEEN '00:00' AND
'08:00'
SET @OTRateTimeTo = DATEADD(dd, 1, @OTRateTimeTo)

/*
Ok, now we're in business. There are four possible scenarios
that we are interested in (ignoring when the Timesheet item period is
entirely outside the OT rate period)
NUMBER 1
S E
OT OT

NUBMER 2
S E
OT OT

NUMBER 3
S E
OT OT

NUBMER 4
S E
OT OT

*/
-- NUMBER 1
IF (@StartTime < @OTRateTimeFrom) AND (@EndTime > @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi,
@OTRateTimeFrom, @OTRateTimeTo)) * @OTRateMultiplier))
SET @Found = 1
END
--NUMBER 2
ELSE IF (@StartTime < @OTRateTimeFrom) AND (@EndTime BETWEEN
@OTRateTimeFrom AND @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi,
@OTRateTimeFrom, @EndTime)) * @OTRateMultiplier))
SET @Found = 1
END
-- NUMBER 3
IF (@StartTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo) AND
(@EndTime > @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi, @StartTime,
@OTRateTimeTo)) * @OTRateMultiplier))
SET @Found = 1
END
--NUMBER 4
ELSE IF (@StartTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo)
AND (@EndTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi, @StartTime,
@EndTime)) * @OTRateMultiplier))
SET @Found = 1
END
FETCH NEXT FROM OTRate INTO @OTRateTimeFrom, @OTRateTimeTo,
@OTRateMultiplier
END
END
--CLOSE OTRate
--DEALLOCATE OTRate
ELSE -- @NumRecords <= 0

BEGIN
DECLARE OTRate CURSOR FOR
SELECT
TimeFrom,
TimeTo,
RateMultiplier
FROM
WorkOTRateDefaults
WHERE
(WorkDay = DATEPART(dw, @StartTime))

OPEN OTRate
FETCH NEXT FROM OTRate INTO @OTRateTimeFrom, @OTRateTimeTo,
@OTRateMultiplier

WHILE (@@fetch_status=0)
BEGIN

-- Set the two time values so that they match the date under
consideration.
SET @OTRateTimeFrom = DATEADD(dd, DATEDIFF(dd, @OTRateTimeFrom,
@StartTime) ,@OTRateTimeFrom)
SET @OTRateTimeTo = DATEADD(dd, DATEDIFF(dd, @OTRateTimeTo ,
@StartTime) ,@OTRateTimeTo)

-- If the TimeTo part is < TimeFrom, then we know it crosses a
time boundary
IF @OTRateTimeTo < @OTRateTimeFrom
SET @OTRateTimeTo = DATEADD(dd, 1, @OTRateTimeTo)

-- If the time is between midnight and 8 a.m. it's the "next"
day
IF CONVERT(datetime, @OTRateTimeFrom, 108) BETWEEN '00:00' AND
'08:00'
SET @OTRateTimeFrom = DATEADD(dd, 1, @OTRateTimeFrom)

IF CONVERT(datetime, @OTRateTimeTo, 108) BETWEEN '00:00' AND
'08:00'
SET @OTRateTimeTo = DATEADD(dd, 1, @OTRateTimeTo)

/*
Ok, now we're in business. There are four possible scenarios
that we are interested in (ignoring when the Timesheet item period is
entirely outside the OT rate period)
NUMBER 1
S E
OT OT

NUBMER 2
S E
OT OT

NUMBER 3
S E
OT OT

NUBMER 4
S E
OT OT
*/
-- NUMBER 1
IF (@StartTime < @OTRateTimeFrom) AND (@EndTime > @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi,
@OTRateTimeFrom, @OTRateTimeTo)) * @OTRateMultiplier))
SET @Found = 1
END
--NUMBER 2
ELSE IF (@StartTime < @OTRateTimeFrom) AND (@EndTime BETWEEN
@OTRateTimeFrom AND @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi,
@OTRateTimeFrom, @EndTime)) * @OTRateMultiplier))
SET @Found = 1
END
-- NUMBER 3
IF (@StartTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo) AND
(@EndTime > @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi, @StartTime,
@OTRateTimeTo)) * @OTRateMultiplier))
SET @Found = 1
END
--NUMBER 4
ELSE IF (@StartTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo)
AND (@EndTime BETWEEN @OTRateTimeFrom AND @OTRateTimeTo)
BEGIN
SET @ReturnValue = @ReturnValue + (((DATEDIFF(mi, @StartTime,
@EndTime)) * @OTRateMultiplier))
SET @Found = 1
END
FETCH NEXT FROM OTRate INTO @OTRateTimeFrom, @OTRateTimeTo,
@OTRateMultiplier
END
END
CLOSE OTRate
DEALLOCATE OTRate

-- If there were no matching OT records, it's just a regular block
of work in normal hours
IF @Found = 0
SET @ReturnValue = @Duration
END

-- Finally we factor in the relation between the Employee's rate and
the Order's stated rate.
RETURN (@ReturnValue * (@EmployeeRatePerHour / @OrderRatePerHour))
END
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

Sep 2 '05 #1
3 6151
te********@hotmail.com wrote:
In the script below is the DDL to create some tables and a UDF.

What I'm interested in is the UDF at the end. Specifically, these few
lines:

--CLOSE OTRate
--DEALLOCATE OTRate
ELSE -- @NumRecords <= 0

I haven't actually read the code through thoroughly, so I don't know if
others are going to give you advice about doing it in a set oriented
fashion, but I believe that your close and deallocate are coming one
END too late. The two ENDs above them (to my reading) are the END of
the while loop and then the end of the if statement. When using ELSE,
the following should be adhered to:

IF <condition>
<statement or block>
ELSE
<statement or block>

where statement is either a single statement or:

BEGIN
<statement> [<statement>...]
END

Damien

Sep 2 '05 #2

Damien wrote:
te********@hotmail.com wrote:
In the script below is the DDL to create some tables and a UDF.

What I'm interested in is the UDF at the end. Specifically, these few
lines:

--CLOSE OTRate
--DEALLOCATE OTRate
ELSE -- @NumRecords <= 0

I haven't actually read the code through thoroughly, so I don't know if
others are going to give you advice about doing it in a set oriented
fashion, but I believe that your close and deallocate are coming one
END too late.


You're quite right - many thanks! As for doing it using sets - well, I
really don't have time!

Edward

Sep 2 '05 #3
(te********@hotmail.com) writes:
You're quite right - many thanks! As for doing it using sets - well, I
really don't have time!


But you assume that anyone will have the time to run that code? I hope
that you can find the time to test it on full-size data, before you
devote your important time to something else!

--
Erland Sommarskog, SQL Server MVP, es****@sommarskog.se

Books Online for SQL Server SP3 at
http://www.microsoft.com/sql/techinf...2000/books.asp

Sep 2 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Amit D.Shinde | last post by:
Hi Experts, i am writting a stored procedure in sql server 7. Its a simple stored procedure It is my first stored procedure. I want insert a record in table if the primary key field user id...
2
by: Roger R. Smith | last post by:
I see this error in my ASP .NET code: I am trying to execute the following: private const string SQL_SELECT_USER = "SELECT User.Email, User.FirstName, User.LastName, User.Status, User.Phone,...
1
by: bdastani | last post by:
I am trying to initialize a dataReader in C#, but I keep on gettin an exception error stating the following: System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior cmdBehavior,...
2
by: Jon | last post by:
hi, i was trying to create a DB in a SQL Server. but when i try to connect it with : Dim conn As SqlConnection = New SqlConnection("Initial Catalog=master; " & _ "Data Source=SERVER-MACHINE;" &...
6
by: ypjofficial | last post by:
HI, I have following terrific confusion. class test { public: int i; int * j; int **k;
1
by: Sandesh | last post by:
Hello All, Me saying " has any body come across such error would be underestimating". Well I am getting a very peculiar and unique error "Line 1: Incorrect syntax near 'Actions'." ...
6
by: martin1 | last post by:
I just use DataSet to bind DataSetGrid and display from SQL DB. when starting run in Visual Studio 2005, get "Line 1: Incorrect syntax near '1'" error message from below fill line, ...
0
by: roamnet | last post by:
hi i created database file with .mdf extention ,sql server as a source and use grid view to display data there're no problem in data retrieve and display,but i want to edit it or insert new...
1
by: karenkksh | last post by:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. ...
27
by: dennis1989 | last post by:
Im having problem running the program. Its say i have incorrect syntax at my strsql coding Private Sub ComboBox1_Change() Dim rst As ADODB.Recordset 'Initialize Recordset ...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.