优化 SQL 查询

Viv*_*ekh 5 sql-server t-sql

我必须选择小于给定 id 且大于给定 id 的 2 个值。我已经尝试过这个查询,但有没有更好的方法来做到这一点

小提琴Sql

Begin 

declare @rootValue int
declare @repID int

set @repID = 2
set @rootValue = (select Id from tblLookups where Id = @repID)

declare @rootMinusTwo int
declare @rootPlusTwo int

set @rootMinusTwo = (select count(*) from tblLookups where Id < @rootValue)
set @rootPlusTwo = (select count(*) from tblLookups where Id > @rootValue)

if @rootMinusTwo >= 2 and @rootPlusTwo >= 2
Begin
    select *  
    from tblLookups 
    where Id between @rootValue - 2 and @rootValue + 2
End
else if @rootMinusTwo < 2 and @rootPlusTwo >= 2
    select * 
    from tblLookups 
    where Id = @repID 
    union
    select * 
    from tblLookups 
    where Id < @rootValue 
    union
    select top (4 - @rootMinusTwo) * 
    from tblLookups 
    where Id > @rootValue
else if @rootMinusTwo >= 2 and @rootPlusTwo < 2
    select * 
    from tblLookups 
    where Id = @repID 
    union
    select * 
    from tblLookups 
    where Id > @rootValue 
    union
    select top(4 - @rootPlusTwo) * 
    from tblLookups 
    where Id < @rootValue
else if @rootMinusTwo < 2 and @rootPlusTwo < 2
    select * 
    from tblLookups 
    where Id = @repID 
    union
    select * 
    from tblLookups 
    where Id < @rootValue 
    union
    select * 
    from tblLookups 
    where Id > @rootValue
End
Run Code Online (Sandbox Code Playgroud)

我忘了在任何时候添加一些东西,如果有那么多满足条件的记录,那么应该有 5 条记录。

例子

ID 是 1,2,3,4,5 如果我提供 2 那么它也应该返回 5

ype*_*eᵀᴹ 7

相当令人费解,但应与下面的值工作,并返回2行@repid,与行@repid和2行以上的值@repid(假设id是一个独特的密钥)。

如果低于或高于 2 个值,则查询将从另一侧获取更多。总共最多返回 5 行。

注:ORDER BY需要。所有三个(不是第 4 个,只有当您需要按特定顺序的结果时):

with a as
  ( select top (4) 
        *, rnk = row_number() over (order by id desc) 
    from tblLookups
    where Id < @repID
    order by id desc
  ),
b as
  ( select top (5) 
        *, rnk = row_number() over (order by id) - 1
    from tblLookups
    where Id >= @repID
    order by id
  ),
c as 
  ( select top (5) *
    from
      ( select *
        from a
      union all
        select *
        from b
      ) x
    order by rnk 
  )
select *
from c
order by id ;
Run Code Online (Sandbox Code Playgroud)

SQLfiddle测试。


And*_*y M 6

以下基本上是您的算法,但作为单个语句实现:

WITH ranked_and_counted AS (
  SELECT
    ID,
    r = ROW_NUMBER() OVER (ORDER BY ID ASC),
    c = COUNT(*) OVER ()
  FROM
    dbo.tblLookups
),
ranked_and_counted_and_r0 AS (
  SELECT
    *,
    r0 = MAX(CASE ID WHEN @ID THEN r END) OVER ()
  FROM
    ranked_and_counted
)
SELECT
  ID
FROM
  ranked_and_counted_and_r0
WHERE
  r >= CASE WHEN r0 > c - 2 THEN c - 4 ELSE r0 - 2 END
  AND
  r <= CASE WHEN r0 < 1 + 2 THEN 1 + 4 ELSE r0 + 2 END
;
Run Code Online (Sandbox Code Playgroud)

第一个 CTE,ranked_and_counted计算行数和总行数。

第二个 CTE,ranked_and_counted_and_r0确定与指定@ID.

主查询使用获取的值来获取所需的行:

  • 如果参考行号 ( r0) 是表中最后两行之一,则当前行号 ( r) 必须大于或等于行数 ( c) 减四(即必须是最后五行之一),否则应大于或等于参考数字减二;

  • 如果参考行是前两行之一,则当前行号不得大于五,否则应小于或等于参考号加二。

该查询可以在SQL Fiddle进行测试。(演示借用了ypercube的设置。)