| Author |
Topic |
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 12:03:45
|
I have two tables. The first table contains the check range issued to the user. The second is the Check Register Table that contains info on which checks the user has printed or voided.ToMailBox StartCheck EndCheck(Varchar (7)) (int) (int)-------------- ------------ ------------01390 205901 205950 chkprtbox chknumber (varchar(5)) (varchar(7))--------- --------- 01390 020590601390 020592401390 0205926 I need to return a recordset to a Crystal Report that lists all of the checks not used. I have the following code that works.declare @ID as int, declare @BegChk as int, @EndChk as int, @NoChks as int, @MBox as varchar(5), @CI as int, @ChkNo as int,@Out as varchar(7), @No as varchar(7), @lNo as int, @Dif as intset @ID = 0set @begchk = 0set @endchk = 0set @NoChks = 0set @mbox = nullset @CI = 0set @chkNo = 0set @Out = Nullset @No = Nullset @lNo = 0 set @dif = 0drop table tmpchkrngcreate table tmpChkRng (ChkNo varchar(7), CI varchar(1))--while (select top 1 chkrangeid from chkrange where chkrangeid > @ID) > 0--begin set @id = (select top 1 chkrangeid from chkrange where tomailbox = '01390') --where chkrangeid > @ID) set @begchk = (select startcheck from chkrange where chkrangeid = @ID) set @endchk = (select endcheck from chkrange where chkrangeid = @ID) set @nochks = (@endchk - @begchk) + 1 set @mbox = (select tomailbox from chkrange where chkrangeid = @ID) set @CI = (select count(chknumber) from chkreg where (chkprtbox = '01390' and chknumber is not null and chktrncode = 'ci')) --@mbox) if @CI < @nochks begin set @chkno = @begchk while @chkno < = @endchk begin set @No = ltrim(rtrim(cast(@chkno as varchar(7)))) set @lno = len(@no) if @lno <> 7 begin set @Dif = 7 - @lno if @Dif = 1 set @No = '0' + @No if @dif = 2 set @No = '00' + @No if @Dif = 3 set @No = '000' + @No end set @Out = (select chknumber from chkreg where chknumber = @No and chkprtbox = '01390') if @Out is null or ltrim(rtrim(@out)) = '' begin --print 'chkno ' + cast(@chkno as varchar(7)) + ' is missing' insert tmpChkRng values( @chkno, 'N') end set @chkno = @chkno + 1 end end--end I've commented out the first while loop to pare it down to one printbox for testing purposes. There are upwards of 1000+ users with the possibility of 50+ unused checks for each user.It's very cumbersome with the while loops. Is there a way to code this without them? Is there a way to code this without the use of the temp table?Any advice would be greatly appreciated!Thanks!TeresaEdited by - TJ on 04/21/2003 12:06:05 |
|
|
dsdeming
479 Posts |
Posted - 2003-04-21 : 12:31:56
|
| Try using a number table. I have a table called Sequence that contains a single column -- Counter -- and 8000 rows where Counter = 1 to 8000.create table CheckRegister(chkprtbox varchar(5),chknumber varchar(7))INSERT INTO CheckRegister SELECT '01390', '0205906'INSERT INTO CheckRegister SELECT '01390', '0205924'INSERT INTO CheckRegister SELECT '01390', '0205926'SELECT Counter + 205901 - 1FROM SequenceWHERE Counter + 205901 - 1 <= 205950 AND Counter + 205901 - 1 NOT IN( SELECT chknumber FROM CheckRegister )drop table CheckRegisterHTHEdited by - dsdeming on 04/21/2003 13:03:07 |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2003-04-21 : 12:49:54
|
Don't know if there's a cleaner way than this, but....Good Luck CREATE TABLE myTable1 (ToMailBox varchar(7), StartCheck int, EndCheck int) GOCREATE TABLE myTable2 (ChkPrtBox varchar(5), ChkNumber varchar(7)) GOINSERT INTO myTable1 (ToMailBox, StartCheck, EndCheck) SELECT '01390',205901,205950GOINSERT INTO myTable2 (ChkPrtBox, ChkNumber)SELECT '01390','0205906' UNION ALLSELECT '01390','0205924' UNION ALLSELECT '01390','0205926'GOCREATE PROC myPROC @ToMailBox varchar(7) ASSET NOCOUNT ONDECLARE @StartCheck int, @EndCheck As intDECLARE @mytable3 table (ChkNumber varchar(7) NOT NULL)SELECT @StartCheck = StartCheck, @EndCheck = EndCheck FROM myTable1WHILE @StartCheck <= @EndCheck BEGIN INSERT INTO @myTable3 (ChkNumber) SELECT RIGHT(REPLICATE('0',7)+Convert(varchar(7),@StartCheck),7) SELECT @StartCheck = @StartCheck + 1 ENDSELECT * FROM @myTable3 o WHERE NOT EXISTS (SELECT 1 FROM myTable2 i WHERE i.ChkNumber = o.ChkNumber)SET NOCOUNT OFFGOEXEC myPROC '01390'GODROP TABLE myTable1GODROP TABLE myTable2GODROP PROC myPROCGOBrett8-)Edited by - x002548 on 04/21/2003 12:51:32 |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 13:01:27
|
| Thanks for the input. I'm really need to get away from the temp tables. It's possible that more than one person could fire up this report. The first person runs the sproc at 9:05 to retrieve data and the second one runs it 9:06. This is going to mess up the first person's dataset. I have this issue with another report that I've created. I'm just not sure what the answer is. I need the recordset returned directly to the report instead of a temp table.If you have any other solutions, or know where I might obtain additional information, please let me know.Thanks for taking the time to respond!Teresa |
 |
