【问题标题】:Get data from Select top从选择顶部获取数据
【发布时间】:2020-02-01 11:26:04
【问题描述】:

我之前的问题已经回答了Select top using SQL Server returns different output than select *

我想从基于字母和编号格式的数据库中获取select top n 数据。输出必须先按字母排序,然后按数字排序。

当我尝试获取所有数据 (select *) 时,我得到了正确的输出:

select nocust, share 
from TB_STOCK
where share = ’BBCA’ 
  and concat(share, nocust) < ‘ZZZZZZZZ’
order by 
    case when nocust like ‘[a-z]%’ then 0 else 1 end, nocust


nocust | share
-------+--------
a522   | BBCA
b454   | BBCA
k007   | BBCA
p430   | BBCA
q797   | BBCA
s441   | BBCA
s892   | BBCA
u648   | BBCA
v107   | BBCA
4211   | BBCA
6469   | BBCA
6751   | BBCA

当我尝试select top n(例如:前 5 名)时,我也得到了正确的数据:

select top 5 nocust, share 
from TB_STOCK
where share = ’BBCA’ 
  and concat(share, nocust) < ‘ZZZZZZZZ’
order by 
    case when nocust like ‘[a-z]%’ then 0 else 1 end, nocust

nocust | share
-------+--------
a522   | BBCA
b454   | BBCA
k007   | BBCA
p430   | BBCA
q797   | BBCA

问题是当我尝试根据最后一次攻击获得下一个前 5 名并分享之前的前 5 名数据时 (concat(share, nocust) &lt; 'ZZZZq797')) 它返回错误的预期数据:

select top 5 nocust, share 
from TB_STOCK
where share = ’BBCA’ 
and concat(share, nocust) < ‘ZZZZq797’
order by 
case when nocust like ‘[a-z]%’ then 0 else 1 end, nocust

nocust | share
-------+--------
a522   | BBCA
b454   | BBCA
k007   | BBCA
p430   | BBCA
q797   | BBCA

它应该返回:

nocust | share
-------+--------
s441   | BBCA
s892   | BBCA
u648   | BBCA
v107   | BBCA
4211   | BBCA

我预计错误在 concat 和 order by 之间,有人可以告诉我如何获得正确的前 5 名。

【问题讨论】:

  • 顺便说一句,我注意到您尚未接受任何问题的答案。请阅读this 并考虑接受您现有问题的答案。

标签: sql-server sql-server-2008 select sql-order-by


【解决方案1】:

我不确定是否有内置函数来获取行范围,但你总是可以使用ROW_NUMBER

select nocust, share
FROM (
  select nocust, share, 
    ROW_NUMBER() OVER(
      ORDER BY case when nocust like ‘[a-z]%’ then 0 else 1 end, nocust
    ) AS RowNum -- Assign rows "row numbers" based on `ORDER BY`
  from TB_STOCK
  where share = ’BBCA’ 
    and concat(share, nocust) < ‘ZZZZZZZZ’
) src
WHERE RowNum BETWEEN <start_row_num> AND <end_row_num> -- Get specified row range
order by 
  case when nocust like ‘[a-z]%’ then 0 else 1 end, nocust -- Not sure if this is needed

这将根据您的ORDER BY 为每一行分配“行号”,然后仅返回您在WHERE 子句中指定的行范围。

【讨论】:

    【解决方案2】:

    您应该显示完整的查询。

    在您的查询中,我也不清楚这件事and concat(share, nocust) &lt; ‘ZZZZZZZZ’。 我没有得到您拥有什么类型的数据以及它将返回什么或您的预期输出是什么

    我想我会在这种情况下创建Indexed view

    CREATE VIEW dbo.vStockView
    WITH SCHEMABINDING
    AS
        select  nocust, [share] ,
     0  SortCol
    from TB_STOCK
    where 
    --  share = ’BBCA’ 
    --  and concat(share, nocust) < ‘ZZZZZZZZ’ 
     -- and 
      isnumeric(nocust)=0
    
      union all
    
      select  nocust, [share] ,
     1  SortCol
    from TB_STOCK
    where 
      isnumeric(nocust)=1
    
    GO
    

    请注意我在 where 条件下的评论,因为这在视图中是不需要的。它可以在 Proc 中实现。

    我没有关于您的查询的完整信息,表格。

    所以低于索引可能没有那么好。

    CREATE NONCLUSTERED INDEX CX_vStockView
      ON dbo.vStockView(SortCol); 
    GO
    

    现在你像这样创建新的过程,

    Create Proc spGETStock
    @share varchar(30)
    @PageNumber int,
    @RowspPage int=30
    as
    
    BEGIN
    set nocount on
    
    select nocust,[share] 
    --,count(*)over() as TotalRecords
    from vStockView
    where share = @share
    ORDER BY SortCol
    OFFSET ((@PageNumber - 1) * @RowspPage) ROWS
    FETCH NEXT @RowspPage ROWS ONLY;
    
    End
    

    或者你可以在Sql server 2008及以下使用Row_Number实现分页。

    我相信它会显着提高性能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-24
      • 2020-03-03
      • 2013-07-04
      • 2015-10-05
      相关资源
      最近更新 更多