T-SQL - справка по операции MAX над многими ко многим - PullRequest
2 голосов
/ 21 декабря 2010

Это тесно связано с предыдущим вопросом, который я задавал.

У меня есть отношение «многие ко многим» между Публикация и Местоположение .

Таблица соединений называется PostLocations и не имеет ничего, кроме FK. (LocationId, PostId)

Я пытаюсь вернуть верхний пост для каждого местоположения .

Это мой запрос (который был дан в ответе на мой предыдущий вопрос):

SELECT pl.LocationId, p.postid, p.UniqueUri, p.Content, MAX(s.BaseScore) as topscore
from dbo.PostLocations pl
inner join dbo.posts p on pl.PostId = p.PostId
inner join dbo.reviews r on p.postid = r.postid
inner join dbo.scores s on r.scoreid = s.scoreid
group by pl.locationid, p.postid, p.UniqueUri, p.Content

Но проблема в том, что PostLocations может иметь такие записи:

LocationId   PostId
1            213213
2            498324
1            230943

Итак, мой приведенный выше запрос возвращает LocationId 1 дважды , потому что он содержит две записи в таблице соединений. Мне нужна только 1 запись для каждого местоположения - верхний пост для locationid.

Я тоже пробовал это:

SELECT l.LocationId, p.postid, p.UniqueUri, p.Content, MAX(s.BaseScore) as topscore
from dbo.PostLocations pl
inner join dbo.Locations l on pl.LocationId = l.LocationId
inner join dbo.posts p on pl.PostId = p.PostId
inner join dbo.reviews r on p.postid = r.postid
inner join dbo.scores s on r.scoreid = s.scoreid
group by l.locationid, p.postid, p.UniqueUri, p.Content

Тот же результат - вот что возвращается:

LocationId   PostId   UniqueUri   Content   TopScore
1            213213   some-post   pew pew   2.00
2            498324   anot-post   blah bl   4.50
1            230943   sadjsa-as   asijd a   3.5

Вот что должно вернуться:

LocationId   PostId   UniqueUri   Content   TopScore
1            230943   sadjsa-as   asijd a   3.5
2            498324   anot-post   blah bl   4.50

Поскольку LocationId 1 имеет 2 сообщения, а PostId 230943 имеет наивысший балл, то есть тот, который был возвращен.

Есть идеи о том, что мне не хватает?

Ответы [ 2 ]

3 голосов
/ 21 декабря 2010

Если вы используете SQL Server 2005 или более позднюю версию, вы можете сделать что-то вроде:

With RankedLocations As
    (
    Select PL.LocationId
        , S.BaseScore
        , P.PostID
        , P.UniqueUri
        , P.Content
        , Row_Number() Over( Partition By PL.LocationId Order By S.BaseScore Desc ) As ScoreRank
    From dbo.PostLocations As PL
        Join dbo.Posts As P
            On P.PostId = PL.PostId
        Join dbo.Reviews As R
            On R.PostId = P.PostId
        Join dbo.Scores As S
            On S.ScoreId = R.ScoreId
    )
Select LocationId, BaseScore, PostID, UniqueUri, Content
From RankedLocations
Where ScoreRank = 1
1 голос
/ 21 декабря 2010

Поскольку вы группируете по postID, который уникален, каждое отдельное сообщение попадает в свою собственную группу из одного.

Я не уверен, есть ли лучший способ сделать это, однако то, что я сделалв прошлом мы выполняем эти строки

Select l.LocationId, p.postid, p.UniqueUri, p.Content, s.basescore as topscore
from
    dbo.Locations l inner join
    (select 
        pl.locationid, max(s.BaseScore) as topscore
    from
        dbo.postlocations pl 
        inner join dbo.posts p on pl.PostId = p.PostId
        inner join dbo.reviews r on p.postid = r.postid
        inner join dbo.scores s on r.scoreid = s.scoreid
    group by
        pl.locationid) as topPost on l.locationid = topPost.locationid
    inner join dbo.postlocations pl on pl.locationid = l.locationid
    inner join dbo.posts p on pl.PostId = p.PostId
    inner join dbo.reviews r on p.postid = r.postid
    inner join dbo.scores s on r.scoreid = s.scoreid and s.basescore = toppost.topscore

Мы создаем подзапрос, чтобы найти максимальный балл для данного местоположения, затем выполняем наши объединения, как и раньше, и в последнем соединении проверяем, что базовая оценка - это верхний бал, который мы нашли ранее..

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

Мне интересно посмотреть, есть ли другие решения этой проблемы, так как с количеством дополнительных объединений это довольно дорогостоящее решение для вычислительной техники.проблема.

Редактировать - в ответ на ваш комментарий, поскольку postid является первичным ключом, мы можем положиться на него, чтобы быть самым большим в последнем сообщении.

Select l.LocationId, p.postid, p.UniqueUri, p.Content, bar.basescore as topscore
from
    dbo.Locations l inner join
    (select 
        l.LocationId, max(p.postid) as postid ,max(s.basescore) as basescore
    from
        (select 
            pl.locationid, max(s.BaseScore) as topscore
        from
            dbo.postlocations pl 
            inner join dbo.posts p on pl.PostId = p.PostId
            inner join dbo.reviews r on p.postid = r.postid
            inner join dbo.scores s on r.scoreid = s.scoreid

        group by
            pl.locationid) as topPost on l.locationid = topPost.locationid
        inner join dbo.postlocations pl on pl.locationid = l.locationid
        inner join dbo.posts p on pl.PostId = p.PostId
        inner join dbo.reviews r on p.postid = r.postid
        inner join dbo.scores s on r.scoreid = s.scoreid and s.basescore = toppost.topscore
    group by l.locationid) as bar on l.locationid = bar.locationid
    inner join posts p on bar.postid = p.postid
...