【问题标题】:SQL Server procedure design to get results and results count in a single callSQL Server 过程设计可在单个调用中获取结果和结果计数
【发布时间】:2017-08-08 19:23:51
【问题描述】:

我有一个需求,我需要提取数据结果集的前 100 条,以及满足我过滤条件的总数据的记录数。

谢谢, 马诺吉。

【问题讨论】:

    标签: sql-server count multiple-results


    【解决方案1】:

    您可以使用输出参数返回记录总数,也可以使用返回结果集的select 语句。

    例如:

    create procedure test
       @totalCount int output
     as begin
         select * from something -- your select statement goes here
         select @totalCount = 'write your statement that counts the records.'
     end
    

    如果您需要从代码中调用它,这里有一个 Java 示例来说明如何进行调用:

    public void test(Connection con) throws SQLException{
        CallableStatement cs = con.prepareCall("test");
        //you can set more parameters if you need to, i.e.: cs.setInt(0,id);
    
        //you need to register your output parameter. If you are referencing it by name, it should match with the name given in the stored procedure.
        cs.registerOutputParameter("totalCount", Types.INTEGER);
        ResultSet rs = cs.executeQuery();
        while(rs.next()){
           //you can save the data into a data structure; a list for example.
           //Or just print the records.
        }
        //here's how you can get the total count
        int total = cs.getInt("totalCount");
    }
    

    此方法只是向您展示如何拨打电话的示例。不要这样写生产代码!!!

    【讨论】:

    • @Manoj,如果这个答案解决了您的问题,请考虑accepting it。它将帮助其他人找到正确的答案。
    【解决方案2】:

    我的一个答案类似于 A2H,但如果您的“计数”与您选择的查询直接相关,则可以避免“双击” ,但将结果放在#temp 表中。

    不过,您也可以使用@@ROWCOUNT 技巧。这是一个新的答案,恕我直言。

    CREATE PROCEDURE dbo.SelectAndCountExample
       @TotalCount int output
     as 
    
    BEGIN
    
    IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
    begin
        drop table #Holder
    end
    
    
    CREATE TABLE #Holder
    (SurrogateKey INT, SomeValue VARCHAR(64) )
    
    
    /* simulate your insert */
    INSERT INTO #HOLDER (SurrogateKey , SomeValue) 
    select 101 , 'A' union all select 102, 'B'  union all select 103, 'C'  union all select 104, 'D' 
    
    /* optional stuff */   
    /* CREATE CLUSTERED INDEX IDX_TempHolder_ID ON #Holder (ID) */
    /* CREATE INDEX IDX_TempHolder_ID ON #Holder (ID) */
    
    Select @TotalCount = count(*) From #Holder
    
    Select SurrogateKey , SomeValue from #HOLDER
    
    
    IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
    begin
        drop table #Holder
    end
    
    
    END
    
    GO
    
    
    declare @MyVariable int
    EXEC dbo.SelectAndCountExample @MyVariable output
    Select @MyVariable as '@MyVariable Value'
    
    
    
    GO
    

    CREATE PROCEDURE dbo.SelectAndCountExampleUsingRowCount
       @TotalCount int output
     as 
    
    BEGIN
    
    
    select 101 , 'A' union all select 102, 'B'  union all select 103, 'C'  union all select 104, 'D' 
    
    Select @TotalCount = @@ROWCOUNT
    
    
    IF OBJECT_ID('tempdb..#Holder') IS NOT NULL
    begin
        drop table #Holder
    end
    
    
    END
    
    GO
    
    
    declare @MyVariable int
    EXEC dbo.SelectAndCountExampleUsingRowCount @MyVariable output
    Select @MyVariable as '@MyVariable Value'
    

    【讨论】:

    • 在您的解决方案中,@TotalCount 和返回的记录数始终相同。我不认为这是@Manoj 想要的。他想要前 100 行以及满足条件的所有行的计数。
    • 我正在为海报(和未来的读者)提供不同的选择。显然,如果结果行与计数不匹配,将会有 2 个不同的查询......这就是为什么我赞成你的回复。
    • 是的,这是有道理的。我的回答更多是关键点的布局,不包括任何实现(这取决于实现者,他/她想如何去做),并且您提供了有效实现的示例。
    【解决方案3】:

    需要对结果进行分页并同时显示可能的结果页数的情况并不少见,这里可能已经有很多关于此的问题。不幸的是,没有内置的机制来处理这个问题。这让您只有几个选择:

    1. 运行查询两次:一次获取总行数,然后再次获取所需结果的子集/页面。这里的缺点是你运行它两次。 (这是@A2H回答的基础)

    2. 运行一次查询,将结果转储到本地临时表中,并使用@@ROWCOUNT 捕获进入临时表的行数。然后,从临时表中选择所需的结果子集/页面。这里的缺点是您会受到 IO(tempdb 数据文件和事务日志)的影响,尽管使用内存中 OLTP 可能会改善这一点。 (类似于@granadaCoder 的答案,但该答案并未遵循行要求的子集)

    3. 将其构建到应用程序代码中:

      • 声明一个计数器来跟踪总行数
      • 运行完整的查询
      • 调用SqlDataReader.Read()(假设您使用的是.NET)——实际上没有检索任何数据——以获取要跳过的行数,然后读取所需结果的子集/页面的行,以及最后调用SqlDataReader.Read() -- 再一次,没有实际检索任何数据 -- 直到没有什么可读取的。在 3 个部分的每一个中增加行计数器。

      请在 StackOverflow 上查看我的以下答案,其中提供了有关此方法的更多详细信息(和变体):

      TSQL: Is there a way to limit the rows returned and count the total that would have been returned without the limit (without adding it to every row)?

    【讨论】:

      猜你喜欢
      • 2014-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-14
      相关资源
      最近更新 更多