SQL以字母顺序获取结果范围

时间:2011-06-25 00:02:15

标签: sql linq sql-server-2008

我有一个表tblTags,其工作方式与StackOverflows标记系统的工作方式大致相同。

当我查看标签页时,让我们说标签Tutorial我想按字母顺序在它之前和之后显示10个标签。

因此,如果我们获得ID Tutorial的标记30,我们如何以类似的顺序返回记录集:

Tap
Tart
> Tutorial
Umbrellas
Unicorns
Xylaphones

我认为这样做的方法非常糟糕,因为它们涉及检索大量数据。

我不确定是否有可能按照(伪)的方式做一些事情:

SELECT RANGE(0 - 30) FROM tblTags ORDER BY Name ASC

但是如何在没有遍历整个列表的情况下以有效的方式知道教程标签在列表中的位置,直到找到它为止?

我正在使用带有LINQ的SQL Server 2008 R2 Express,如果它有所不同,SQL查询或LINQ将是很好的答案,谢谢!

5 个答案:

答案 0 :(得分:3)

也许工会会奏效。 (我确定我有一些语法错误,但你明白了)

(编辑:感谢评论和其他答案,尤其是rsbarro)


DECLARE @tags AS TABLE(TagID INT, tag VARCHAR(30))
INSERT INTO @tags VALUES(1, 'a')
INSERT INTO @tags VALUES(2, 'b')
INSERT INTO @tags VALUES(3, 'c')
INSERT INTO @tags VALUES(4, 'd')
INSERT INTO @tags VALUES(5, 'e')
INSERT INTO @tags VALUES(6, 'f')
INSERT INTO @tags VALUES(7, 'g')
INSERT INTO @tags VALUES(8, 'h')
INSERT INTO @tags VALUES(9, 'i')
INSERT INTO @tags VALUES(10, 'j');

select * from (select top(2) tag
from @tags
where tag < 'f'
order by tag desc
) a

union

select * from (select top(3) tag
from @tags
where tag >= 'f'
order by tag) b;

但是我会进行性能检查以确定这是否确实比返回更多行然后过滤更快。我觉得有一种更高效的方法。

答案 1 :(得分:3)

建立Jacob的UNION建议,您使用表变量来选择匹配的TagID,然后再与Tag表联接以获取匹配的记录。它并不像我想的那么优雅,但确实有效。

作为旁注,我认为UNION方法可行,但AFAIK SQL Server仅在最后一个SELECT上允许ORDER BY,并且ORDER BY适用于整个结果集(this post也表示同样的事情)。

DECLARE @tags AS TABLE(TagID INT, Name VARCHAR(30))
INSERT INTO @tags VALUES(1, 'a')
INSERT INTO @tags VALUES(2, 'b')
INSERT INTO @tags VALUES(3, 'c')
INSERT INTO @tags VALUES(4, 'd')
INSERT INTO @tags VALUES(5, 'e')
INSERT INTO @tags VALUES(6, 'f')
INSERT INTO @tags VALUES(7, 'g')
INSERT INTO @tags VALUES(8, 'h')
INSERT INTO @tags VALUES(9, 'i')
INSERT INTO @tags VALUES(10, 'j')

DECLARE @selectedTags AS TABLE(TagID INT)
INSERT INTO @selectedTags
SELECT TOP 2 TagID FROM @tags WHERE Name < 'e' ORDER BY Name DESC
INSERT INTO @selectedTags
SELECT TOP 2 TagID FROM @tags WHERE Name >= 'e' ORDER BY Name

SELECT * 
FROM @tags T
JOIN @selectedTags ST ON ST.TagID = T.TagID
ORDER BY T.Name

答案 2 :(得分:2)

正如雅各布所说,我的想法完全相同,只有SQL Server会采用“前10名”而不是限制。

select top 3 * 
from names
where name<'d'
union
select top 3 * 
from names
where name>='d'
order by name 

(在SQL Server 2008 R2上测试过这个)

编辑: 正确指出,先前的查询未提供所需的结果。但是,这个应该有更有效的方法来做同样的事情。

select name from names
where name in (
    select top 3 name from names where name<'e' order by name desc
    )or name in (
    select top 3 name from names where name>='e')
order by name 

答案 3 :(得分:2)

With X As (select tblTag.*, Row_Number() Over(Order By tag) R_NUMB From tblTag )
Select tag From X
Where X.R_NUMB  Between (Select X.R_NUMB From X  Where tag = 'Tutorial') - 10 
And (Select X.R_NUMB From X  Where tag = 'Tutorial') + 10

答案 4 :(得分:0)

我花了一些时间才弄明白,感谢工会的想法。不太确定为什么这是有效的,.take(n)似乎需要大量的工作,不太确定为什么会这样,这段代码似乎100%正常工作,每边需要5个:

var q = (
    from c in db.tblTags
    where
        !(from o in db.tblTagSynonyms
            select o.SynonymTagID)
        .Contains(c.ID)
        &&
        c.Name.CompareTo(AnchorTagName) < 1
    orderby c.Name descending
    select new
        {
            c.ID,
            c.Name,
            c.Priority,
            TotalResources = (from a in db.tblTagAnchors where a.TagID == c.ID select new { a.ID }).Count()
        }
    ).Take(7).ToArray().Reverse().Union(
    from c in db.tblTags
    where
        !(from o in db.tblTagSynonyms
            select o.SynonymTagID)
        .Contains(c.ID)
        &&
        c.Name.CompareTo(AnchorTagName) >= 1
    orderby c.Name ascending
    select new
    {
        c.ID,
        c.Name,
        c.Priority,
        TotalResources = (from a in db.tblTagAnchors where a.TagID == c.ID select new { a.ID }).Count()
    }
).Skip(1).Take(11).ToArray();