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.

 All Forums
 SQL Server 2000 Forums
 SQL Server Development (2000)
 Return count of results for paging purposes

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 clients
FUNCTIONALITY: 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 ONLY
CREATOR: Rebecca Starr
CREATEC:\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
)
AS
SET NOCOUNT ON
SET ROWCOUNT 0
DECLARE @lastID INT

SET @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 @limit
INSERT INTO @docSetLimit (DocSetID, DocumentDate, AccountNumber)
SELECT DS.DocumentSetID, D.DocumentDate, A.AccountNumber
FROM 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.DocumentSetID

SET ROWCOUNT 0

SELECT 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.DocumentDate


Thanks in advance

Hearty 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 @@rowcount

Not sure if this is really what you are looking to do or what, as I'm pretty confused reading your explanation.
Go to Top of Page

madhivanan
Premature Yak Congratulator

22864 Posts

Posted - 2005-12-01 : 03:12:10
Other Paging methods
http://weblogs.sqlteam.com/jeffs/archive/2003/12/22/672.aspx
http://www.aspfaq.com/show.asp?id=2120


Madhivanan

Failing to plan is Planning to fail
Go to Top of Page

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 application
4) 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 interface
5) 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 application
8)In the stored procedure, the second search locates all the documents that match the criteria
9) It is the applications job to assemble the results into document sets, and display one result per document set
10) 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 sets
11) 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 returned
13) I use 'SET ROWCOUNT @limit' to limit the number of document sets in the table variable

Example

First 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))= 0
SET ROWCOUNT @limit --which equals 2

--Results of @docSetLimit

TableID DocSetID DocumentDate AccountNumber
1 1243 1/11/05 12345
2 34 4/11/05 23456

2nd 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 > 0

Results 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))= 2

Results of @docSetLimit
[code]
TableID DocSetID DocumentDate AccountNumber
1 1243 1/11/05 12345
2 34 4/11/05 23456
3 256 14/11/05 123
4 790 1/12/05 12345

2nd query
SELECT .......
INNER JOIN @docSetLimit ON .....
WHERE TableID > @lastID --where TableID > 2

Results 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 = 1
begin
SELECT count(*) ......
end

REST 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
Go to Top of Page

Bex
Aged Yak Warrior

580 Posts

Posted - 2005-12-02 : 06:34:24
FYI

I 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
Go to Top of Page
   

- Advertisement -