Can I make this stored procedure faster - sql

I have the stored procedure below. This stored procedure runs in 3-4 seconds even on my developer computer but on the server it takes 15-20 seconds. I tried to change some of subqueries to cross apply and some to outer apply. But it caused to take more longer time.
#startDate datetime ,
#endDate datetime ,
#customerId int
;WITH t1(Plate,UsedFuelTypeUID,RemainingBefore,DateRangeTotal,DateRangeTransactionsTotal,RemaininCurrent) AS
(
select
v.Plate, v.UsedFuelTypeUID,
isnull((select isnull( sum(vls1.FT_TotalLimit),0)
from VehicleChildLog vls1
where vls1.VehicleChildId =v.VehicleID and vls1.UpdateDate < #startDate
),0)-
isnull((select isnull( sum(t1.Liter),0) from Transactions t1
where t1.VehicleChildID=v.VehicleID and t1.SaleDate <#startDate
),0)as RemainingBefore,
sum(vl.FT_TotalLimit) DateRangeTotal,
isnull((select isnull( sum(t1.Liter),0) from Transactions t1
where t1.VehicleChildID=v.VehicleID and t1.SaleDate between #startDate and #endDate
),0) as DateRangeTransactionsTotal,
(v.FT_TotalLimit - v.FT_UsedTotalLimit) as RemainingCurrent
from VehicleChildLog vl
inner join VehiclesChild v on vl.VehicleChildId = v.VehicleID
where vl.CustomerChildID = #customerId and vl.UpdateDate between #startDate and #endDate
group by
v.VehicleID, v.Plate, v.UsedFuelTypeUID
,v.FT_TotalLimit - v.FT_UsedTotalLimit
)
select *, t1.RemainingBefore+t1.DateRangeTotal-t1.DateRangeTransactionsTotal as RemainingAfter from t1 ;
Table structure is below
[Transactions]
(
[TransactionID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[SaleDate] [datetime] NULL,
[Liter] [float] NULL,
[VehicleChildID] [int] NULL
...
)
[VehiclesChild]
(
[VehicleID] [int] IDENTITY(1,1) NOT NULL,
[CustomerChildID] [int] NULL,
[Plate] [varchar](16) NULL,
[UsedFuelTypeUID] [int] NULL,
[FT_TotalLimit] [float] NULL,
[FT_UsedTotalLimit] [float] NULL
...
)
[VehicleChildLog]
(
[VehiclesChildLogId] [int] IDENTITY(1,1) NOT NULL,
[VehicleChildId] [int] NOT NULL,
[CustomerChildId] [int] NOT NULL,
[FT_TotalLimit] [float] NULL,
[FT_UsedTotalLimit] [float] NULL,
[UpdateDate] [datetime] NULL
...
)

Related

Create interval for recording

I have a table of schedule templates.
CREATE TABLE [dbo].[Template]
(
[ID] [uniqueidentifier] NOT NULL,
[Name] [nvarchar](50) NULL,
[Interval] [nvarchar](50) NULL,-- reception interval in minutes
[Activate] [bit] NOT NULL,-- is the template active or not
) ON [PRIMARY]
Therefore, only one template is active at any time, and for each template there is an n-th number of schedule intervals
CREATE TABLE [dbo].[Schedule]
(
[ID] [uniqueidentifier] NOT NULL,
[TemplateID] [uniqueidentifier] NULL,
[StartTime] [nvarchar](50) NULL, --start of available recording time
[EndTime] [nvarchar](50) NULL,--end of available recording time
[Monday] [bit] NULL,-- True or false whether the entry is available on Monday
[Tuesday] [bit] NULL,
[Wednesday] [bit] NULL,
[Thursday] [bit] NULL,
[Friday] [bit] NULL,
[Saturday] [bit] NULL,
[Sunday] [bit] NULL
) ON [PRIMARY]
I also have a table in which records and occupied time are already stored:
CREATE TABLE [dbo].[EventRecord]
(
[ID] [uniqueidentifier] NOT NULL,
[PeopleID] [uniqueidentifier] NULL,
[TemplateID] [uniqueidentifier] NULL,
[DateTime] [datetime] NULL,-- date and time of an already created entry
[Interval] [nvarchar](max) NULL,
[CheckOut] [bit] NULL,
[Details] [nvarchar](max) NULL
) ON [PRIMARY]
I need to write a stored procedure (query) that would return the available time for recording (if possible, in one query) given:
Reception interval
Already taken time by other records
Days of the week.
I can build the intervals of one Schedule, but how can I do this for all Schedules of one template and exclude the time for which I signed up.
DECLARE #intervalMinutes int = 10
DECLARE #myDates TABLE
(
startTime datetime,
endTime datetime
)
DECLARE #startTime DATETIME = '2016-07-10 08:00'
DECLARE #endTime DATETIME = '2016-07-10 22:00'
;WITH CTE AS
(
SELECT #startTime st
UNION ALL
SELECT DATEADD (MINUTE, #intervalMinutes, st) st
FROM cte
WHERE DATEADD (MINUTE, #intervalMinutes, st) < #endTime
)
SELECT st, DATEADD (MINUTE, #intervalMinutes, st)
FROM cte

Stored procedure throws an error while getting data from two table using UNION

I have two tables which are shown in this screenshot:
I am writing a stored procedure which will return data from both tables:
ALTER PROCEDURE [dbo].[GetInventoryDetails]
#MaterialId INT
AS
BEGIN
SELECT
tms.Material_ID AS MaterialId,
tmm.Name As MaterialName,
CONVERT(varchar,Quantity) AS AddedQuantity,
UtilizedQuantity ='-',
tcl.LedgerName AS SupplierName,
UsedFor = '-',
tmm.CurrentStock,
tmm.OpeningStock,
CONVERT(DATETIME,CONVERT(VARCHAR(100), tms.Material_Date, 112)) AS MaterialDate,
tms.Narration AS Narration
FROM
tblMaterialSheet tms
JOIN
tblMaterialMaster tmm ON tmm.Material_ID = tms.Material_ID
JOIN
tblCompanyLedger tcl ON tcl.Pk_LedgerId = tms.Ledger_ID
WHERE
tms.Material_ID = #MaterialId
AND tms.isActive = 1
UNION
SELECT
tmu.Material_ID AS MaterialId,
tmm.Name As MaterialName,
AddedQuantity = '-',
CONVERT(varchar,Utilized_Quantity) AS UtilizedQuantity,
CONVERT(DATETIME,CONVERT(VARCHAR(100), Utilization_Date, 112)) AS MaterialDate,
SupplierName = '-',
tbst.Name AS UsedFor,
tmm.CurrentStock,
tmm.OpeningStock,
tmu.Narration As Narration
FROM
tblMaterialUtilization tmu
JOIN
tblMaterialMaster tmm ON tmm.Material_ID = tmu.Material_ID
JOIN
tblBuildingSubTask tbst ON tbst.BuildingSubTask_ID = tmu.BuildingSubTask_ID
WHERE
tmu.Material_ID = #MaterialId
AND tmu.isActive = 1
END
When I call the stored procedure, it throws an error:
Conversion failed when converting date and/or time from character string.
Table structure: tblmaterialsheet
CREATE TABLE [dbo].[tblMaterialSheet]
(
[MaterialSheet_ID] [int] IDENTITY(1,1) NOT NULL,
[Company_ID] [int] NOT NULL,
[User_ID] [int] NOT NULL,
[BuildingSubTask_ID] [int] NOT NULL,
[Material_Date] [datetime] NOT NULL,
[Material_ID] [int] NOT NULL,
[Unit_ID] [int] NOT NULL,
[Quantity] [decimal](10, 2) NOT NULL,
[Size_ID] [int] NULL,
[Height] [decimal](6, 2) NULL,
[Width] [decimal](6, 2) NULL,
[Rate_Per_Unit] [money] NULL,
[Paid_Amount] [money] NULL,
[Total_Amount] [money] NULL,
[Vehical_No] [varchar](50) NULL,
[Ledger_ID] [int] NULL,
[Narration] [varchar](max) NULL,
[Challan_No] [int] NULL,
[Bill_ID] [int] NULL,
[isBilled] [bit] NOT NULL,
[Approval] [varchar](50) NULL,
[Approval_ModifiedDate] [datetime] NULL,
[UploadImage] [image] NULL,
[isActive] [bit] NOT NULL,
[CreatedBy] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedBy] [int] NULL,
[ModifiedDate] [datetime] NULL
)
Table structure : tblMaterialUtilization
CREATE TABLE [dbo].[tblMaterialUtilization]
(
[MaterialUtilization_ID] [int] IDENTITY(1,1) NOT NULL,
[Company_ID] [int] NOT NULL,
[User_ID] [int] NOT NULL,
[BuildingSubTask_ID] [int] NOT NULL,
[Material_ID] [int] NOT NULL,
[Utilization_Date] [datetime] NOT NULL,
[Utilized_Quantity] [decimal](10, 2) NOT NULL,
[Narration] [varchar](max) NOT NULL,
[IsActive] [bit] NOT NULL,
[CreatedBy] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedBy] [int] NULL,
[ModifiedDate] [datetime] NULL
)
Table structure : tblMaterialMaster
CREATE TABLE [dbo].[tblMaterialMaster]
(
[Material_ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](100) NOT NULL,
[Unit_ID] [int] NOT NULL,
[IsActive] [bit] NOT NULL,
[CreatedBy] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedBy] [int] NULL,
[ModifiedDate] [datetime] NULL,
[OpeningStock] [numeric](18, 0) NULL,
[PurchaseLedger] [numeric](18, 0) NULL,
[CurrentStock] [numeric](18, 0) NULL
)
Table structure : tblBuildingSubTask
CREATE TABLE [dbo].[tblBuildingSubTask]
(
[BuildingSubTask_ID] [int] IDENTITY(1,1) NOT NULL,
[BuildingTask_ID] [int] NOT NULL,
[Name] [varchar](200) NOT NULL,
[Narration] [varchar](max) NULL,
[StartDate] [datetime] NULL,
[TargetCompletionDate] [datetime] NULL,
[ActualCompletionDate] [datetime] NULL,
[IsActive] [bit] NOT NULL,
[CreatedBy] [int] NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[ModifiedBy] [int] NULL,
[ModifiedDate] [datetime] NULL
)
How to solve this error?
TRY THIS NOW: The order of the column were not in the same order so it was getting the different datatype values for the same column. Datatype and Order is most important in the UNION
ALTER PROCEDURE [dbo].[GetInventoryDetails]
#MaterialId int
AS
BEGIN
SELECT
tms.Material_ID AS MaterialId,
tmm.Name As MaterialName,
CONVERT(varchar,Quantity) AS AddedQuantity,
UtilizedQuantity ='-',
tcl.LedgerName AS SupplierName,
UsedFor='-',
tmm.CurrentStock,
tmm.OpeningStock,
CONVERT(DATETIME,CONVERT(VARCHAR(100), tms.Material_Date, 112)) AS MaterialDate,
tms.Narration As Narration
FROM
tblMaterialSheet tms
JOIN tblMaterialMaster tmm on tmm.Material_ID = tms.Material_ID
JOIN tblCompanyLedger tcl on tcl.Pk_LedgerId = tms.Ledger_ID
WHERE
tms.Material_ID = #MaterialId
AND
tms.isActive = 1
UNION
SELECT
tmu.Material_ID AS MaterialId,
tmm.Name As MaterialName,
AddedQuantity = '-',
CONVERT(varchar,Utilized_Quantity) AS UtilizedQuantity,
SupplierName = '-', --Moved up
tbst.Name AS UsedFor, --Moved up
tmm.CurrentStock, --Moved up
tmm.OpeningStock, --Moved up
CONVERT(DATETIME,CONVERT(VARCHAR(100), Utilization_Date, 112)) AS MaterialDate,
tmu.Narration As Narration
FROM
tblMaterialUtilization tmu
JOIN tblMaterialMaster tmm on tmm.Material_ID = tmu.Material_ID
JOIN tblBuildingSubTask tbst on tbst.BuildingSubTask_ID = tmu.BuildingSubTask_ID
WHERE
tmu.Material_ID = #MaterialId
AND
tmu.isActive = 1
END
The troubleshooting direction I'd take:
Look at your SQL. You're looking for anything that might be converting something of non-date type to date type. Your error probably means there's data somewhere you're converting to date that can't be converted. Be aware that this can include comparisons or functions that output a date.
Looking at your example, without knowing that actual data types, the only place I can see this happening is the explicit CONVERT functions on tms.Material_Date and Utilization_Date. I'd quickly comment these out and run each of the halves of the UNION separately. If they work, I could uncomment one or other until I figure out which field is causing the error. If they work independently but not unioned, I know that it's the after-union fields getting converted to date because the pre-union field is date.
Say it's the first half, before the union. I'd run:
SELECT * As Narration
FROM
tblMaterialSheet tms
JOIN tblMaterialMaster tmm on tmm.Material_ID = tms.Material_ID
JOIN tblCompanyLedger tcl on tcl.Pk_LedgerId = tms.Ledger_ID
WHERE
tms.Material_ID = #MaterialId
AND
tms.isActive = 1
AND
ISDATE(tms.Material_Date) = 0
You might need to work outwards in your converting to see where it falls over, e.g.,
AND
ISDATE(CONVERT(VARCHAR(100), tms.Material_Date, 112))
Then you should have a good idea about the problem.
Incidentally,
CONVERT(DATETIME,CONVERT(VARCHAR(100), Utilization_Date, 112))
looks very odd - what are you trying to achieve here by converting a date to varchar and back?
When you write a UNION or UNION ALL, You should make sure the following
No of Columns should be Same for Each Select Should Be same
Data Type of Column coming on the same position of each select Should be same
Suppose I have a column with character datatype for the first select and I'm trying to union it with a DateTime datatype, then I will get the error
SELECT 'ABCD'
UNION ALL
SELECT GETDATE()
This will throw the error
Msg 241, Level 16, State 1, Line 1
Conversion failed when converting date and/or time from character string.
because the datatypes do not match.
And this will cause another error:
SELECT 'ABCD',GETDATE()
UNION ALL
SELECT GETDATE()
Like this:
Msg 205, Level 16, State 1, Line 1
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
because the number of columns does not match.
So make sure that the datatypes match for each column in your UNION and if they does not match, try Cast or Convert

t-sql end of month insert

I have created two database tables named TSALESFACT and DimDate. TSALESFACT table contains the monthly sales target values. And DimTime contains the date values which begins from 01/01/2005.
CREATE TABLE [dbo].[TSalesFact](
[DateID] [smalldatetime] NULL,
[YearID] [int] NOT NULL,
[MonthID] [int] NOT NULL,
[SeasonID] [char](10) NOT NULL,
[DepartmentID] [char](10) NOT NULL,
[SalesAmount] [int] NOT NULL
)
CREATE TABLE [dbo].[dim_Date](
[ID] [int] NOT NULL,
[Date] [datetime] NOT NULL,
[Day] [char](2) NOT NULL,
[DaySuffix] [varchar](4) NOT NULL,
[DayOfWeek] [varchar](9) NOT NULL,
[DOWInMonth] [tinyint] NOT NULL,
[DayOfYear] [int] NOT NULL,
[WeekOfYear] [tinyint] NOT NULL,
[WeekOfMonth] [tinyint] NOT NULL,
[Month] [char](2) NOT NULL,
[MonthName] [varchar](9) NOT NULL,
[Quarter] [tinyint] NOT NULL,
[QuarterName] [varchar](6) NOT NULL,
[Year] [char](4) NOT NULL,
[StandardDate] [varchar](10) NULL,
[HolidayText] [varchar](50) NULL)
I would like to INSERT these sales target values into a new table named DailySalesTargets. But, the main purpose of this operation is writing the target sales to the each of end of month date. All of the date values for the relevant month will be zero. My desired resultset for this operation is like below:
How can I achieve this? Any idea?
I think this is what you are trying to do.
insert into [DailySalesTargets]([DateID],[YearID],[MonthID],
[SeasonID],[DepartmentID],[SalesAmount])
select d.[Date],d.[Year],d.[Month]
,dptSeason.[SeasonID],dptSeason.[DepartmentID]
,case when EOMONTH(d.[Date])=s.[DateID] then s.[SalesAmount] else 0 end as [SalesAmount]
from [dbo].[dim_Date] d
cross join (select distinct [DepartmentID],[SeasonID] from [dbo].[TSalesFact]) dptSeason
left join [dbo].[TSalesFact] s on d.[Date] = s.[DateID]
and s.[DepartmentID]=dptSeason.[DepartmentID]
and s.[SeasonID]=dptSeason.[SeasonID]

Error converting data type varchar to bigint in stored procedure

I'm trying to call this procedure with the usp_TimesheetsAuditsLoadAllbyId 42747, NULL command.
But I always get an error
Msg 8114, Level 16, State 5, Procedure usp_TimesheetsAuditsLoadAllById, Line 9
Error converting data type varchar to bigint.
The ID of TimesheetsAudits table is a bigint type. I tried several types of conversions and casts, but I'm really stuck right now.
Hope somebody can help. Thanks
ALTER PROCEDURE [dbo].[usp_TimesheetsAuditsLoadAllById]
(
#Id INT,
#StartDate DATETIME
)
AS
BEGIN
SET NOCOUNT ON
SELECT TOP 51 *
FROM
(SELECT TOP 51
ID,
Type,
ReferrerId,
CAST(Description AS VARCHAR(MAX)) AS Description,
OnBehalfOf,
Creator,
DateCreated
FROM
TimesheetsAudits
WHERE
(ReferrerID = #Id) AND
(#StartDate IS NULL OR DateCreated < #StartDate)
ORDER BY
DateCreated DESC
UNION
SELECT TOP 51
tia.ID,
tia.Type,
tia.ReferrerId,
'[Day: ' + CAST(DayNr AS VARCHAR(5)) + '] ' + CAST(tia.Description AS VARCHAR(MAX)) AS Description,
tia.OnBehalfOf,
tia.Creator,
tia.DateCreated
FROM
TimesheetItemsAudits tia
INNER JOIN
TimesheetItems ti ON tia.ReferrerId = ti.ID
WHERE
(ti.TimesheetID = #Id) AND
(#StartDate IS NULL OR tia.DateCreated < #StartDate)
ORDER BY
tia.DateCreated DESC) t
ORDER BY
t.DateCreated DESC
END
Table definition for tables from comments:
CREATE TABLE [dbo].[TimesheetsAudits](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[Type] [tinyint] NOT NULL,
[ReferrerId] [varchar](15) NOT NULL,
[Description] [text] NULL,
[OnBehalfOf] [varchar](10) NULL,
[Creator] [varchar](10) NOT NULL,
[DateCreated] [datetime] NOT NULL
)
CREATE TABLE [dbo].[TimesheetItemsAudits](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[Type] [tinyint] NOT NULL,
[ReferrerId] [varchar](15) NOT NULL,
[Description] [text] NULL,
[OnBehalfOf] [varchar](10) NULL,
[Creator] [varchar](10) NOT NULL,
[DateCreated] [datetime] NOT NULL
)
You perform an INNER JOIN of [dbo].[TimesheetsAudits] and TimesheetItems ti ON tia.ReferrerId = ti.ID
tia.[ReferrerId] is varchar and ti.[ID] is [bigint].
I'd expect a value in tia.[ReferrerId] that cannot be converted to bigint.
Try the following:
SELECT [ReferrerId] FROM TimesheetItemsAudits WHERE ISNUMERIC(ReferrerId) = 0
This may help you to find the "offending rows".

SQL select all records only if the sum is greater than 0

I have the following SQL;
ALTER PROCEDURE [dbo].[MyReport]
#startdate datetime,
#enddate datetime
AS
/* Return the event plan (coming events) for a specific volunteer */
declare #sd datetime
declare #ed datetime
/* Ensure that the start and end dates covert whole days */
set #sd = convert(varchar(10),#startdate,120) + ' 00:00:00'
set #ed = convert(varchar(10),#enddate,120) + ' 23:59:59'
SELECT
E.EventID, E.EventDate, E.StartTime, E.StartLocation, E.EndTime,
E.EndLocation, E.Charged, E.Actual,E.ChargeRate, E.Cost,
E.Persons, E.Reason,
C.ClientID, C.Address1, C.Address2,
C.Town, C.County, C.Postcode,
C.InvoiceName, C.InvoiceAddress1, C.InvoiceAddress2,
C.InvoiceTown, C.InvoiceCounty, C.InvoicePostCode,
ISNULL(C.Surname, '') + ', ' + ISNULL(C.Forename, '') AS ClientSurnameForename
FROM
vEvents E
INNER JOIN
vClients C ON E.ClientID = C.ClientID
WHERE
(E.EventDate BETWEEN #sd AND #ed)
AND E.SchemeID = 4
ORDER BY
c.Surname, c.Forename, E.EventDate, E.StartTime, E.EndTime
I need to sum the column E.Charged to check see if the amount for the client is greater than 0 before returning the recordset. I have tried the following:
ALTER PROCEDURE [dbo].[MyReport]
#startdate datetime,
#enddate datetime
AS
/* Return the event plan (coming events) for a specific volunteer */
declare #sd datetime
declare #ed datetime
/* Ensure that the start and end dates covert whole days */
set #sd = convert(varchar(10),#startdate,120) + ' 00:00:00'
set #ed = convert(varchar(10),#enddate,120) + ' 23:59:59'
SELECT
E.EventID, E.EventDate, E.StartTime, E.StartLocation, E.EndTime,
E.EndLocation, E.Charged, E.Actual,E.ChargeRate, E.Cost,
E.Persons, E.Reason,
C.ClientID, C.Address1, C.Address2, C.Town, C.County, C.Postcode,
C.InvoiceName, C.InvoiceAddress1, C.InvoiceAddress2, C.InvoiceTown,
C.InvoiceCounty, C.InvoicePostCode,
ISNULL(C.Surname, '') + ', ' + ISNULL(C.Forename, '') AS ClientSurnameForename
FROM
vEvents E
INNER JOIN
vClients C ON E.ClientID = C.ClientID
WHERE
vEvents.ClientID IN (SELECT vEvents.Charged
FROM vEvents
GROUP BY vEvents.ClientID, vEvents.charged
HAVING SUM(vEvents.Charged) > 0)
AND (E.EventDate BETWEEN #sd AND #ed)
AND E.SchemeID = 4
ORDER BY
c.Surname, c.Forename, E.EventDate, E.StartTime, E.EndTime
But I keep getting 'the multipart identifier could not be bound'. TIA Andrew
Table Structure
[vEvents](
[EventID] [int] IDENTITY(1,1) NOT NULL,
[ClientID] [int] NOT NULL,
[ChargeID] [int] NOT NULL,
[EventDate] [datetime] NULL,
[StartTime] [datetime] NULL,
[StartLocation] [nvarchar](50) NULL,
[EndTime] [datetime] NULL,
[EndLocation] [nvarchar](50) NULL,
[Reason] [nvarchar](50) NULL,
[Charged] [decimal](6, 2) NOT NULL,
[Actual] [decimal](6, 2) NOT NULL,
[Additional] [decimal](6, 2) NOT NULL,
[Done] [bit] NOT NULL,
[Verifier] [nvarchar](50) NULL,
[ChargeRate] [decimal](6, 4) NULL,
[TeamID] [int] NOT NULL,
[Combined] [bit] NOT NULL,
Its an edit list but contains the most relevant
The Client Table
[vClients](
[ClientID] [int] IDENTITY(1,1) NOT NULL,
[ManagerID] [int] NOT NULL,
[RegularID] [int] NOT NULL,
[Forename] [nvarchar](50) NULL,
[Surname] [nvarchar](50) NULL,
[Address1] [nvarchar](50) NULL,
[Address2] [nvarchar](50) NULL,
[Town] [nvarchar](50) NULL,
[County] [nvarchar](50) NULL,
[PostCode] [nvarchar](10) NULL,
[Telephone] [nvarchar](30) NULL,
[Comments] [ntext] NULL,
[ReviewDate] [datetime] NULL,
[Requirements] [int] NOT NULL,
[Status] [int] NOT NULL,
[EmergencyType] [nvarchar](50) NULL,
[EmergencyContact] [nvarchar](50) NULL,
[EmergencyNotes] [ntext] NULL,
[EmergencyTelephone] [nvarchar](50) NULL,
[Title] [nvarchar](50) NULL,
[VolunteerID] [int] NOT NULL,
[UserID] [int] NOT NULL,
[DateOfBirth] [datetime] NULL,
[HasPushPin] [bit] NULL,
[InvoiceAddress1] [nvarchar](50) NULL,
[InvoiceAddress2] [nvarchar](50) NULL,
[InvoiceTown] [nvarchar](50) NULL,
[InvoiceCounty] [nvarchar](50) NULL,
[InvoicePostcode] [nvarchar](10) NULL,
[InvoiceName] [nvarchar](50) NULL,
[Email] [nvarchar](50) NULL,
Try to change the WHERE part of your query to something like this:
WHERE
E.ClientID IN (SELECT vEvents.ClientID
FROM vEvents
GROUP BY vEvents.ClientID
HAVING SUM(vEvents.Charged) > 0)
AND ...
Maybe:
ALTER PROCEDURE [dbo].[MyReport]
#startdate datetime,
#enddate datetime
AS
/* Return the event plan (coming events) for a specific volunteer */
declare #sd datetime
declare #ed datetime
/* Ensure that the start and end dates covert whole days */
set #sd = convert(varchar(10),#startdate,120) + ' 00:00:00'
set #ed = convert(varchar(10),#enddate,120) + ' 23:59:59'
SELECT
E.EventID, E.EventDate, E.StartTime, E.StartLocation, E.EndTime,
E.EndLocation, E.Charged, E.Actual,E.ChargeRate, E.Cost,
E.Persons, E.Reason,
C.ClientID, C.Address1, C.Address2, C.Town, C.County, C.Postcode,
C.InvoiceName, C.InvoiceAddress1, C.InvoiceAddress2, C.InvoiceTown,
C.InvoiceCounty, C.InvoicePostCode,
ISNULL(C.Surname, '') + ', ' + ISNULL(C.Forename, '') AS ClientSurnameForename
FROM
vEvents E
INNER JOIN
vClients C ON E.ClientID = C.ClientID
INNER JOIN (SELECT ClientID, SUM(Charged) ch
FROM vEvents
GROUP BY ClientID
HAVING SUM(Charged) > 0) t
ON t.ClientID = vEvents.ClientID
WHERE (E.EventDate BETWEEN #sd AND #ed)
AND E.SchemeID = 4
ORDER BY
c.Surname, c.Forename, E.EventDate, E.StartTime, E.EndTime