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 |
|
Bex
Aged Yak Warrior
580 Posts |
Posted - 2005-11-30 : 11:52:29
|
I have the following stored procedure that returns a number of documents that match a criteria. However, the documents themselves (mobile phone invoices) can be part of a bigger document (what we constitute as a doc set). For example, a cost centre may recieve a monthly bill for all their employees. This bill can consist of a customer summary, a customer invoice, an itemised section, and then individual summaries for every handsets. Each section is classified as a document that is part of a document set. The bills are stored at document level, but need to be returned as a document set.On submitting a search, the results are returned to the application, which then assembles the document collection as a documentset. A search can return many results, therefore, we want to allow the user to page through the result set. From what I have read, the most optimal solution is to only return the required results per page. This is fine so far, as the stored procedure limits the number of doc sets returned. However, we also need a complete count of how many docsets match the search criteria. I don't want to fill the table variable with the complete results each time (by removing SET ROWCOUNT @limit), and if I do remove this functionality, it also has the affect of returning ALL of the docsets (as the table variable is used to deduce the docsets that are returned in the second search).How can I return a count, efficiently and effectively, and without doing so each time the procedure is called for each page???Here is the code:/* PURPOSE: Procedure to search for document sets across clientsFUNCTIONALITY: The database is searched and returns all the documents that match any of the variables provided. This can either be a single document set or multiple, depending on the level of the search.NOTE: FOR INTERNAL USE ONLYCREATOR: Rebecca StarrCREATEC:\Program Files\Microsoft SQL Server 28th June 2005*/CREATE PROCEDURE [dbo].[usp_SEARCHDocuments_Paging1]( @clientID INT , @accountNumber VARCHAR(15) = NULL, @invoiceNumber VARCHAR(20) = NULL, @documentDate SMALLDATETIME = NULL, @handsetNumber VARCHAR(12) = NULL, @recipientName VARCHAR(45) = NULL, @limit SMALLINT = 20, @pageNumber SMALLINT = 1)ASSET NOCOUNT ONSET ROWCOUNT 0DECLARE @lastID INTSET @lastID = (@limit * (@pageNumber-1))SET @limit = (@limit * @pageNumber)SET @handsetNumber = REPLACE(@handsetNumber, ' ', '')/*Selects the information based on the parameters passed. If no variables are passed, then all the data in the database is returned.*/--An invoice number, handset number, etc can identify a document set or a single document--In order to return all the documents of a document set, a nested select is performed--1) First Part: Applies a limit of how many document sets are to be returned using ROWCOUNT--2) Second Part: Creates a table variable and all the document sets that match the search-- criteria are inserted into the variable @docSetLimit--3) Third Part: Selects all the documents that belong to the document sets contained in the-- table variable (inner join @docSetLimit) DECLARE @docSetLimit TABLE( TableID INT IDENTITY PRIMARY KEY CLUSTERED, DocSetID BIGINT , DocumentDate SMALLDATETIME, AccountNumber VARCHAR(15))SET ROWCOUNT @limitINSERT INTO @docSetLimit (DocSetID, DocumentDate, AccountNumber)SELECT DS.DocumentSetID, D.DocumentDate, A.AccountNumberFROM Client C INNER JOIN Account A ON ( (C.ClientID = A.ClientID) AND (A.ClientID = @clientID) AND (AccountNumber = @accountNumber OR @accountNumber IS NULL) ) INNER JOIN DocumentRecipient DR ON ( (A.AccountID = DR.AccountID) AND (@recipientName IS NULL OR DocumentRecipientName LIKE ('%' + @recipientName + '%')) ) INNER JOIN Document D ON ( (DR.DocumentRecipientID = D.DocumentRecipientID) AND (DocumentInvoiceNumber = @invoiceNumber OR @invoiceNumber IS NULL) AND (DocumentDate = @documentDate OR @documentDate IS NULL) ) INNER JOIN DocumentSet DS ON DS.DocumentSetID = D.DocumentSetID INNER JOIN [File] F ON F.FileID = DS.FileID INNER JOIN Status S ON (S.StatusID = F.StatusID AND StatusName = 'Accessible') GROUP BY DS.DocumentSetID, DocumentDate, AccountNumber ORDER BY D.DocumentDate desc , A.AccountNumber , DS.DocumentSetIDSET ROWCOUNT 0SELECT DocumentRecipientName , DocumentRecipientPostcode , DocumentInvoiceNumber , T1.DocumentDate , DocumentPageCount , D.DocumentID , HandsetNumber , T1.AccountNumber , DocumentSequenceNumber , DocumentSetID FROM Client C INNER JOIN Account A ON C.ClientID = A.ClientID INNER JOIN DocumentRecipient DR ON A.AccountID = DR.AccountID INNER JOIN Document D ON DR.DocumentRecipientID = D.DocumentRecipientID LEFT OUTER JOIN Handset H ON D.DocumentID = H.DocumentID INNER JOIN @docSetLimit T1 ON T1.DocSetID = D.DocumentSetID WHERE (TableID > @lastID) ORDER BY T1.AccountNumber , DocumentInvoiceNumber , DocumentSetID , DocumentSequenceNumber , T1.DocumentDateThanks in advanceHearty head pats |
|
|
druer
Constraint Violating Yak Guru
314 Posts |
Posted - 2005-11-30 : 13:20:54
|
| If you are trying to ask for how many rows a query returned you can use the @@rowcount system variable. select @@rowcountNot sure if this is really what you are looking to do or what, as I'm pretty confused reading your explanation. |
 |
