2012-05-07 2 views
0

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

Я могу выполнять инструкции SQL, чтобы получить список имен групп и количество пользователей в этой группе (запрос 1), а также список имен групп и количество сообщений (запрос 2), но я хотел бы, чтобы быть в том же запросе.

Query 1

select count(pg.personID) as GroupSize, g.GroupName 
from Group g inner join PersonGroup pg g.GroupID = pg.GroupID 
where LastViewed between @startDate and @enddate and 
    g.Type = 0 
group by g.GroupID, g.GroupName 
order by GroupSize 

Query 2

select count(gp.PostID) as TotalPosts, g.GroupName 
from Group g inner join GroupPost gp on g.GroupID = gp.GroupID 
    inner join Post p on gp.PostID = p.PostID 
where g.Type = 0 and 
    gp.Created between @startDate and @enddate 
group by g.GroupID, g.GroupName 
order by TotalPosts 

** Примечание: Человек может опубликовать то же самое "сообщение" для нескольких групп

я считаю, из этих данных я мог бы построить гистограмма (# групп с 10-20 пользователями, 21-30 пользователей и т. д.) и включает среднее количество сообщений для групп в этих разных ячейках.

ответ

1

простое решение было бы использовать эти запросы как подзапросы, и объединить их:

SELECT 
    grps.GroupName, 
    grps.GroupSize, 
    psts.TotalPosts 
FROM (
    select count(pg.personID) as GroupSize, g.GroupName, g.GroupID 
    from Group g inner join PersonGroup pg g.GroupID = pg.GroupID 
    where LastViewed between @startDate and @enddate and 
     g.Type = 0 
    group by g.GroupID, g.GroupName 
    order by GroupSize) grps 
JOIN (
    select count(gp.PostID) as TotalPosts, g.GroupName, g.groupID 
    from Group g inner join GroupPost gp on g.GroupID = gp.GroupID 
     inner join Post p on gp.PostID = p.PostID 
    where g.Type = 0 and 
     gp.Created between @startDate and @enddate 
    group by g.GroupID, g.GroupName 
    order by TotalPosts) psts 
ON psts.GroupID = grps.GroupID 
0

решение Павла предполагает, что два набора групп (по должности и пользователей) одно и то же. Это может быть неверно, поэтому необходимо либо полное внешнее соединение, либо объединение.

Я предпочитаю следующее:

with groups as 
(
    select * 
    from Group g 
    where g.Type = 0 
    and g.LastViewed between @startDate and @enddate 
) 
select GroupId, GroupName, SUM(GroupSize) as GroupSize, SUM(TotalPosts) as TotalPosts) 
from 
(
    (select groups.GroupId, groups.GroupName, 1 as GroupSize, 0 as TotalPosts 
    from groups 
    join PersonGroup pg 
    on pg.GroupId = groups.groupId 
    ) 
    union all 
    (select groups.GroupId, groups.GroupName, 0 as GroupSize, 1 as TotalPosts 
    from groups 
    join GroupPost gp 
     on groups.GroupId = gp.GroupId 
    join Post p 
     on gp.PostId = p.PostId 
    ) 
) 
group by GroupId, GroupName 

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

+0

Запросы OP используют несколько разные фильтрации: 'gp.Created между @startDate и @ enddate' во втором запросе по сравнению с первым запросом' LastViewed между @startDate и @ enddate'. Также не установлено, что 'LastViewed' является столбцом' Group'. (Да, OP, вероятно, был бы более ясен с этой стороны, но мы не должны слишком много думать, если мы.) –

+0

Кроме этого, я согласен с вашим подходом, на самом деле. Возможно, я использовал бы реальные идентификаторы из объединенных таблиц и NULL для замены, и, следовательно, я бы вычислил COUNT вместо SUM, но в основном это было бы так же, как и ваше предложение. –

Смежные вопросы