tags:

views:

176

answers:

5

Let say that I have 2 tables with the same structure : STOCK and NEW_STOCK. These tables have a primary key composed of (ID_DATE, ID_SELLER, ID_INVOICE, ID_DOC).

Now, I need to get for every (ID_DATE, ID_SELLER, ID_INVOICE, ID_DOC), the value of the amount (field AMOUNT) regarding this requirement:

If a record is present in NEW_STOCK, I get the AMOUNT from NEW_STOCK, otherwise, I get the AMOUNT from STOCK table.

Note that ID_DATE and ID_SELLER are the inputs given to the query, i.e. a query that considers only STOCK table will look like :

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 |
+---------+-----------+------------+--------+--------+

Then, I must get the following results:

+---------+-----------+------------+--------+--------+
| 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: I'm working on Oracle 10.

+3  A: 

Use outer join and NVL(arg1, arg2) function. It returns first argument if it is not NULL, otherwise it returns second argument. Example:

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';

You can use LEFT OUTER JOIN syntax instead of (+) if you find it more readable. I'm using Oracle since v7 and I like (+) more.

Here is LEFT OUTER JOIN syntax:

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';
zendar
Thanks, it was what I tried, except that I added "n.ID_DATE=1 and n.ID_SELLER = 'SELL1'" in the where part, which not worked for records only present in STOCK table.By the way, how do you write a "left outer join" when there are more than one field used for the join?
romaintaz
No, it's ok for the "left outer join". Thanks.
romaintaz
A: 
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';
Victor Vostrikov
A: 

You need a UNION.

Visage
A: 

The following should work for it:

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';

Exclude the matched rows from a LEFT JOIN and UNION that set with the results from the NEW_STOCK table.

Jonathan Kehayias
A: 
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'
najmeddine