|
|
MichaelP
Jedi Yak
2489 Posts |
Posted - 2003-04-21 : 13:04:41
|
| Correct me if I'm wrong, but aren't temp tables unique to a connection? If two users are executing a query that uses temp tables, they should not step on each other. A temp table gets a "unique" name in TempDB when you create it.Give the temp table solution a try. I bet it will work just fine for ya.Global Temp tables are shared across all connections. That might be what you are thinking# = Temp table## = Global Temp TableMichael<Yoda>Use the Search page you must. Find the answer you will.</Yoda> |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 13:09:08
|
quote: Give the temp table solution a try. I bet it will work just fine for ya.
My mistake... we create small tables and use them as temp tables. I'll check out a TRUE temp table (#) and see how that works!Thanks!Teresa |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2003-04-21 : 13:18:10
|
| Yes a LOCAL temp table is only valid for the time of the connection. A GLOBAL temp table will hang around as long as it's being referenced.If you're using SQL2000, I would recommend using Table Datatypes as I have in my post (MOO). If you noticed there are no temp tables in it.Brett8-) |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2003-04-21 : 13:21:13
|
quote: I have this issue with another report that I've created. I'm just not sure what the answer is. I need the recordset returned directly to the report instead of a temp table.
I would think you're confusing a "Work" Table (an actual physically defined object) with a temp table.In either event, I still say DECLARE a Table datatype local variable.Brett8-) |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 13:22:48
|
quote: If you're using SQL2000, I would recommend using Table Datatypes as I have in my post (MOO). If you noticed there are no temp tables in it.
I'm sorry... I should have posted that I'm using SQL 7. Thanks!Teresa |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 13:24:50
|
quote: I would think you're confusing a "Work" Table (an actual physically defined object) with a temp table.
You're right! I am!Teresa |
 |
|
|
dsdeming
479 Posts |
Posted - 2003-04-21 : 13:27:47
|
| I'm a true believer in number tables, thanks to Umachandar. They can be used to do things that are otherwise extremely awkward. Using one in this case avoids any necessity for temp tables. The number table doesn't even have to be in the same database.DECLARE @min int, @max intSET @min = 205900SET @max = 205950 SELECT Counter + @minFROM Utility..Sequence WHERE Counter + @min <= @maxAND Counter + @min NOT IN( SELECT chknumber FROM CheckRegister ) |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-21 : 13:34:50
|
quote: I'm a true believer in number tables
Why do you need a number table? Why can't you use a variable and increment it? I'm trying to understand the process, but am having trouble with it since there isn't a 'work' or '#' table. Teresa |
 |
|
|
dsdeming
479 Posts |
Posted - 2003-04-21 : 13:48:49
|
| The number table eliminates the need for incrementing variables, using cursors, or using temp tables. A single select returns the data you're looking for. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2003-04-21 : 13:53:17
|
| But don't you still have the datatype conversion problem?And how do create and populate your sequence table.In TJ's example she has a known range. What are the ranges in your sequence table?EDIT: TJ since you're using 7.0, you change the datatype table to a #temp table in the code I posted, and you shouldn't have any problems with your users.Brett8-)Edited by - x002548 on 04/21/2003 13:54:26 |
 |
|
|
dsdeming
479 Posts |
Posted - 2003-04-21 : 14:01:18
|
quote: But don't you still have the datatype conversion problem?
The code I originally posted worked fine on my system just doing an implicit conversion. Not the best practice, but this was just intended as a starting point.quote: And how do create and populate your sequence table.
I used a while loop to slam 8000 integers into the table in my utility database. I've never had to touch it since.quote: In TJ's example she has a known range. What are the ranges in your sequence table?
Her start and end numbers are the @min and @max I use to add to the Counter column of the sequence table. The sequence can always bee offset by whatever minimum value you need. My table will allow for 8000 values between @min and @max, but you could always add more. |
 |
