2013-09-19 2 views
2

У меня есть таблица хобби, чей фрагмент выглядит следующим образом:значение SQL суммы из тех же таблиц

Name Activity Hours 

John Hiking  .5 
Sam  Cycling  .5 
Sam  Swimming 1 
Sam  Hiking  .5 
John Running  1 
Sam  Sailing  1 

Для каждого человека X в (X, Y), я хотел бы найти сумму часов где X и Y не имеют общего. Например, если John = X и Sam = Y, то это даст 1, так как Running - единственное действие, которое у Джона у Сэма нет.

Мой код выглядит следующим образом:

select a.Name, b.Name, sum(a.Hours) 
from Hobby a, Hobby b 
where a.Name <> b.Name and a.Activity <> b.Activity 
group by a.Name, b.Name; 

Однако, это дало мне неправильный ответ. Что не так с моим кодом?

ответ

4

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

Итак, следующий запрос работает, получив список всех пар имен. Это упорядоченный список, поэтому данная пара имен появляется только один раз. Затем он соединяется с таблицей Hobby дважды, используя left outer join для получения совпадений. Ключ, однако, заключается в том, что когда нет совпадения, строка с Activity на нем по-прежнему присутствует, но с NULL значением.

Предложение where находит все Activity s, у которых есть NULL в любой таблице. Это те, которые не совпадают. Тогда это просто вопрос просто суммирование часов:

select names.Name1, names.Name2, sum(coalesce(h1.hours, h2.hours)) 
from (select distinct h1.Name as name1, h2.Name as name2 
     from Hobby h1 cross join Hobby h2 
     where h1.Name < h2.Name 
    ) names left outer join 
    Hobby h1 
    on names.name1 = h1.name left outer join 
    Hobby h2 
    on names.name2 = h2.name and 
     h1.Activity = h2.Activity 
where h1.Activity is null or h2.Activity is null 
group by names.Name1, names.Name2; 
+0

Это не симметричными 'часов (X, Y) = часы (Y, X) 'в общем случае, измените' '' 'на'! = ' – Laurence

0

ваш от пункта читает

FROM Hobby a, Hobby b 

Поставив запятую в ЕКЕ означает «CROSS JOIN», что означает каждую строку в первом таблица сопоставляется с каждой строкой во второй таблице. Учитывая ваше предложение, я бы подумал, что это дает довольно большие цифры.

ваш запрос должен быть немного другое:

select sum(hours) 
from hobby 
where name = 'John' 
    and activity not in (
    select activity 
    from hobby 
    where name = 'Sam' 
) 
0

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

with 
    cte_unique_names as (
    select distinct name 
    from hobby) 
select 
    h.name participates, 
    n.name does_not_participate, 
    sum(hours) hours 
from 
    hobby h 
cross join 
    cte_unique_names n 
where 
    n.name != h.name and 
    not exists (
    select null 
    from hobby h2 
    where h2.name  = n.name and 
      h2.activity = h.activity) 
group by 
    h.name, 
    n.name 
0

Подумайте о базовых результатах перед группой. Рассмотрим только строки, где таблица a равна John, Hiking. В вашем запросе вы бы

John Hiking 0.5 John Hiking  0.5 
John Hiking 0.5 Sam  Cycling  0.5 
John Hiking 0.5 Sam  Swimming 1 
John Hiking 0.5 Sam  Hiking  0.5 
John Hiking 0.5 John Running  1 
John Hiking 0.5 Sam  Sailing  1 

С вашей ИНЕКЕ, вы удалите строки Джона и пешеходные строки из таблицы б оставляя:

John Hiking 0.5 Sam  Cycling  0.5 
John Hiking 0.5 Sam  Swimming 1 
John Hiking 0.5 Sam  Sailing  1 

Таким образом, вы будете подсчетом этих часов три раза в наборе John, Sam.

Вот способ, чтобы настроить его, в то же время только с помощью каждой таблицы раз:

Select 
    a.Name, 
    b.Name Name2, 
    Sum(a.Hours)/count(distinct b.activity) 
     - Sum(case when a.Activity = b.Activity then a.Hours else 0 end) as Hours 
From 
    Hobby a, 
    Hobby b 
Where 
    a.Name != b.Name 
Group By 
    a.Name, 
    b.Name 

Example Fiddle

+0

. Я думаю, что если вы присоединитесь к отдельному списку имен вместо полной таблицы хобби, вам не понадобится деление по количеству действий. –

+0

Вы правы, но я пытался как можно меньше адаптировать запрос OP. – Laurence

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