SQL-соединение без потери строк

У меня есть 2 таблицы с одинаковой схемой идентификатора пользователя, категории, количества. Мне нужен запрос для суммирования количества каждой пары userID/category. Иногда пара будет существовать в одной таблице, а не в другой. У меня возникли проблемы с объединением без потери строк, где пара идентификатор пользователя/категория существует только в 1 таблице. Вот что я пытаюсь (без успеха):

select a.user, a.category, count=a.count+b.count
from #temp1 a join #temp2 b
on a.user = b.user and a.category = b.category

Пример:

Вход:

user    category    count
id1     catB        3
id2     catG        9
id3     catW        17

user    category    count
id1     catB        1
id2     catM        5
id3     catW        13

Желаемый результат:

user    category    count
id1     catB        4
id2     catG        9
id2     catM        5
id3     catW        30

Обновление: «счетчик» не является фактическим именем столбца. Я просто использовал его ради этого примера и забыл, что это зарезервированное слово.


person JCB    schedule 10.07.2013    source источник
comment
Почему ID2 не суммируется? он есть в обеих таблицах.   -  person S Nash    schedule 10.07.2013
comment
@SNash, категории разные. Вы можете перечитать требования к суммированию.   -  person Michael Goldshteyn    schedule 10.07.2013


Ответы (2)


Тебе следует:

  1. Используйте полное внешнее соединение, чтобы не удалять строки, присутствующие в одной таблице, а не в другой.
  2. Объединение подсчитывается перед добавлением, потому что 0 + NULL = NULL

Кроме того, поскольку COUNT является зарезервированным словом, я бы рекомендовал избегать его.

Итак, используя все эти рекомендации, ваш запрос становится:

SELECT COALESCE(a.user, b.user) AS user, 
       COALESCE(a.category, b.category) AS category, 
       COALESCE(a.[count],0) + COALESCE(b.[count],0) AS [count]
FROM #temp1 AS a 
FULL OUTER JOIN #temp2 AS b
             ON a.user = b.user AND 
                a.category = b.category
person Michael Goldshteyn    schedule 10.07.2013
comment
Идеальный! Я не знал о COALESCE, это именно то, что мне было нужно. Я также считаю, что AS [count] является посторонним, поскольку у вас есть [count] = в начале этой строки. - person JCB; 10.07.2013
comment
@JCB, я хотел удалить часть [count] =, что я и сделал в последнем редактировании. Спасибо что подметил это. - person Michael Goldshteyn; 10.07.2013

Один из способов приблизиться к этому — использовать полное внешнее соединение:

select coalesce(a.user, b.user) as user,
       coalesce(a.category, b.category) as category,
       coalesce(a.count, 0) + coalesce(b.count, 0) as "count"
from #temp1 a full outer join
     #temp2 b
     on a.user = b.user and
         a.category = b.category;

При использовании full outer join вы должны быть осторожны, потому что ключевые поля могут быть NULL, когда есть совпадение только в одной таблице. В результате select имеет тенденцию иметь много coalesce() (или подобных конструкций).

Другой способ — использовать запрос union all с агрегацией:

select "user", category, SUM(count) as "count"
from ((select "user", category, "count"
       from #temp1
      ) union all
      (select "user", category, "count"
       from #temp2
      )
     ) t
group by "user", category
person Gordon Linoff    schedule 10.07.2013