▶ 뭉충닷컴
 
mungchung.com login
Site Search
My Space
주절주절...
공부방
쥔장소개
Board
자유게시판
유용한 정보
자료실
Programming
강좌 & Articles
Spring 3.0
프로그래밍 Tip
   -ASP
   -PHP
   -JavaScript
   -HTML
   -Java/JSP
   -Database
   -Crystal Report
   -Visual Basic
   -이클립스
   -리눅스
   -기타
Windows API (VB)
Spread Sheet 7.0
컴퓨터활용 Tip
Other things
StarCraft 전략
StarCraft 문서
김용(金庸)
Son Q & Dieda

ASP 페이징 쉽게 처리하기

조회 수 24701 추천 수 0 2006.08.29 14:32:43

게시물 페이징이 사용자한텐 상당히 편한 기능이지만 개발자한테는 귀찮고 괴로운 작업중 하나다. 페이징을 해보면 알겠지만 페이징 처리를 위해서 목록 페이지 곳곳에 이런 저런 처리를 해줘야한다. 단지 페이지 이동 링크들 넣을 뿐인데 그 작업량은 상당하다.

이런 개노다(?) 작업외에 무시할 수 없는 부분이 페이징시 사용되는 쿼리문이다. 일전에 "프로그래밍 Tip"란에 큰머리님의 페이징 테스트 자료를 올려두었는데, 그 게시물만 보더라도 페이징 관련 쿼리문이 여러가지 있다. (페이징 테스트 자료로 가기)

이 테스트 자료를 보면 가장 빠른 페이징을 6번째 방법이였는데 솔직히 이 방법은 실무에서 사용하긴 좀 부족한 감이 있다. 실제 개발에선 테이블 하나만 가지고 페이징하진 않는다. 몇개씩 조인한 테이블의 데이타들을 페이징 하는것은 물론 심한 경우 10개이상의 테이블에서 조인한 데이타를 페이징 해야하는 경우도 있다. (이 10개이상 조인은 상당히 비추천이지만 어쩔수 없는 경우가 있다 -_-;;;)

거기다 또 다른 문제는 쿼리문에 Distinct, Group, Having..등등 절을 사용했을 경우 실제 기존 사용하던 페이징 쿼리를 사용하면 잘 안맞는 경우가 있다. 이 부분은 개발시에 생각보다 간과하게 쉬운데 꼼꼼히 살펴보면 페이징 되는것이 뭔가 이상함을 발견할 수 있을것이다. 무리하게 기존 페이징 코드 Copy & Paste했다간 추후 낭패를 본다 -_- 이런 쿼리들을 실제로 보여줬으면 좋을텐데 아쉽게도 제대로 정리해두질 않았고 그런 쿼리들을 지금 만들자니 끔찍하다. 그러니 그냥 '그런 경우도 있구나...' 라고만 생각해라 -_-;;;

 

이번에 다룰 페이징 함수는 위와 같은 문제점을 한방에 해결해준다. 적용하기 쉽고, 코드양 현저하게 줄어들고, 어떤 쿼리라도 정확하게 페이징 해준다.(물론 100% 장담 못한다. -_- 그냥 허위광고라 생각해라 -_-)

단! 단점이 있다. 속도는 보장 못한다. 이 함수는 속도보다는 편리함에 중점을 둔것이다. 페이징 속도를 생명처럼 여긴다면 이 함수 적용하지 않는것이 좋다. 뭐..그렇다고 속도가 기존 페이징 쿼리보다 2배이상 현저하게 떨어진다거나 그렇진 않다. 단지 속도에 중점을 둔 쿼리가 아니라는 것이다. (실제 개발에 사용했을때도 페이징 속도때문에 문제된적은 한번도 없었다 -_-)

또 한가지 단점은 레코드 수가 1000000000(10억)이 넘는 게시물은 페이징 할 수 없다. 이렇게 제한을 둔 이유는 Top 쿼리문 특성 때문인데...이 함수 만들당시에 왜 10억개로 제한했는지 기억이 안난다 -_-;; 그 당시 무슨 이유때문에 이렇게 만들어 두었는데 당췌 기억이... -_-;; 대충..기억으론 Top에서 사용할수 있는 개수 제한이 있었던것 같은데 지금 좀더 높은 수로 테스트 해봐도 된다. 문제는 그 당시는 ms-sql 2000으로 테스트 했었고 지금 로컬에 설치되어있는것은 ms-sql 2005이다. 그래서 정확하게 비교가 좀 그렇다.

