SQL для получения диапазона результатов в алфавитном порядке - PullRequest
4 голосов
/ 25 июня 2011

У меня есть таблица, tblTags, которая работает так же, как система тегов StackOverflows.

Когда я просматриваю страницу тегов, скажем, тег Tutorial Я хочу отобразить 10 тегов до и после него в алфавитном порядке.

Итак, если нам присваивается тег Tutorial с идентификатором 30, как мы можем вернуть набор записей в следующем порядке:

Tap
Tart
> Tutorial
Umbrellas
Unicorns
Xylaphones

Я думал о способах сделать это, на мой взгляд, плохо, поскольку они включают в себя извлечение ужасных объемов данных.

Я не уверен, возможно ли что-то сделать в духе (псевдо):

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

Но как вы узнаете позицию тега учебника в списке эффективным образом, не просматривая весь список, пока не найдете его?

Я использую SQL Server 2008 R2 Express с LINQ, если что-то изменится, SQL-запросы или LINQ будут отличными ответами, спасибо!

Ответы [ 5 ]

3 голосов
/ 25 июня 2011

Основываясь на предложении Джейкоба UNION, вы используете переменную таблицы, чтобы выбрать соответствующие идентификаторы TagID, а затем присоединитесь к таблице тегов, чтобы получить соответствующие записи.Это не так элегантно, как хотелось бы, но это работает.

В качестве примечания, я думаю, что подход UNION будет работать, но AFAIK SQL Server разрешает ORDER BY только на последнем SELECT и что ORDER BYприменяется ко всему набору результатов ( в этом посте также говорится то же самое).

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
3 голосов
/ 25 июня 2011

Может быть, союз будет работать. (я уверен, что у меня есть некоторые синтаксические ошибки, но вы поняли)

(редактировать: благодаря комментариям и другим ответам, особенно 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;

Однако я бы проверил производительность, чтобы увидеть, действительно ли это быстрее, чем возвращать больше строк и затем фильтровать их. У меня такое ощущение, что есть более эффективный метод.

2 голосов
/ 25 июня 2011
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
2 голосов
/ 25 июня 2011

Как предполагает Джейкоб, у меня была точно такая же идея, только «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 
0 голосов
/ 25 июня 2011

Мне потребовалось время, чтобы понять это, спасибо за идею профсоюза.Не совсем уверен, , почему это работает, .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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...