【问题标题】:SQL get ROW_NUMBER and COUNT on every SELECT requestSQL 在每个 SELECT 请求上获取 ROW_NUMBER 和 COUNT
【发布时间】:2014-09-16 10:21:56
【问题描述】:

我正在构建一个网格机制,我需要从数据库中检索找到的总数或记录的数据,只检索其中包含 row_number 的这些记录的范围。

我正在使用 SqlServer 进行测试,但我还需要在 Oracle 和 MySql 上支持它。

这就是我正在尝试的,但我无法让它发挥作用:

    SELECT * FROM 
           (SELECT ROW_NUMBER() AS RN, 
                   COUNT(*) AS TOTALCN, 
                   Id, 
                   Name, 
                   Phone 
            FROM MyTable WHERE Deleted='F')
            WHERE RN > 100 AND RN < 150;

想法是:

MyTable -> number of records: 1000
Select Id, Name, Phone from MyTable where Deleted='F' -> number of records: 850
Get the records 100 to 150 from the 850.

我想得到一个像这样的选择:

RN   TOTALCN Id    Name   Phone
1    850     Data  Data   Data
2    850     Data  Data   Data
3    850     Data  Data   Data
4    850     Data  Data   Data
5    850     Data  Data   Data
6    850     Data  Data   Data

CN (850) 将是我的网格总记录数。 RN 将是数据的网格索引。

有人可以帮我完成吗?

感谢您的帮助。

[编辑]

所以,我肯定会在每个 SELECT 上添加一个 ORDER BY。到目前为止,这是我所得到的:

SELECT * FROM (SELECT ROW_NUMBER() 
              OVER (ORDER BY ID)  AS RN, 
              COUNT(*) OVER (ORDER BY (SELECT NULL) AS CNT) 
              Id, Name Phone FROM MyTable WHERE Deleted='F') 
T WHERE RN > 100 AND RN < 500;

我走对了吗?

这对 SQL 来说有多昂贵?

【问题讨论】:

  • 这是 MySQL 还是 SQL?语言不一样。

标签: mysql sql-server oracle11g aggregate-functions row-number


【解决方案1】:

在带有一堆详细信息行的同一 SELECT 子句中包含 COUNT(*) 是失败的。那是因为COUNT(*) 是一个聚合函数。在没有GROUP BY 的情况下,它只返回其结果集中的一行。因此,您需要在其自己的SELECT 语句中查询计数。

SQL Server 具有ROW_NUMBER() 函数。 Oracle 有一个名为ROWNUM 的伪列。 MySQL 有一个非常糟糕的获取行号的方法。它被描述为here。 MySQL - Get row number on select

【讨论】:

  • 所以,我可以理解我的选择是:(a) 在每次选择时添加一个 order by,(b) 执行 2 个不同的查询 - 一个用于计数,一个用于数据?
  • Oracle 也有row_number();和count() 的分析版本,它不需要group by 子句,也不需要自己的select。试图找到一种适合所有三个数据库的解决方案可能会导致心痛...
【解决方案2】:

这可能是为了允许分页。显示总行数可能非常昂贵。

我发现在各种数据库上都能很好地工作的一种方法是将工作分成两部分。首先,您在临时表中收集相关行的 ID。其次,您查询完整的数据集。第一部分收集的数据为您提供了一种简单的方法来计算特定页面上的总行数和行 ID。

以下是 SQL Server 的粗略示例。请注意,该示例不依赖于像 row_number() 这样的窗口函数,这些函数在 MySQL 中不可用。

create table #id_list (rn int identity, pk int);

insert   #id_list
         (pk)
select   customer_id
from     customers
where    name like '%Joe%';

select   (select  count(*) from #id_list) as total_rows
,        rn -- The row's number
,        name
,        birth_date
,        ... -- Other columns
from     #id_list id
join     customer c
on       c.pk = c.customer_id
where    rn between 15 and 29; -- Second 15-row page 

顺便说一句,如果可行,我会将此要求返回给设计人员,以仔细检查这是否值得花费大量时间。如果您不需要显示总行数,则要简单得多。

【讨论】:

  • 我认为与添加订单相比,这将非常昂贵......我说得对吗?
  • 在我的测试中,这是性能最好的解决方案。如果我是你,我会写一些替代方案并测试它们!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
  • 2013-02-02
  • 2012-12-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多