혹시 Top 절의 개수 제한이 있는지 도움말과 이런 저런 책을 잠깐 봤는데..음 찾을수가 없다. 그냥 10억개로 제한해두고 사용하자! 알겠지만 10억개까지 있는 게시물은 평생 찾아보기 힘들고 만들기도 힘들다. 일전에 큰머리님의 페이징 자료 테스트 해본다고 100만개 레코드 생성하는데 하다 포기했다. 한 40만개까지인가 만든것으로 기억하는데 간단한 레코드인데도 생성시간이 대략 한시간정도 걸린것으로 기억한다 -_-;;; 그러니 10억개 레코드 테스트 해보려고 한다면 몇일간 컴퓨터 개고생 시켜야 할것이다.

음..뭔가 서론이 상당히 긴듯한데 결론은 ...다시 읽어보니 왠지 이 함수의 단점들을 변명하는것 같군 -_- 아무튼 실제 개발에 적용해도 문제없는 함수이니 필요하면 가져다 사용하자!

 

아래는 페이징 안하고 모든 레코드 가져오는 코드이다.

<% OPTION EXPLICIT %>
<%
Dim DBCon : Set DBCon = Server.CreateObject("ADODB.Connection")
Dim strConn : strConn = ""
Dim strQry
Dim rs

strConn = strConn&"Provider=SQLOLEDB.1;Persist Security Info=True;"
strConn = strConn&"Data Source=localhost;"  ' Server Name
strConn = strConn&"User ID=sa;"             ' User ID
strConn = strConn&"Password=;"              ' User Password
strConn = strConn&"Initial Catalog=NorthWind;"   ' DataBase
DBCon.Open strConn

strQry = "select CompanyName from Customers"
Set rs = DBCon.Execute(strQry)

Do While not rs.eof
    Response.Write rs(0) & "<hr>"
    rs.MoveNext()
Loop
rs.Close
Set rs = nothing
%>

이 코드에 페이징 처리 구문을 넣어보자

<% OPTION EXPLICIT %>
<!--#include file="asp_page_function.asp"-->
<%
Dim DBCon : Set DBCon = Server.CreateObject("ADODB.Connection")
Dim strConn : strConn = ""
Dim strQry
Dim rs
Dim req_curPage : req_curPage = Request("curPage")

strConn = strConn&"Provider=SQLOLEDB.1;Persist Security Info=True;"
strConn = strConn&"Data Source=localhost;"  ' Server Name
strConn = strConn&"User ID=sa;"             ' User ID
strConn = strConn&"Password=;"              ' User Password
strConn = strConn&"Initial Catalog=NorthWind;"   ' DataBase
DBCon.Open strConn

strQry = "select CompanyName from Customers"
Set rs = ExecutePage(strQry,req_curPage)

Do While not rs.eof
    Response.Write rs(0) & "<hr>"
    rs.MoveNext()
Loop
rs.Close
Set rs = nothing

' 페이지 이동 부분 뿌려준다.
Response.Write ShowPageBar(req_curPage,"","","")
%>

단지, 강조된 부분만 처리해주면 바로 페이징이 된다! 몇번을 야려봐도 정말 간단하다(나만 간단한가 -_-;;)

하나씩 살펴보면 일단 보여줄 페이지 번호를 Request로 받아온다.

 
Dim req_curPage : req_curPage = Request("curPage")

그래서 그 보여줄 페이지 번호와 쿼리문을 ExecutePage 함수에 인자로 던져준다.

 
Set rs = ExecutePage(strQry,req_curPage)

그런후 페이지 이동바 함수를 호출해서 뿌려주면 끝이다.

 
Response.Write ShowPageBar(req_curPage,"","","")

