not the TOP 10 (Full Version)

All Forums >> [Web Development] >> ASP and Database



Message


yogaboy -> not the TOP 10 (9/1/2005 14:40:59)

ello peeps

I'm looking for a clever way to pick the results of a query from 10 to 20, so that once the user's read the top 10 they can move on. I don't want to return 100 results and then use code to show the 10 -20 etc.

Any ideas? Perhaps

SELECT SECOND 10 * from Table

SELECT THIRD 10 * from Table

[:)]




rdouglass -> RE: not the TOP 10 (9/1/2005 15:21:51)

How about the top 25 and dump 'em into an array. Then:

IF ubound(myArray,2) > 19
myMax = 19
ELSE
myMax = ubound(myArray,2)

IF myMax > 9 THEN
FOR i = 10 TO myMax
' Do code
NEXT
END IF

You'd have to check for valid recordset data first tho. At least that might be one way. That help any?




dpf -> RE: not the TOP 10 (9/1/2005 15:24:55)

??maybe a loop??
set x =1
y=10
Select from x to y
x= x + 10
y = y + 10




yogaboy -> RE: not the TOP 10 (9/1/2005 15:36:48)

Cheers guys, but I'm trying to head in a slightly different direction to that. I'm sort of thinking about the way that Google works. It can find over 100,000 records but it obviously doesn't return them all, and yet your able to move from page 1 to page 2 only showing 10 results at a time.

I'm using SQL Server, and I've tried putting the results in an table-array (on the SQL Server) and numbering the results using and identity column. It works, but it makes the query a lot slower.

I'm basically building a search engine for a site that may return large amounts of data, so I'm trying to find an alternative to grabbing all the data and then limiting it by a TOP clause.




rdouglass -> RE: not the TOP 10 (9/1/2005 15:40:50)

Oh, you mean "paged" recordsets. [:D]

This is a pretty good one:

http://www.learnasp.com/learn/dbtablepaged.asp




yogaboy -> RE: not the TOP 10 (9/1/2005 15:49:41)

But that still means I have to pull all the data into the recordset, right? I was hoping there was a special SQL clause like TOP that might help that actually restricts the unused data from being sent in the first place?? I want to avoid pulling out more data than is needed at the database side of things.




rdouglass -> RE: not the TOP 10 (9/1/2005 16:02:34)

Other than an XML / AJAX solution, I personally don't know how.

A stored procedure perhaps?




Spooky -> RE: not the TOP 10 (9/2/2005 3:33:37)

Like so :
The trick is to "move" and chunk the records

<%
  iStart = Request("Start")
  iOffset = Request("Offset")
  if Not IsNumeric(iStart) or Len(iStart) = 0 then
    iStart = 0
  else
    iStart = CInt(iStart)
  end if
  if Not IsNumeric(iOffset) or Len(iOffset) = 0 then
    iOffset = 100
  else
    iOffset = Cint(iOffset)
  end if

  Response.Write "Viewing " & iOffset & " records starting at record " & iStart & "<BR>"

'------------------------------
' Get chunked records using getrows
'------------------------------
  Set objConn = Server.CreateObject("ADODB.Connection")
  objConn.Open sDSN
  Set objRS = Server.CreateObject("ADODB.Recordset")
  With objRS
  	.Open "Select * from Reports",objConn,0,1,&H0001
  	.Move(iStart)
  	aResults = .GetRows(iOffset)
  	.Close
  End With
  Set objRS = Nothing
' with count
  Set objRS2 = objConn.Execute("Select Count(ReportID) from Reports")
  recs = objRS2(0)
  objRS2.close
  Set objRS2 = Nothing
  objConn.Close
  Set objConn = Nothing
'------------------------------
' Count results
'------------------------------
  iRows = UBound(aResults, 2)
  iCols = UBound(aResults, 1)
  If iRows > (iOffset + iStart) Then
    iStop = iOffset + iStart - 1
  Else
    iStop = iRows
  End If
'------------------------------
' Formatting each row
'------------------------------
  For iRowLoop = 0 to iStop
      Response.Write aResults(0, iRowLoop) &","
  Next
'------------------------------
' Paging
'------------------------------
  Response.Write "<P>"
  if iStart > 0 then Response.Write "<A HREF=""getrows.asp?Start=" & iStart-iOffset & "&Offset=" & iOffset & """>Previous " & iOffset & "</A>"
  if iStop+1 = iOffset then Response.Write " <A HREF=""getrows.asp?Start=" & iStart+iOffset & "&Offset=" & iOffset & """>Next " & iOffset & "</A>"
  Response.write "<br>Record Count = "&recs
%>





rdouglass -> RE: not the TOP 10 (9/2/2005 10:05:42)

Question Spooky:

I generally stay away from recordsets because I think they're slow so I'm not at all sure, but doesn't this still go thru all the records up to that point anyways? So isn't the server usage the same as if you dumped the first 200 into an array with getrows?

Or maybe I just don't understand the recordset objects enough?




Spooky -> RE: not the TOP 10 (9/2/2005 15:24:43)

Apart from a stored procedure, GetRows/Move above is pretty much the fastest and most efficient method.

http://www.aspfaq.com/show.asp?id=2120




yogaboy -> RE: not the TOP 10 (9/2/2005 17:14:24)

