Как объединить результаты из двух таблиц в Oracle 10

Допустим, у меня есть 2 таблицы с одинаковой структурой: STOCKи NEW_STOCK. Эти таблицы имеют первичный ключ, состоящий из (ID_DATE, ID_SELLER, ID_INVOICE, ID_DOC).

Теперь мне нужно получить для каждого (ID_DATE, ID_SELLER, ID_INVOICE, ID_DOC) значение суммы (поле AMOUNT) относительно этого требования:

Если запись присутствует NEW_STOCK, я получаю СУММУ NEW_STOCK, иначе я получаю СУММУ из STOCKтаблицы.

Обратите внимание, что ID_DATE и ID_SELLER являются входными данными для запроса, то есть запрос, который рассматривает только STOCKтаблицу, будет выглядеть следующим образом:

select AMOUNT, ID_DATE, ID_SELLER, ID_INVOICE
    from STOCK
    where ID_DATE = 1
      and ID_SELLER = 'SELL1';

STOCK :

+---------+-----------+------------+--------+--------+
| ID_DATE | ID_SELLER | ID_INVOICE | ID_DOC | AMOUNT |
+---------+-----------+------------+--------+--------+
|       1 |     SELL1 |        IN1 |   DOC1 |    100 |
|       1 |     SELL1 |        IN2 |   DOC2 |     50 |
|       1 |     SELL1 |        IN3 |   DOC3 |     42 |
+---------+-----------+------------+--------+--------+

NEW_STOCK:

+---------+-----------+------------+--------+--------+
| ID_DATE | ID_SELLER | ID_INVOICE | ID_DOC | AMOUNT |
+---------+-----------+------------+--------+--------+
|       1 |     SELL1 |        IN2 |   DOC2 |     12 |
+---------+-----------+------------+--------+--------+

Затем я должен получить следующие результаты:

+---------+-----------+------------+--------+--------+
| ID_DATE | ID_SELLER | ID_INVOICE | ID_DOC | AMOUNT |
+---------+-----------+------------+--------+--------+
|       1 |     SELL1 |        IN1 |   DOC1 |    100 |
|       1 |     SELL2 |        IN2 |   DOC2 |     12 |
|       1 |     SELL3 |        IN3 |   DOC3 |     42 |
+---------+-----------+------------+--------+--------+

PS: я работаю над Oracle 10.

13.10.2009 12:50:15
4 ОТВЕТА
РЕШЕНИЕ

Используйте внешнее соединение и функцию NVL (arg1, arg2). Он возвращает первый аргумент, если он не равен NULL, в противном случае он возвращает второй аргумент. Пример:

select s.AMOUNT, s.ID_DATE, s.ID_SELLER, s.ID_INVOICE,
   NVL(n.AMOUNT, s.AMOUNT) amount       
from STOCK s, NEW_STOCK n
where s.ID_DATE = n.ID_DATE(+) 
  and s.ID_SELLER = n.ID_SELLER(+)
  and s.ID_INVOICE = n.ID_INVOICE(+)
  and s.ID_DOC = n.ID_DOC(+)
  and s.ID_DATE = 1
  and s.ID_SELLER = 'SELL1';

Вы можете использовать LEFT OUTER JOINсинтаксис вместо, (+)если вы найдете его более читабельным. Я использую Oracle начиная с v7, и мне нравится (+)больше.

Вот LEFT OUTER JOINсинтаксис:

select s.AMOUNT, s.ID_DATE, s.ID_SELLER, s.ID_INVOICE,
   NVL(n.AMOUNT, s.AMOUNT) amount       
from  STOCK s left outer join NEW_STOCK n 
      on s.ID_DATE = n.ID_DATE
         and s.ID_SELLER = n.ID_SELLER
         and s.ID_INVOICE = n.ID_INVOICE
         and s.ID_DOC = n.ID_DOC
where s.ID_DATE = 1
  and s.ID_SELLER = 'SELL1';
3
13.10.2009 13:13:52
Спасибо, это было то, что я попробовал, за исключением того, что я добавил "n.ID_DATE = 1 и n.ID_SELLER = 'SELL1'" в части where, которая не работала для записей, присутствующих только в таблице STOCK. Кстати, как вы пишете «левое внешнее соединение», когда для объединения используется более одного поля?
Romain Linsolas 13.10.2009 13:09:31
Нет, это нормально для "левого внешнего соединения". Спасибо.
Romain Linsolas 13.10.2009 13:11:10
SELECT * FROM (
    SELECT * FROM new_stock
    UNION ALL
    SELECT * FROM stock
    WHERE (ID_DATE,ID_SELLER,ID_INVOICE,ID_DOC) NOT IN 
     (SELECT ID_DATE,ID_SELLER,ID_INVOICE,ID_DOC FROM new_stock)
)
WHERE ID_DATE = 1 
   AND ID_SELLER = 'SELL1';
0
13.10.2009 12:59:48

Следующее должно работать для этого:

SELECT s.AMOUNT, s.ID_DATE, s.ID_SELLER, s.ID_INVOICE    
FROM STOCK s
LEFT JOIN NEW_STOCK ns 
   ON s.ID_DATE = ns.ID_DATE 
   AND s.ID_SELLER = ns.ID_SELLER 
   AND s.ID_INVOICE = ns.ID_INVOICE
WHERE s.ID_DATE = 1      
  AND s.ID_SELLER = 'SELL1'
  AND ns.ID_DATE IS NULL
UNION
SELECT AMOUNT, ID_DATE, ID_SELLER, ID_INVOICE    
FROM NEW_STOCK    
WHERE ID_DATE = 1
  AND ID_SELLER = 'SELL1';

Исключить совпадающие строки из LEFT JOIN и UNION, которые установлены с результатами из таблицы NEW_STOCK.

0
13.10.2009 13:00:23
SELECT COALESCE(NS.AMOUNT, S.AMOUNT) AMOUNT, 
       S.ID_DATE, 
       S.ID_SELLER, 
       S.ID_INVOICE
  FROM STOCK S 
  LEFT JOIN NEW_STOCK NS ON S.ID_DATE = NS.ID_DATE
                        AND S.ID_SELLER = NS.ID_SELLER
                        AND S.ID_INVOICE = NS.ID_INVOICE
                        AND S.ID_DOC = NS.ID_DOC 
 WHERE S.ID_DATE = 1
   AND S.ID_SELLER = 'SELL1'
0
13.10.2009 13:03:43