만약 뿌려질 목록수를 10개에서 20개 혹은 30개로 조절하고 싶다거나 페이지 이동바의 모양을 변경하고 싶다거나.. 등등 미묘한 설정을 건드리고 싶다면 asp_page_function.asp 이 파일 열어서 수정하면된다. 나름대로 주석 여기저기 달아두었으니 수정하는데 그리 큰 어려움은 없을꺼라 본다. 아! 잠시 깜빡하고 넘어갈뻔했는데 실제로 이 페이징 함수 적용하려면 asp_page_function.asp 파일 수정해 줘야한다. 거기서 DB연결 객체의 Execute 이용하는데.. 개발자마다 DB연결객체 처리 방식이 틀리기 때문에 그 부분은 수정해 줘야한다. 그러니 소스코드 다운받고 실행하고선 곧바로 '이거 왜 안되지?'라고만 생각하지 말고 자신의 설정에 맞게 코드들 좀 수정해 줘야한다.

마지막으로 asp_page_function.asp의 코드를 보자 이 페이징 처리의 핵심 로직이 들어가있다 -_-

<%
'#################################################################################
'# 페이징 관련 함수
'#################################################################################

' 페이징시 필요한 전역변수 2개
Dim G_PAGE_SIZE : G_PAGE_SIZE = 10  ' 뿌려질 레코드 개수
Dim G_TOTAL_RECORD                  ' 전체 레코드 수


'/* 쿼리문 + 페이징 */
Public Function ExecutePage(ByVal pSql, ByVal pPage)
    Dim rs : Set rs = Server.CreateObject("ADODB.RecordSet")
    Dim strSQL
    Dim nPage
    Dim cut, l_sql, r_sql
    
    If pPage = "" or isNull(pPage) Then pPage = 1

    pSql = UCase(pSql)                  ' 대문자로 변환  
    pSql = Replace(pSql, vbTab, " ")    ' 쿼리문의 Tab은 Space로 
    pSql = Replace(pSql, vbCr, " ")     ' 쿼리문의 개행은 Space로
    
    cut = InStr(1, pSql, " TOP ")
    ' top 절이 없으면 order by에서 오류 - top절 있는지 검사
    If cut = 0 Then
        cut = InStr(1, pSql, " DISTINCT ")
        If cut > 0 Then
            ' distinct 가 있을 경우
            cut = cut + 8
            l_sql = Left(pSql, cut)
            r_sql = Right(pSql, Len(pSql) - cut - 1)
            
            pSql = l_sql & " TOP 1000000000 " & r_sql
        Else
            ' distinct 가 없을 경우
            cut = InStr(1, pSql, "SELECT ")
            If cut > 0 Then
                cut = cut + 5
                l_sql = Left(pSql, cut)
                r_sql = Right(pSql, Len(pSql) - cut - 1)
                
                pSql = l_sql & " TOP 1000000000 " & r_sql
            End If
        End If
    End If
    
    nPage = pPage * CLng(G_PAGE_SIZE)
    strSQL = "Select TOP " & CStr(nPage) & " * From (" & pSql & ") AS _TEMP_PAGE_TABLE"
    
    G_TOTAL_RECORD = ExecuteCount(pSql)     ' 쿼리문의 전체 레코드 수 구함
        
    rs.CursorType = 1
    rs.PageSize = G_PAGE_SIZE
    rs.Open strSQL, DBCon
    
    If Not (rs.EOF Or rs.BOF) Then rs.AbsolutePage = pPage
    
    Set ExecutePage = rs
End Function

'/* 쿼리문을 주면 그 쿼리문의 레코드 수를 반환 */
Public Function ExecuteCount(ByVal pSql)
    Dim rs : Set rs = Server.CreateObject("ADODB.RecordSet")

    pSql = "Select Count(*) From (" & pSql & ") AS _TEMP_PAGE_TABLE_CNT"
    Set rs = DBCon.Execute(pSql)
    
    ExecuteCount = CLng(rs(0))
    rs.Close
    Set rs = nothing
End Function

'/* 페이징시 전체 페이지수 계산 */
Function GetPageCount(ByVal pTotalRecord)
    Dim retVal
    
    pTotalRecord = CLng(pTotalRecord)
    retVal = Fix(pTotalRecord / G_PAGE_SIZE)
    If (pTotalRecord Mod G_PAGE_SIZE) > 0 Then
        retVal = retVal + 1
    End If
    GetPageCount = CLng(retVal)
End Function