|
|
madhivanan
Premature Yak Congratulator
22864 Posts |
|
|
Bex
Aged Yak Warrior
580 Posts |
Posted - 2005-12-01 : 07:24:16
|
Hi All,Thanks for your replies! Druer, it is a little confusing I know, so I shall try and explain a little clearer (if thats possible). As I explained (albeit not that clearly), rather than page at document level, i want to page at document set level. I shall try and give you a user scenario to see if that makes things clearer:We offer a reprint service for our clients(mobile service providers). They require the ability to reprint entire invoices as sent to their customers in an envelope. An invoice consists of different sections (which we classify as documents). Each document is archived seperately, but can be related back to its document set. All documents are archived in a storage system. A database contains index information about each document, enabling its retrieval. A user will perform a search, locate the document set they wish to reprint, and then the application will render the invoice enabling the user to print an identical copy of the original invoice prior to being archived.1) A user wishes to reprint an entire invoice by entering search criteria. This invoice is for billing a call centre for all their handsets.2) The invoice can consist of multiple sections, and the user can enter search criteria to locate any one of those sections (for example, a handset summary by entering the handset number)3) Rather than return just that section, the whole invoice will be returned to the application4) The application will calculate the total number of pages for the entire invoice, and display the entry as a single document set on the web interface5) If the number of entries per page is limited to 20, then only 20 document sets will be returned. 6) However, 20 document sets can equate to 30,60,100,200,etc documents (or rather sections of the entire invoice)7) It is imperative that the reprinted bill is a replica of the original, therefore, ALL the documents relating to a document set have to be returned to the application8)In the stored procedure, the second search locates all the documents that match the criteria9) It is the applications job to assemble the results into document sets, and display one result per document set10) I cannot, therefore, limit the results of the second search, as this will return only 20 documents, and not all the documents for 20 document sets11) In order to limit the number of document sets returned, I repeat the search to fills a table variable with the document sets that match the search criteria (group by DocumentSetID)12) this table variable is joined to the second search, so that all of the documents for the document sets are returned13) I use 'SET ROWCOUNT @limit' to limit the number of document sets in the table variableExampleFirst call to the stored procedure (2 results per page...for simplicity)@limit = 2 --passed in by application@pageNumber = 1@limit = @limit * @pageNumber --which equals 2@lastID = (@limit * (@pagenumber-1)) --which equals(2 * (1-1))= 0SET ROWCOUNT @limit --which equals 2--Results of @docSetLimit TableID DocSetID DocumentDate AccountNumber1 1243 1/11/05 123452 34 4/11/05 234562nd query to select all the documents relating to the document sets in @docSetLimit SELECT ....... INNER JOIN @docSetLimit as T1 ON .....WHERE T1.TableID > @lastID --where TableID > 0Results sent to application:DocumentID DocSetID .............1 1243 .............2 1243 ............. 3 1243 ............. 4 34 ............. 5 34 ............. Second call to the stored procedure (2 results per page...for simplicity)@pageNumber = 2@limit = @limit * @pageNumber --which equal 2@lastID = (@limit * (@pagenumber-1)) --which equals (2 * (2-1))= 2Results of @docSetLimit [code]TableID DocSetID DocumentDate AccountNumber1 1243 1/11/05 123452 34 4/11/05 234563 256 14/11/05 1234 790 1/12/05 123452nd query SELECT ....... INNER JOIN @docSetLimit ON .....WHERE TableID > @lastID --where TableID > 2Results sent to application:DocumentID DocSetID .............6 256 .............7 256 ............. 8 256 ............. 9 790 ............. 10 790 ............. 11 790 ............. and so on so forth How can I obtain a complete count of all the document sets that match the search criteria without completely filling the table variable (for performance purposes) and also becuase it effs up the paging??Would I have to perform the same query that fills the table variable to obtain the count or is there a method more optimal. For example:IF @pagecount = 1beginSELECT count(*) ......endREST OF SPROC.........I just feel that it is not the best method as I will be running the same query THREE times, for the first call to the sproc. What other method could I consider for optimal performance and that follows best practice guidelines (whatever they may be)???Sorry for the long winded post, but I tend to explain things in great depth!Hearty head pats |
 |
|
|
Bex
Aged Yak Warrior
580 Posts |
Posted - 2005-12-02 : 06:34:24
|
| FYII decided to write a function that executes the query again and returns a count of all the doc sets returned, but only on the first call to the sproc. As of yet, it does not seem to have an affect on performance, but I still have testing to do.Anywya, thought you may be interested in how this story ended!Hearty head pats |
 |
|
|
|
|
|
|
|