|
|
X002548
Not Just a Number
15586 Posts |
Posted - 2003-04-21 : 15:34:36
|
Looks like her range could be in the millions thoughquote: chkprtbox chknumber (varchar(5)) (varchar(7))--------- --------- 01390 020590601390 020592401390 0205926
Brett8-) |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2003-04-21 : 21:55:39
|
quote: Looks like her range could be in the millions though
Which is a perfect lead-in to one extremely good reason NOT to use table variables, even if she had the option: you cannot index or create statistics on a table variable, and yes, you can see significantly better performance with an indexed temp table than a table variable:http://www.sqlteam.com/Forums/topic.asp?TOPIC_ID=22212I've also seen this effect on much smaller rowsets (2,000 - 4,000 rows) Indexing and statistics can make a very noticeable improvement in performance over table variables. And as GreatInca's post points out, table variables are almost useless in JOINs, especially to tables on disk.Remember that even though a table variable is entirely in RAM, it is essentially a heap of data. To find anything, you have to search ALL of it. With an index, the values you are searching for will fall within hard boundaries that negate the need to search all of the available data. Also, once the temp table and its index(es) are read into memory, they stay in the data cache and are, in effect, already table variables.And if you are going to have millions of rows of data, table variables are definitely a bad way to go. Even if you have gobs of RAM, if they overflow the available space then SQL Server will have to page the data out to the swap file, which is an expensive I/O operation compared to simply flushing some buffers and reading fresh, indexed, organized data sequentially from a disk on which it already exists (yes, even millions of rows of it...swap file I/O is completely unorganized) This will become especially noticeable if many users are running the same procedure at one time. |
 |
|
|
byrmol
Shed Building SQL Farmer
1591 Posts |
Posted - 2003-04-21 : 22:33:12
|
You don't need the entire numeric range. You just need to find the largest range of checks.. In this case it is 50...A Numbers table is definately the way to go....Using Bretts DDL and DML and a Numbers table with a column called NumberSELECT CAST(StartCheck AS INT) + Number - 1 as UnUsedChecksFROM myTable1 CROSS JOIN NumbersWHERE Number <= CAST(EndCheck AS INT) - CAST(StartCheck as INT) + 1AND NOT EXISTS(SELECT 1 FROM myTable2WHERE ChkNumber = CAST(StartCheck AS INT) + Number - 1) You will have to Cast/format the Check number back...DavidM"SQL-3 is an abomination.."Edited by - byrmol on 04/21/2003 22:34:32 |
 |
|
|
TJ
Posting Yak Master
201 Posts |
Posted - 2003-04-22 : 16:20:41
|
I agreed with Rob, 'cause he knows a lot about SQL , until I worked with this today. SELECT ((tbl1.StartCheck +Number) - 1) as ChkNo, tomailbox as mBox, tbl1.startcheck as Start#, tbl1.endcheck as End#, frmmailbox as BnkMailbox FROM tbl1 CROSS JOIN Numbers WHERE Number <= CAST(((tbl1.EndCheck - tbl1.StartCheck )+1)as varchar(7)) AND NOT EXISTS (SELECT 1 FROM tbl2 WHERE Chknumber = replicate ('0', 7 - len(ltrim(rtrim(cast(tbl1.startcheck +number - 1 as varchar))))) +ltrim(rtrim(cast(tbl1.startcheck +number - 1 as varchar))) )This alleviated the need for any kind of work or # table and the sproc runs in 14 seconds compared to 1+ minute. The work & # tables were indexed and I included an order by and it still didn't perform as well as this code. My co-worker had used replicate in one of his sprocs and helped me with the data conversion.Thanks to all who helped. While I was skeptical at first, I've become a believer too. Best regards from a grateful recipient of the help from the wonderful, outstanding, stupendous, SQL TEAM!!!!Teresa |
 |
|
|
jsmith8858
Dr. Cross Join
7423 Posts |
Posted - 2003-04-22 : 16:53:15
|
| Nice one, Byrmol !!- Jeff |
 |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2003-04-22 : 21:12:23
|
quote: I agreed with Rob, 'cause he knows a lot about SQL , until I worked with this today.
HA! That'll be the last time you ever agree with me! I should've clarified that you didn't need a TEMP table either...just any regular, indexable table would work, especially a numbers table like everyone suggested.And I'm also a HUUUUUUUUUUUGE believer in numbers/sequence/tally tables:http://www.sqlteam.com/item.asp?ItemID=2652 |
 |
|
|
Next Page
|