'/* 페이지 네비게이션을 뿌려주는 함수 */
Public Function ShowPageBar(ByVal pCurPage, ByVal pPreImg, ByVal pNextImg, ByVal param)
    Dim nPREV
    Dim nCUR
    Dim nNEXT
    Dim i
    Dim nPageCount
    Dim retVal
    Dim strLink
    Dim pageKubun

    If pCurPage = "" or isNull(pCurPage) Then pCurPage = 1
    
    nPageCount = GetPageCount(G_TOTAL_RECORD)
    
    If pPreImg = "" Then
        pPreImg = "[이전]"
    Else
        pPreImg = "<img src='" & pPreImg & "' border=0 align=absmiddle>"
    End If
    
    If pNextImg = "" Then
        pNextImg = "[다음]"
    Else
        pNextImg = "<img src='" & pNextImg & "' border=0 align=absmiddle>"
    End If
    
    nPREV = (Fix((pCurPage - 1) / 10) - 1) * 10 + 1
    nCUR = (Fix((pCurPage - 1) / 10)) * 10 + 1
    nNEXT = (Fix((pCurPage - 1) / 10) + 1) * 10 + 1

    ' [이전] 페이지 조합
    If nPREV > 0 Then
        strLink = "?curPage=" & nPREV & param
        retVal = "<a href=""" & strLink & """>" & pPreImg & "</a> "
    Else
        retVal = "" & pPreImg & " "
    End If
    i = 1
    Do While i < 11 And nCUR <= nPageCount
        If nCUR = nPageCount Or i = 10 Then
            pageKubun = " "
        Else
            pageKubun = " . "
        End If
        
        If CInt(pCurPage) = CInt(nCUR) Then
            retVal = retVal & "<font color=#FF6700 size=3><b>" & nCUR & "</b></font>" & pageKubun
        Else
            strLink = "?curPage=" & nCUR & param
            retVal = retVal & "<a href=""" & strLink & """>" & nCUR & "</a>" & pageKubun
        End If
        nCUR = nCUR + 1
        i = i + 1
    Loop
    ' [다음] 페이지 조합 
    If nNEXT <= nPageCount Then
        strLink = "?curPage=" & nNEXT & param
        retVal = retVal & " <a href=""" & strLink & """>" & pNextImg & "</a>"
    Else
        retVal = retVal & pNextImg & ""
    End If
    
    ShowPageBar = retVal
End Function
%>

(이상하게 asp_page_functioh.asp 의 소스코드가 star-light 적용했더니 들여쓰기가 잘 안맞는다. -_- 실제 소스코드는 제대로 되어있으니 실제 코드 다운받아 보면된다.)

함수 총 4개에 전역변수 2개다.

전역변수 2개는 "보여줄 게시물 갯수 지정", "전체 레코드 수" 이다. 함수 4개에서 이 전역변수 2개를 이용해서 데이타를 만들어 내기 때문에 없애거나 변수명 수정하면 안된다. 만일 수정하려면 함수안에 있는 전역변수 명까지 다 수정해주자. 이렇게 함수간의 통신을 위해서 전역변수를 이용하는 방법은 그다지 좋은 방법은 아닌데..내가 기존에 사용하고 있던 모듈에서 페이징 부분만 떼어오다보니 이렇게 바꿔버리게 되었다. 원랜 소스는 전역변수들이 전부 클래스의 멤버 변수로 선언되서 사용되는데 공개용으로 함수를 만들다보니 클래스를 이용하는 방법이 적당치 않은듯해서...어찌 어찌 하다보니 이렇게 되었다 -_-;;;

함수 4개는 "페이징 처리 함수","전체 레코드수 가져오는 함수","페이지 갯수 계산하는 함수","페이지 이동바 만들어주는 함수" 이렇게 4개인데 그 중에서 첫번째 함수의 마지막 함수만 주의해서 보면 된다. 첫번째 함수는 쿼리문과 페이지 번호를 받으면 그 페이지에 해당하는 게시물만 가져오는 함수다. 가장 중요한 함수다. 자세한 설명은 없다. 그냥 야리는거다. -_- 마지막 함수는 페이지이동바를 만들어주는데...역시나 보면 안다. -_-

오늘도 이렇게 날림강좌 하나 완성이다. 후훗 뿌뜻하다.

 

 

 

p/s 이번 강좌 적으면서 내 강좌에 대한 내 스스로 느낀점
1. 헛소리가 많다.
2. 지식이 얕고 귀찮아서 자세한 정보 잘 제공 안한다.
3. 소스코드 전체를 그냥 보여준다.
4. 그 소스코드 설명 안하고 무조건 야리라고만 한다.
5. 그림이 없어서 이해가 힘들다.
5. -_- <ㅡ 요게 너무 많다 -_-


댓글 '4'

선한악마

2007.07.26 10:34:13
*.128.77.141

10자 이상적으랍니다. 잘 보겠습니다.

버러지

2008.05.15 14:50:02
*.140.107.162

p/s 이부분이 공감이 잘가구요~ 그래서 더 좋은듯 해요 심플한 강좌 ㅋㅋ ^^ 감사 잘보고 갑니다.

감사

2009.03.12 18:29:36
*.57.31.20

좋은 정보 퍼갑니다..정말 감사합니다 ^^

멜랑꼴랑

2011.03.29 10:23:55
*.98.68.119

좋은 정보 감사합니다!!

문서 첨부 제한 : 0Byte/ 2.00MB
파일 크기 제한 : 2.00MB (허용 확장자 : *.*)
List of Articles
번호 제목 글쓴이 날짜 조회 수
27 keyfile을 이용한 ssh 접속 방법 뭉충닷컴 2010-10-28 13824
26 멀티 브라우저 지원하는 frame, iframe 접근 코딩 방법 [3] 뭉충닷컴 2010-07-21 27271
25 crontab을 이용한 Tomcat 서버 자동 재시작 shell 뭉충닷컴 2009-08-28 25425
24 자바스크립트로 각 form의 element(요소)에 접근 방법 file [2] 뭉충닷컴 2008-09-11 63515
23 ERwin 에서 Logical의 컬럼명을 코멘트(Comment)로 변경하기 file [2] 뭉충닷컴 2008-01-16 32377
22 Tabular Data Control 마지막 강좌! 뭉충닷컴 2007-06-14 15720
21 ASP로 웹 어플리케이션 주소 사용하기 file 뭉충닷컴 2006-12-10 18056
20 VB로 WebBrowser 컨트롤의 HTML 제어 file 뭉충닷컴 2006-12-01 21569
» ASP 페이징 쉽게 처리하기 file [4] 뭉충닷컴 2006-08-29 24701
18 두개의 비슷한 DB를 비교해서 변경된 부분 찾아내기 file 뭉충닷컴 2006-05-03 15044
17 ASP에서 Class 를 이용해보자 file 뭉충닷컴 2006-02-26 25236
16 Hotmail의 DHTML EDITOR 편집기를 이용해보자. file [34] 뭉충닷컴 2006-02-04 30410
15 Tabular Data Control 응용 - 제목 Sort (정렬) 쉽게 하기 [3] 뭉충닷컴 2006-01-27 14155
14 스크립트(Script) 코드를 암호화 시켜보자(Encode/Decode) [2] 뭉충닷컴 2005-06-10 19171
13 dll을 이용한 로그인 file [1] 뭉충닷컴 2005-11-25 22155
12 Tabular Data Control 응용 - 페이징 처리하는 3가지 방법 file [1] 뭉충닷컴 2005-11-23 16335
11 Query를 잼있고, 유용하게 사용해보자 file [3] 뭉충닷컴 2005-10-01 14764
10 Tabular Data Control 응용 - 테이블의 행 배경색이 격으로 변하게하기 뭉충닷컴 2005-09-25 15837
9 폼(Form) 검증해주는 스크립트(Script) file [15] 뭉충닷컴 2005-06-07 19641
8 asp 로 서버에 zip 압축/압축해제(풀기) 예제 file [8] 뭉충닷컴 2005-08-12 20213
7 MS-SQL의 osql.exe 이용 하기 (도스상에서 sql 구문 이용) 뭉충닷컴 2005-09-25 19414
6 SQL Script 로 ERD와 테이블 생성 손쉽게하기 뭉충닷컴 2005-09-25 22316
5 Tabular Data Control 기초 다지기 4 - 마지막! file 뭉충닷컴 2005-09-25 14749
4 Tabular Data Control 기초 다지기 3 file 뭉충닷컴 2005-09-25 14509
3 Tabular Data Control 기초 다지기 2 file 뭉충닷컴 2005-09-25 14251
2 Tabular Data Control 기초 다지기 1 file [1] 뭉충닷컴 2005-09-25 15404
1 OWC를 이용한 웹에서 엑셀 그래프 그리기 file [4] 뭉충닷컴 2007-12-19 19880