I've ended up with a mixture of what's in the link to aspfaq. I've ranked the search results and put them into a table UDF with an identity column, but I haven't put all the fields in - just their id. Then I use a few parameters to work out how many results are to be returned and which page is required. Then I've joined the required id's back to the table they've come from. Then I put it all in a GetRows array on the client.

It means that I can pull just 10 (as default) records from a search with any number of returned results.

I've put the code below for masochists to pull apart in their own time. It seems to work ok for now. Thanks everyone for your input.

--this proc returns the results of a search, but only the number
--of records requested
--searches the info table by title, blurb and date seperately
-- and gives a relevance score
/*declare @Count int
exec dbo.KeyDoc3SEARCH_usp 'positive', -1, 10, 9, @Count OUTPUT
select @Count*/
ALTER   PROC  dbo.KeyDoc3SEARCH_usp
	(
	@searchterm nvarchar(60)
	, @mDiff int = -1
	, @magnitude int= 10
	, @page tinyint = 1
	, @Count int OUTPUT
	)
--@mDiff is the month difference
--@magnitude is the number of results per page
--@page is the page required
--@Count is the total number of records returned by the search
AS
--turn off count to avoid errors with output variable
SET NOCOUNT ON
--use the magnitude and page number to work out the lower and higher bounds of the records
--asked for - eg magnitude 10 = 10 records per page, page = 2 means @lower = 10 and 
--@higher = 20
	declare  @date1 smalldatetime, @date2 smalldatetime, @higher int, @lower int
	set @higher = @magnitude * @page
	set @lower = @higher - @magnitude
--select @higher, @lower
	IF @mDiff >= 0 OR @mDiff IS NULL
	BEGIN
              --if empty then set for 1 month back
		SET @mDiff = -1
	END	
set @date1 = DATEADD(  m, @mDiff, GETDATE()  )
set  @date2 = GETDATE()
/* -- some ready made inputs for error checking
declare @searchterm nvarchar(60), @date1 smalldatetime, @mDiff int
set @searchterm = N'camhs'
set @date1 = null */

-- the select statement
	select  i.[id], i.Title, i.Blurb
			, dbo.DateFormat_fn(i.DateCreated, ' ') AS DateCreated
			, h.Host AS host, u.Path AS path
			, u.ALTcontent
			, i2.Score
		FROM Info AS i
			INNER JOIN 
                            --this udf is a 2d array with 3 columns
                            --1st col is IDENTITY, 2nd col is the id's from the Info table
                            --3rd col is the search relevance score eg 3 or 2
                            --sorted by count DESC, then the IDENTITY is added
				dbo.SearchResultsKEYDOC_udf(@searchterm,@date1, @date2)
			AS i2
				ON i.[id] = i2.[Infoid]
-- getting the urls
			INNER JOIN InfoRelURL AS r  
				 ON i.[Id] = r.InfoId 
			INNER JOIN URL AS u
				ON r.URLid = u.[id]
			INNER JOIN dbo.urlHost_udf()  AS h
					ON u.Hostid = h.id

-- this where clause restricts the returned records using values derived from @magnitude
-- and @page
	WHERE i2.id BETWEEN @lower AND @higher
-- output the count
	SELECT @Count = Count(*)
		FROM dbo.SearchResultsKEYDOC_udf(@searchterm,@date1, @date2)

SET NOCOUNT OFF



this is the udf that does the search scoring
--last updated 1 9 05 17.20
--select * from dbo.SearchResults_udf('positive', '10 Aug 2005', '1 Sep 2005')
--optimised for KEYDOCs
-- UNION ALL is used to allow a GROUP BY which can then be counted
--giving a rudimentary relevance score
CREATE  FUNCTION  dbo.SearchResultsKEYDOC_udf
	(
	@searchterm nvarchar(60)
	, @date1 smalldatetime = null
	, @date2 smalldatetime = null
	)
	RETURNS @myTable TABLE
	(
	id int IDENTITY(1,1)
	, Infoid int
	, Score tinyint
	)
AS
	BEGIN
-- the insert
		INSERT @myTable
			select  i.[id]
				,  COUNT(*) AS Score		
				FROM Info AS i
					INNER JOIN
					(
--search the title
				select * from dbo.InfoSELECTidsfromTitleKEYDOC_udf(@searchterm)
							UNION ALL
--search the blurb
				select * from dbo.InfoSELECTidsfromBlurbKEYDOC_udf(@searchterm)
							UNION ALL
--search between dates
				select * from dbo.InfoSELECTidsfromDatesKEYDOC_udf(@date1, @date2)
					) AS i2
						ON i2.[id] = i.[id]
-- group by and sort by...
				GROUP BY i.[id]
				ORDER BY Score DESC

-- return the array
			RETURN
	END




rdouglass -> RE: not the TOP 10 (9/3/2005 12:15:40)

Thanks for posting your solution. So many times these threads are left hangin. [8|][;)]




yogaboy -> RE: not the TOP 10 (9/3/2005 13:30:53)

Try and hide it, but it's the masochist in you that's glad![:D]




Page: [1]

Valid CSS!




Forum Software © ASPPlayground.NET Advanced Edition 2.4.5 ANSI
0.0625