Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-11 : 18:50:36
|
| APOLOGIES to anyone who looked at this earlier - it was late night and sloppy - now updated to fully demonstrate the issue - hopefully without SQL errors except in the FunctionI am trying to return a single value calculated from different subsets and using a while loop to total one of the subsets - any help much appreciatedCode to reproduce is as follows:Database, table and record creationCREATE TABLE [dbo].[PEOPLE]([PEOPLE_ID] [uniqueidentifier] NOT NULL,[LASTNAME] [nvarchar](30) NULL,[FIRSTNAME] [nvarchar](30) NULL,[REFERENCENUMBER] [nvarchar](30) NULL,[FULLNAME] AS ([FIRSTNAME] + ' ' + [LASTNAME]),CONSTRAINT [PK_PEOPLE] PRIMARY KEY CLUSTERED([PEOPLE_ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY],CONSTRAINT [IX_PEOPLE_UNIQUE] UNIQUE NONCLUSTERED([REFERENCENUMBER] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]) ON [PRIMARY]CREATE TABLE [dbo].[JOBDETAIL]([JOBDETAIL_ID] [uniqueidentifier] NOT NULL,[JOBTITLE] [uniqueidentifier] NULL,[PEOPLE_ID] [uniqueidentifier] NOT NULL,[CREATEDBY] [nvarchar](20) NOT NULL,[CURRENTRECORD] [nvarchar](5) NOT NULL,[WORKINGHOURSPERYEAR] [INT] NOT NULL,CONSTRAINT [PK_JOBDETAIL] PRIMARY KEY NONCLUSTERED([JOBDETAIL_ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]) ON [PRIMARY] GOSET ANSI_PADDING OFFGOALTER TABLE [dbo].[JOBDETAIL] WITH NOCHECK ADD CONSTRAINT [FK_JOBDETAIL_PEOPLE] FOREIGN KEY([PEOPLE_ID])REFERENCES [dbo].[PEOPLE] ([PEOPLE_ID])ON UPDATE CASCADEON DELETE CASCADEGOALTER TABLE [dbo].[JOBDETAIL] CHECK CONSTRAINT [FK_JOBDETAIL_PEOPLE]CREATE TABLE [dbo].[POST]([POST_ID] [uniqueidentifier] NOT NULL,[PERCENTAGETEACHING] [int] NOT NULL,[REFERENCENUMBER] [int] NOT NULL,CONSTRAINT [PK_POST] PRIMARY KEY CLUSTERED([POST_ID] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY],CONSTRAINT [IX_POST_UNIQUE] UNIQUE NONCLUSTERED([REFERENCENUMBER] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]) ON [PRIMARY]GO SET ANSI_PADDING OFFINSERT RECORDS:--Create one Person RecordInsert into People (People_id, LastName, FirstName)VALUES (newid(), 'Peter', 'Charles')--Select * from People--Create 2 post recordsInsert into Post (Post_ID, PERCENTAGETEACHING, REFERENCENUMBER)VALUES (newid(), 40, 1001)Insert into Post (Post_ID, PERCENTAGETEACHING, REFERENCENUMBER)VALUES (newid(), 20, 1002)--select * from PostInsert into JobDetail (JobDetail_id, JobTitle, CreatedBy, CurrentRecord, WorkingHoursPerYear)Select top 1 newid(), Po.Post_ID, 'Peter', 'Yes', 100from Post PO where PO.PERCENTAGETEACHING = 40--Create 2 Job records - both for the same person but for different postsInsert into JobDetail (JobDetail_id, JobTitle, CreatedBy, CurrentRecord, WorkingHoursPerYear, People_id)Select newid(), Po.Post_ID, 'Peter', 'Yes', 100, (select top 1 People_id from People)from Post PO--Select * from jobdetail --CREATE FunctionUSE [TEST1]GO/****** Object: UserDefinedFunction [dbo].[RMET_PercentageTeaching] Script Date: 08/11/2009 20:55:00 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOCREATE FUNCTION [dbo].[RMET_PercentageTeaching](@Id uniqueidentifier)RETURNS INTEGERASBEGINDECLARE @CountJobs INTEGERSET @CountJobs = 0DECLARE @TotalWHPY INTEGERSET @TotalWHPY = 0 DECLARE @Counter IntegerSET @Counter = 0DECLARE @PCTeaching INTEGERSET @PCTeaching = 0DECLARE @RESULT INTEGERSET @RESULT = 0--Count of Jobs where PercentageTeaching > 0 - used by the While loopSelect @CountJobs = Count(J.CreatedBy) FROM JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0-- following subset required in order to obtain total hours for ALL jobsSELECT @TotalWHPY = (Select SUM(J2.WorkingHoursPerYear) from JobDetail J2WHERE J2.People_id = J.People_ID and J2.CurrentRecord = 'Yes'Group By J2.People_id) FROM JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes'--The following set statement to show that @CountJobs and @TotalWHPY are working--SET @RESULT = @CountJobs + @TotalWHPY--This is what we really want--Now loop through the teaching jobs and total their hours and percentages--using the values from @countJobs and @TotalWHPYSELECT @RESULT = WHILE @counter <= @CountJobsBEGINSET @counter = @counter + 1SET @PCTeaching = @PCTeaching + (PO.PercentageTeaching * (J.WorkingHoursPerYear/@TotalWHPY))from JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0END RETURN @ResultEND--Select statement to show the result--select p.fullname, dbo.RMET_PercentageTeaching(people_id) from people p-- Expected Result Peter Charles 30 |
|
|
Lamprey
Master Smack Fu Yak Hacker
4614 Posts |
Posted - 2009-08-11 : 19:03:33
|
| That query is very broken. Can you provide some sample data and expected ouput? This link will help you prepare the data for us to help you: [url]http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx[/url] |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-11 : 19:56:10
|
| Thank you for the pointersplease see original post for updated codeagain thank you |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 06:08:32
|
I might be missing something but I think your WHILE part can actually be rewritten like thisSELECT @PCTeaching = SUM(PO.PercentageTeaching * (J.WorkingHoursPerYear/@TotalWHPY))FROM JobDetail J INNER JOIN POST PO ON PO.Post_ID = J.JobTitleWHERE J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0RETURN @PCTeaching Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 06:11:20
|
| thank you - I will try it out and let you know ... |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 06:20:04
|
| You are aware that you are returning an integer?for a percentage like this you will be loosing some precision.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 06:21:04
|
| Sorry - I should explain the reason for the loop. The person has 2 active jobs and I need to carry out the calculation on each job and then add the results together e.g. in the records I put in the original postThe post TeachingPercentage are 40 for one JobDetail record and 20 for the otherThe JobDetail WorkingHoursPerYear records for this one person are both 100 hours - so a total of 200 hours in the yearSo what I want to achieve is40 * 100/200+20 * 100/200result 30OR in an example with different hours40 * 100/20020 * 300/400result 35thanks for you help |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 06:22:06
|
| about precision - yes - I am happy to lose the accuracy |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 06:23:28
|
In fact -- you are doing integer division throughout.Try these select statements to see if that's what you really really want.DECLARE @intA INTEGER SET @intA = 59DECLARE @intB INTEGER SET @intB = 4-- This == 14 (which is the FLOOR of 14.75)SELECT @intA / @intBDECLARE @floatA FLOAT SET @floatA = 59DECLARE @floatB FLOAT SET @floatB = 4-- THis == 14.75SELECT @floatA / @floatB Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 06:38:35
|
| Thank you Charlie - I think you are right - I will do the calculation as a Float and then round to whole numbers at the end |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 06:40:50
|
Yes -- the problem is here:PO.PercentageTeaching * (J.WorkingHoursPerYear/@TotalWHPY) J.WorkingHoursPerYear/@TotalWHPYin your data is this:100 / 300which equals 0With that changed to a float (or a decimal or whatever) you should be good. The SUM method should work.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 06:58:58
|
| OK ... so we need the float - and I think we also need the While Loop e.g.Declare @PC Float Set @PC = 40Declare @PC2 Float Set @PC2 = 20Declare @WorkingHours Float Set @WorkingHours = 100Declare @WorkingHours2 Float Set @WorkingHours2 = 300Declare @TotalWorkingHours Float Set @TotalWorkingHours = 400--the equivalent of a loopSelect (@PC * (@WorkingHours / @TotalWorkingHours)) + (@PC2 * (@WorkingHours2 / @TotalWorkingHours))-- Returns 25--just using totals across the two recordsSelect ((@PC+@PC2) * (@WorkingHours+@WorkingHours2)) / @TotalWorkingHours--Returns 60 |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 07:04:49
|
| thank you Charlie - So if we add in the float and the while loop I have error messages about the while loop - function and error messages belowBEST VERSION of the functionUSE [TEST1]GO/****** Object: UserDefinedFunction [dbo].[RMET_PercentageTeaching] Script Date: 08/11/2009 20:55:00 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER FUNCTION [dbo].[RMET_PercentageTeaching](@Id uniqueidentifier)RETURNS INTEGERASBEGINDECLARE @CountJobs INTEGERSET @CountJobs = 0DECLARE @TotalWHPY INTEGERSET @TotalWHPY = 0 DECLARE @Counter IntegerSET @Counter = 0DECLARE @PCTeaching FloatSET @PCTeaching = 0DECLARE @RESULT FloatSET @RESULT = 0--Count of Jobs where PercentageTeaching > 0 - used by the While loopSelect @CountJobs = Count(J.CreatedBy) FROM JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0-- following subset required in order to obtain total hours for ALL jobsSELECT @TotalWHPY = (Select SUM(J2.WorkingHoursPerYear) from JobDetail J2WHERE J2.People_id = J.People_ID and J2.CurrentRecord = 'Yes'Group By J2.People_id) FROM JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes'--The following set statement to show that @CountJobs and @TotalWHPY are working--SET @RESULT = @CountJobs + @TotalWHPY--This is what we really want--Now loop through the teaching jobs and total their hours and percentages--using the values from @countJobs and @TotalWHPYSELECT @RESULT = WHILE @counter <= @CountJobsBEGINSET @counter = @counter + 1SET @PCTeaching = @PCTeaching + (PO.PercentageTeaching * (J.WorkingHoursPerYear/@TotalWHPY))from JobDetail JINNER JOIN POST PO ON PO.Post_ID = J.JobTitleWhere J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0END RETURN @ResultEND--Select statement to show the result--select p.fullname, dbo.RMET_PercentageTeaching(people_id) from people p-- Expected Result Peter Charles 30RETURNS THESE ERROR MESSAGESMsg 156, Level 15, State 1, Procedure RMET_PercentageTeaching, Line 33Incorrect syntax near the keyword 'WHILE'.Msg 156, Level 15, State 1, Procedure RMET_PercentageTeaching, Line 38Incorrect syntax near the keyword 'from'. |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 10:19:03
|
I think you are making this way more complicated than it needs to be:Does this do the job:USE [TEST1]GO/****** Object: UserDefinedFunction [dbo].[RMET_PercentageTeaching] Script Date: 08/11/2009 20:55:00 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGOALTER FUNCTION [dbo].[RMET_PercentageTeaching](@Id UNIQUEIDENTIFIER)RETURNS FLOATASBEGIN DECLARE @TotalWHPY FLOAT SET @TotalWHPY = 0 DECLARE @PCTeaching FLOAT SET @PCTeaching = 0 -- following subset required in order to obtain total hours for ALL jobs SELECT @TotalWHPY = SUM(J.WorkingHoursPerYear) FROM JobDetail J INNER JOIN POST PO ON PO.Post_ID = J.JobTitle WHERE J.People_ID = @id AND J.CurrentRecord = 'Yes' SELECT @PCTeaching = SUM(PO.PercentageTeaching * (J.WorkingHoursPerYear/@TotalWHPY)) FROM JobDetail J INNER JOIN POST PO ON PO.Post_ID = J.JobTitle WHERE J.People_ID = @id AND J.CurrentRecord = 'Yes' AND PO.PercentageTeaching > 0 RETURN @PCTeachingEND NB -- I've changed the return type to FLOAT -- that seemed to make sense. You were still trying to use integer division before.If you don't want a FLOAT returned then you can ROUND or CAST the result to an INT and then return that instead.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
Buzzard724
Yak Posting Veteran
66 Posts |
Posted - 2009-08-12 : 10:58:16
|
| Hi Charlie - thank you for persisting with thisI really appreciate code that is elegant and does the job with minimum effort - precisely what your suggestion does - thank you(not quite sure why I was hooked on the loop - I think I assumed that the SUM would happen on the individual elements of the calculation - clearly a blind alley)(and I will Round the result - thank you) |
 |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2009-08-12 : 11:25:20
|
| NP. Glad I could help.CYACharlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
 |
|
|
|
|
|
|
|