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 |
|
sfortner
Yak Posting Veteran
63 Posts |
Posted - 2011-09-15 : 10:56:43
|
Hey gurus, I have a table that I inherited that contains the following pertinent fields. It's not set up well, because there's an ordered set of job numbers followed by a separate ordered set of job numbers for a separate division:create table Job (JobNumber int, Entered datetime)insert into Jobselect '4000', '01/01/2011' unionselect '4001', '01/02/2011' unionselect '4001', '01/03/2011' unionselect '4002', '01/09/2011' unionselect '9668', '04/20/2011' unionselect '9669', '04/30/2011' There's a udf that retrieves the next available job number, in this case, it would return 4003, but it's currently taking 12 seconds to return. I need to make this more efficient. I was able to get it down to 3 seconds by adding a table variable and removing some checks for date and job number sequence (don't ask...). I also tried a while loop and just loop through the job numbers till the difference between the next job number and the previous > 1, but that's taking around 45 seconds to run. Here's what I've got now, but I'm certain this can be rewritten (with a CTE?) to be more efficient and faster:DECLARE @result int, @reset datetime, @default intset @reset = '2010.01.01'set @default = 4000 declare @tvJob table (JobNumber int)insert into @tvJob select distinct JobNumber from Job where JobNumber >= @default and Entered >= @resetselect top 1 JobNumber + 1 from (select JobNumber, (select top 1 JobNumber from @tvJob where /*Entered >= @reset and*/ JobNumber = j.JobNumber+1 order by JobNumber desc) NextJobNumber from @tvJob j /*where JobNumber >= @default and Entered >= @reset*/) t where t.NextJobNumber is null order by JobNumber asc --Steve |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2011-09-15 : 18:06:25
|
Hello Steve,Can you add a 'modulus check' and limit the values to those within the range of @default?Something like this?SELECT MAX(jobNumber)+1 FROM JobWHERE JobNumber >= @default AND Entered >= @reset --limit the value by evaluating a modulus AND JobNumber % @default < 100 |
 |
|
|
sfortner
Yak Posting Veteran
63 Posts |
Posted - 2011-09-16 : 08:45:55
|
Well, that's definitely faster : ) but it's not returning the right results as is. If I add more values to be closer to what we actually have in production with this sql statement:declare @default intset @default = 4003while (@default < 5000) begin insert into Job select @default, getdate() set @default = @default + 1end it incorrectly returns 4100. The mod check seems to be more of a "hard-coded" soln where we need to find the first non-sequential number.quote: Originally posted by ehornSELECT MAX(jobNumber)+1 FROM JobWHERE JobNumber >= @default AND Entered >= @reset --limit the value by evaluating a modulus AND JobNumber % @default < 100
--Steve |
 |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2011-09-16 : 09:00:35
|
quote: Originally posted by sfortner Well, that's definitely faster : ) but it's not returning the right results as is. If I add more values to be closer to what we actually have in production with this sql statement:declare @default intset @default = 4003while (@default < 5000) begin insert into Job select @default, getdate() set @default = @default + 1end it incorrectly returns 4100. The mod check seems to be more of a "hard-coded" soln where we need to find the first non-sequential number.quote: Originally posted by ehornSELECT MAX(jobNumber)+1 FROM JobWHERE JobNumber >= @default AND Entered >= @reset --limit the value by evaluating a modulus AND JobNumber % @default < 100
--Steve
Good morning Steve,The example using 'modulus' was intended to stimulate some thought around a simpler solution. If modulus function is considered as a potential solution for filtering this result, it likely would need to be adjusted to meet the needs of the 'job numbers' series data. However, I do not have the benefit of knowing enough about the data specifics to provide a finished solution.The value of '100' in the modulus example was only for an example. You could change it to '< 1000' and that may provide you the result you are seeking. But without the benefit of deeper understanding of the job numbers data, this may not be an adequate solution either.Can you share more insight into your job numbers series data. For instance, what happens when the max(jobnumber) reaches 4999 and next series in a job is '5000'. Can this happen? What would be the expected result. Are the job numbers series always organized around the 000's ranges? |
 |
|
|
sfortner
Yak Posting Veteran
63 Posts |
Posted - 2011-09-16 : 09:55:07
|
| Maybe it would help to have more info. This db is used by a job board web app and when they create a new job the GetNewJobNumber udf is called to get the next available job number. There's currently job numbers 4000 - 8677 that are in the range where we want to create the next job number. There's other job numbers in the 1 - 2344 range that are from the old system that we don't want to use, nor do we want to use any job numbers in the 2345 - 3999 range (at least not yet). There's also some other job numbers seeded from 9668 - 9999 that we don't want to use either - these are used for special contract jobs. It's something I inherited, so I can't change it.That said, that's why we have a @default variable that gets set to 4000 so it uses the 4000 - 9999 range. All the GetNewJobNumber udf should do is get the first available job number, where it hasn't been used yet. At some point job number 5000 in our example could get created, and to confirm, when a new job number is created, it just gets the next available number. The query should determine when the job numbers are not in sequence and return the next one.--Steve |
 |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2011-09-16 : 10:54:33
|
quote: Originally posted by sfortner Maybe it would help to have more info. This db is used by a job board web app and when they create a new job the GetNewJobNumber udf is called to get the next available job number. There's currently job numbers 4000 - 8677 that are in the range where we want to create the next job number. There's other job numbers in the 1 - 2344 range that are from the old system that we don't want to use, nor do we want to use any job numbers in the 2345 - 3999 range (at least not yet). There's also some other job numbers seeded from 9668 - 9999 that we don't want to use either - these are used for special contract jobs. It's something I inherited, so I can't change it.That said, that's why we have a @default variable that gets set to 4000 so it uses the 4000 - 9999 range. All the GetNewJobNumber udf should do is get the first available job number, where it hasn't been used yet. At some point job number 5000 in our example could get created, and to confirm, when a new job number is created, it just gets the next available number. The query should determine when the job numbers are not in sequence and return the next one.--Steve
I see, thanks for clarifying the need. Perhaps another method would be to create and use a table of numbers and then compare the numbers table to what exists in your jobNumbers table. Then Find the minimum available number for which there is no corresponding jobnumber. Something like this;SELECT MIN(n)FROM dbo.numbers nLEFT JOIN Job j ON j.jobNumber = n.nWHERE n.n >= @default AND n.n < 9668AND j.jobNumber IS NULL So here, dbo.numbers contains only one int field [n] which is a primary key and contains those numbers for which jobs can be assigned. The first null value it finds when joined to your Jobs table is then the value returned.HTH. |
 |
|
|
sfortner
Yak Posting Veteran
63 Posts |
Posted - 2011-09-16 : 14:06:38
|
quote: Originally posted by ehorn I see, thanks for clarifying the need. Perhaps another method would be to create and use a table of numbers and then compare the numbers table to what exists in your jobNumbers table. Then Find the minimum available number for which there is no corresponding jobnumber. Something like this;SELECT MIN(n)FROM dbo.numbers nLEFT JOIN Job j ON j.jobNumber = n.nWHERE n.n >= @default AND n.n < 9668AND j.jobNumber IS NULL So here, dbo.numbers contains only one int field [n] which is a primary key and contains those numbers for which jobs can be assigned. The first null value it finds when joined to your Jobs table is then the value returned.HTH.
Brilliant - works perfectly - and it even does it in 0 ms vs 11333 ms for the existing soln! The old Celko numbers table to the rescue. I'm surprised that it runs in 0 ms too - wouldn't have thought that would have been possible, but these are fairly small tables and the est execution plan shows it's using the new non-clustered index I added and the pk index on the Numbers table. Great job - thanks again!--Steve |
 |
|
|
ehorn
Master Smack Fu Yak Hacker
1632 Posts |
Posted - 2011-09-16 : 14:12:43
|
quote: Originally posted by sfortner Brilliant - works perfectly - and it even does it in 0 ms vs 11333 ms for the existing soln! The old Celko numbers table to the rescue. I'm surprised that it runs in 0 ms too - wouldn't have thought that would have been possible, but these are fairly small tables and the est execution plan shows it's using the new non-clustered index I added and the pk index on the Numbers table. Great job - thanks again!--Steve
yvw,Have a nice day. |
 |
|
|
|
|
|
|
|