DISTINCT в ПРИСОЕДИНЯЙСЯ

У меня вопрос по Oracle SQL.

Чтобы упростить мою проблему, скажем, у меня есть две таблицы:

TAB1:                TAB2:
Usr  Fruit            Fruit  Calories
1    A                A      100
1    A                B      200
1    A                C      150
1    C                D      400
1    C                E      50
2    A
2    A
2    E

Важно, чтобы в TAB1 были двойные записи. Теперь хочу узнать калории на usr 1. Но объединив обе таблицы

SELECT TAB2.calories from TAB1
JOIN TAB2 ON TAB1.Fruit = TAB2.Fruit
WHERE TAB1.Usr = 1;

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

Спасибо!


person panuffel    schedule 08.10.2015    source источник
comment
Если пользователь ест/использует фрукт три раза, разве он/она не получает в три раза больше калорий?   -  person Gordon Linoff    schedule 08.10.2015
comment
Вы имеете в виду, что если я съем 800 г шоколада в 4 зельях, будет учитываться только 200 г?   -  person A ツ    schedule 08.10.2015
comment
Почему важно иметь повторяющиеся записи в TAB1? Если в usr 1 есть фрукт А 3 раза, то калорийность 300. А точный результат тоже важен?   -  person Paul Maxwell    schedule 08.10.2015


Ответы (4)


Я большой поклонник полусоединения. Для таких маленьких таблиц это не будет иметь значения, но для больших таблиц это может иметь большое значение:

select
  tab2.calories
from tab2
where exists (
  select null
  from tab1
  where tab1.fruit = tab2.fruit and tab1.usr = 1
)
person Hambone    schedule 08.10.2015
comment
Это отличное решение, я должен сказать! +1 :) - person Jorge Campos; 08.10.2015

Попробуйте так:

SELECT TAB2.calories 
 from (select distinct usr, fruit from TAB1) as T1
        JOIN TAB2 ON T1.Fruit = TAB2.Fruit
WHERE T1.Usr = 1;
person Jorge Campos    schedule 08.10.2015

Вы должны сделать отдельный перед соединением

select sum(tab2.calories) as TotalCalories
from (select distinct tab1.*
      from tabl
     ) t1 join
     tab2
     on t1.fruit = tab2.fruit
where t1.user = 1;

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

person Gordon Linoff    schedule 08.10.2015

поскольку вы ничего не выбираете на вкладке A и, возможно, у вас есть какой-то полезный индекс, я бы выбрал IN вместо соединения

SELECT TAB2.calories 
FROM TAB2
WHERE TAB2.Fruit IN ( SELECT TAB1.Fruit FROM TAB1 WHERE TAB1.Usr = 1)

я почти уверен, что это займет больше времени, но вы все равно можете попробовать:

SELECT TAB2.calories 
FROM TAB2
WHERE TAB2.Fruit IN ( SELECT DISTINCT TAB1.Fruit FROM TAB1 WHERE TAB1.Usr = 1)
person A ツ    schedule 08.10.2015
comment
Мне сказали (но я не знаю из первых рук), что первый способ предпочтительнее, так как CBO оптимизирует его в полусоединение, если это необходимо, тем самым устраняя группировку/сортировку, связанную с отдельным. Что касается результатов, они определенно дадут одинаковые результаты. - person Hambone; 08.10.2015
comment
@Hambone, да, мой комментарий был не таким ясным. изменил его. - person A ツ; 08.10.2015
comment
Может быть, это оплошность, но мне любопытно, почему за этот ответ проголосовали против. Решение будет работать, было правильно объяснено и эффективно. Если кто-то может объяснить, я хотел бы знать, для моего собственного образования, что не так с ответом. - person Hambone; 09.10.2015