本人用C#做了一个web的动态查询器,查询的数据量可能比较大。现求一动态查询结果的数据库分页方法。
注意:
1:要求实现数据库内部分页(输入:sql,页号码,每页显示行数)然后显示对于数据。
2:查询器最后输出的只是一条sql语句(可能含有where,group by ,聚会函数,order by等部分,甚至嵌入子查询)。
3:不知道查询的主键(网上的方法全部要求有主键)。
4:可以在C#.net,或者存储过程实现。
5:考虑web项目的性能问题,这个查询使用的十分频繁。

解决方案 »

  1.   

    建议搜索一下csdn。有很多这样的例子。吴哥有实例。
      

  2.   

    http://www.webdiyer.com可以去参考一下
      

  3.   

    http://community.csdn.net/Expert/topic/3592/3592434.xml?temp=7.075137E-02
      

  4.   

    wssmax(请叫我三角猫):我查过csdn,例子的确不少,但谈到数据库分页都是要求有主键,如今我的例子是只有一个sql语句,根本不知道主键。如何实现?hackate(兰花开香入梦境,独思佳人亦飘然!!) :你的例子显示“无法打开登录 'webdiyer' 中请求的数据库。登录失败。用户 'webdiyer' 登录失败。”的错误。看来要求先登陆。morality(业精于勤,行成于思!):同样,你的例子要求有主键的输入。如今我的例子是只有一个sql语句,根本不知道主键。如何实现?
      

  5.   

    搜webdiyer.com分布控件,可以找出很多别的下载站也有下载啊。里面有详细的帮助,而且开源。
      

  6.   

    搜webdiyer.com分布控件?www.webdiyer.com打不开,提示错误啊。
      

  7.   

    楼上rd16和hackate推荐的www.webdiyer.com做的分页控件很好,但楼主的问题难点不在此,而是动态sql语句的生成。楼主需求表达不清,查询语句是动态的,那么你打算如何让用户来“设计”这个语句呢?极端的说,让用户自己用sql enterprise manager连接数据库不就可以了么,不描述UI此题无解。
      

  8.   

    athossmth(athos):关于动态sql语句生产我已经完成,是通过一个查询器提供用户完成(类似万能查询)。反正sql语句已经产生,而且确符号语法,问题是查询的数据量可能比较大,在web页中我要解决2个问题。
    1:分页问题(数据库分页,因为sql语句动态产生,所以不能确定主键)。
    2:打印问题(我看了不少的例子都不是完全动态,或者是导出一个文件再打印,目前没有比较好的解决办法,我试过研究水晶报表,不能处理大量动态列问题。如果有,渴望提供)。
      

  9.   

    如果是sql语句以生成,则很简单,因可以传给分页控件主键列表。不知道你的查询器是怎么做的,一般可以读取数据库中table主键设置,可以提示用户选定主键或“主表”。另,cuike519曾经发布过一个控件PowerGrid,它是datagrid的一个扩充,可以完成数据的分页。还有一个办法是自己对运行结果加一个递增数的列作为主键,反正并不涉及数据更新,足够了。又,你的查询器是怎么做的?很感兴趣啊,有时间请email联系,我的:[email protected]
      

  10.   

    athossmth(athos):因为我查询的数据源根本不是一个表,是多个表集合的视图(开发人员事前配置的),所以没有主键。如果使用datagrid分页,页面很慢,根本不能接受。所以才必须用数据库内部分页。
    你说的运行结果加一个递增数的列作为主键,我考虑过。这样对后面的打印操作有影响,而且这个查询器就有不通用的限制(当然可能是我水平不足,见笑)。
    至于我的查询器。msn:[email protected]
      

  11.   

    如果是嫌datagrid慢的话webdiyer的分页控件倒是很好的解决方案,已经email给你,并加了msn
      

  12.   

    我有现成的方法,不要求主键,但最好order by 的那个字段是主键,那样才有最高的性能。/// <summary>
    /// 获取分页的数据集
    /// </summary>
    /// <param name="strSql">带SELECT的SQL查询语句</param>
    /// <param name="pageSize">每页的记录数</param>
    /// <param name="nCount">记录总数</param>
    /// <param name="pageIndex">要获取记录的页码</param>
    /// <param name="key">排序的字段,主键或有索引的字段</param>
    /// <param name="sortType">ASC 或 DESC</param>
    /// <returns>DataSet</returns>
    public static DataSet getDataByPage(string strSql,int pageSize,int nCount,int pageIndex,string key,string sortType)
      

  13.   

    如下代码动态为每一个查询创建主键,其它分页就参照已发表的哦Dim co As New DataColumn
    co.AllowDBNull = False
    co.AutoIncrement = True
    co.AutoIncrementSeed = 1
    co.AutoIncrementStep = 1
    co.ColumnName = "Alpha_AID"
    co.Unique = True
    NewTable.Columns.Add(co) dbAdpt.Fill(NewTable)
      

  14.   

    lamcoo(烟虫):一个动态的sql语句不一定有order by 部分。而且有的时候也可能不止一个,ASC 或 DESC就可能有多个了,最主要的是你的函数和“AlphaGIS(飘零) ”朋友的都是C#(服务器实现)这样效率虽然有提高,但还是不如用数据库分页(直接在存储过程中实现)好。不过如果讲你们的思路放到存储过程中可以实现吗,可以将一个动态sql放到一个临时表(#table),然后再在#table加上一列自增的列(identity)吗?
      

  15.   

    steary(good) ,当然,将我的方法里的逻辑写到存储过程里去,也可以。一样的原理的。但用临时表完全没有必要。原理是:(举例说明:获取第6页的数据,每页10条记录)
    1) select top 60 .. order by key, 得到第一个数据集,
    2) 将1的结果反过来,再取前10,得到第60~51的记录(反的)。
    3)再反一次,得到51~60条记录,即第6页数据。以上过程全部在一句SQL语句得到。当然,还要考虑最后一页数据数的问题。
      

  16.   

    在以前ASP作过有点类似但也有不同, 至少没你的要求那么多.
    看有没有点用....sqlPS="select * From Employee Left JOIN Department ON Employee.DepartmentID=Department.DepartmentID Order By Employee.DepartmentID,Employee.EmNO"call GetPage_RSDT(sqlPS,con,intListCount,"PageControl","EmID","frmList",rsPS)
    '|ResultPageRS(Sql串,连接,每页行数,页号,过滤字段,表单名,)
     function GetPage_RSDT(strSqlText,objConn,intPageSize,PageControl,KeyID, strFormName, Ref_RS)
     set Rsdt=Server.CreateObject("ADODB.Recordset")
    if IsNumeric(PageControl) then
    intPageIndex = PageControl
    CurrentPage = "PageControl"
    else
    CurrentPage = PageControl
    intPageIndex = Trim(Request(PageControl))
    if IsNumeric(intPageIndex) then
    if intPageIndex <= 0 then intPageIndex = 1
    else
    intPageIndex = 1
    end if
    end if

    dim strSql,strPageOut,intAll,intNot,intPos,intOrder,intWhere

    RsTotalCount = dbCount(strSqlText,objConn) strSql = Trim(strSqlText)
    intPos_Select = instr(1,strSql,"select",1) + 6
    'response.Write(Left(strSql,6)) & "|<BR>"
    'response.Write(Left(strSql,7)) & "|<BR>"
    'response.Write("|"& mid(strSql,7)) & "|<BR>"
    'response.Write("|"& mid(strSql,8)) & "|<BR>"
    'response.End 
    strSql_1 = Left(strSql,intPos_Select) '|取出 select
    strSql_2 = Mid(strSql,intPos_Select+1) '|取出 select 之后的内容


    intPos = InStr(UCase(strSql_2)," FROM ") '|取出表单
    intWhere = InStr(UCase(strSql_2)," WHERE ") '|取出条件
    intOrder = InStr(UCase(strSql_2)," ORDER ") '|取出排序 Sql_7

    strSql_6 = left(strSql_2,intOrder)
    if intOrder > 0 then 
    strSql_7 = mid(strSql_2,intOrder)
    strSql_2 = strSql_6
    end if
    '|Response.Write(strSql_7 & "<hr>") 
    if intWhere > 0 then
    strSql_2 = left(strSql_2,intWhere+6) & "(" & mid(strSql_2,intWhere+7) & ")" '|重载变量
    end if

    intAll = cint(intPageIndex) * cint(intPageSize)
    intNot = cint(intPageIndex - 1) * cint(intPageSize)

    strSql_3 = " Top " & cint(intPageSize) & " "
    strSql_4 = " Top " & intNot & " "

    if intWhere > 0 then
    strSql_5 = " AND ((" & KeyID & " NOT IN (" & strSql_1 & strSql_4 & " " & KeyID & " " & mid(strSql_2,intPos) & " " & strSql_7 & ")))"
    else
    strSql_5 = " WHERE ((" & KeyID & " NOT IN (" & strSql_1 & strSql_4 & " " & KeyID & " " & mid(strSql_2,intPos) & " " & strSql_7 & ")))"
    end if

    'response.Write(strSql_1 & "<hr>") '|select 
    'response.Write(strSql_3 & "<hr>") '|Top 4 
    'response.Write(strSql_2 & "<hr>") '|源SQL * - Where ..
    'response.Write(strSql_5 & "<hr>") '|附加 where
    'response.Write(strSql_7 & "<hr>") '|Order by

    strSql = strSql_1  & strSql_3 & strSql_2 & strSql_5 & strSql_7
    '| Response.Write(strSql) '| "SELECT TOP 9 * FROM Manager WHERE (ID NOT IN (SELECT TOP 2 ID FROM Manager))"
    'response.Write strSql
    '||response.End

    Rsdt.Open strSql,con,1,1
    if TypeName(Ref_RS) = "Recordset" then set Ref_RS = Rsdt

    call getPageControl(intPageIndex,intPageSize,RsTotalCount,strFormName,CurrentPage)
    'Rsdt.Close()
    'set Rsdt = nothing
     End function
      

  17.   

    我还是多谢各位给出各类的答案,只要有回答的朋友我都一定给分,但希望你们提供的方法记得:
    1:没有 Pk,key,order by的这个东西,输入只是一个sql。
    2:在存储过程中实现。
    谢谢各位高手。一旦有解决方法,我会贴出来。
      

  18.   

    试试这个方法,看性能如何?
    我现在也在想这个问题.这个方法其实就是做减法,用  记录集(startPage+pageSize)-记录集(startPage)
    我没有用IN,是觉得这样性能可能高些.declare @pagesize int
    declare @startpage int
    declare @sql varchar(4000)
    set @startpage=30
    set @pagesize=10set @sql='select ee.* from (select top '+ convert(varchar,@pagesize+@startpage) +' aa.* from t4 aa) ee where 
    not exists(select ff.* from (select top '+convert(varchar,@startpage) +' bb.SID from t4 bb) ff where ee.SID=ff.SID)'exec(@sql)
      

  19.   

    各位朋友,谢谢你们的提供各种的答案。关于动态的没有主键(记得,这是全局问题的焦点,如果有主键根本不需要如此复杂)的sql语句分页的解决方案。在大家的帮助下我在已经有相对比较完善的解决办法。等完全测试,我就公布出来,希望各位参考,然后结贴,再次谢谢各位。如果有必要,可以和我探讨。
      

  20.   

    一个高效的分页存储过程 
    摘自CSDNCREATE PROCEDURE PAGINATION@tblName   varchar(255),       @strGetFields varchar(1000) = '*',  @fldName varchar(255)='',     @PageSize   int = 10,       @PageIndex  int = 1,       @doCount  bit = 0,  @OrderType bit = 0,  @strWhere  varchar(1500) = ''  ASdeclare @strSQL   varchar(5000)      declare @strTmp   varchar(110)       declare @strOrder varchar(400)       if @doCount != 0  begin    if @strWhere !=''    set @strSQL = 'select count(*) as Total from [' + @tblName + '] where '+@strWhere    else    set @strSQL = 'select count(*) as Total from [' + @tblName + ']'end  elsebegin if @OrderType != 0begin    set @strTmp = '<(select min'    set @strOrder = ' order by [' + @fldName +'] desc'endelsebegin    set @strTmp = '>(select max'    set @strOrder = ' order by [' + @fldName +'] asc'end if @PageIndex = 1begin    if @strWhere != ''       set @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from [' + @tblName + '] where ' + @strWhere + ' ' + @strOrder     else     set @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from ['+ @tblName + '] '+ @strOrderendelsebeginset @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from ['    + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['+ @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['+ @fldName + '] from [' + @tblName + ']' + @strOrder + ') as tblTmp)'+ @strOrder if @strWhere != ''    set @strSQL = 'select top ' + str(@PageSize) +' '+@strGetFields+ '  from ['        + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['        + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['        + @fldName + '] from [' + @tblName + '] where ' + @strWhere + ' '        + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrderend end   exec (@strSQL)GO