简体   繁体   中英

Oracle left outer join, only want the null values

I'm working on a problem with two tables. Charge and ChargeHistory. I want to display a selection of columns from both tables where either the matching row in ChargeHistory has a different value and/or date from Charge or if there is no matching entry in ChargeHistory at all.

I'm using a left outer join declared using the ansi standard and while it does show the rows correctly where there is a difference, it isn't showing the null entries.

I've read that there can sometimes be issues if you are using the WHERE clause as well as the ON clause. However when I try and put all the conditons in the ON clause the query takes too long > 15 minutes (so long I have just cancelled the runs).

To make things worse both tables use a three part compound key.

Does anyone have any ideas as to why the null values are being left out?

    SELECT values...
    FROM bcharge charge
    LEFT OUTER JOIN chgHist history
    ON charge.key1 = history.key1 AND charge.key2 = history.key2 AND charge.key3 = history.key3 AND charge.chargeType = history.chargeType
    WHERE charge.chargeType = '2'
      AND (charge.value <> history.value OR charge.date <> history.date)
    ORDER BY key1, key2, key

You probably want to explicitly select the null values:

 SELECT values...
    FROM bcharge charge
    LEFT OUTER JOIN chgHist history
    ON charge.key1 = history.key1 AND charge.key2 = history.key2 AND charge.key3 = history.key3 AND charge.chargeType = history.chargeType
    WHERE charge.chargeType = '2'
      AND ((charge.value <> history.value or history.value is null) OR (charge.date <> history.date or history.date is null))
    ORDER BY key1, key2, key

You can explicitly look for a match in the where . I would recommend looking at one of the keys used for the join :

SELECT . . . 
FROM bcharge charge LEFT OUTER JOIN
     chgHist history
     ON charge.key1 = history.key1 AND charge.key2 = history.key2 AND
        charge.key3 = history.key3 AND charge.chargeType = history.chargeType
WHERE charge.chargeType = '2' AND
      (charge.value <> history.value OR charge.date <> history.date OR history.key1 is null)
ORDER BY key1, key2, key;

The expressions charge.value <> history.value change the left outer join to an inner join because NULL results will be filtered out.

Have a look at this site, it will be very helpful for you, visual illustration of all the join statements with code samples

blog.codinghorror.com

Quoted of the relevant info in the above link:

SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name

Sample output:

id  name       id    name
--  ----       --    ----
1   Pirate     2     Pirate
2   Monkey     null  null
3   Ninja      4     Ninja
4   Spaghetti  null  null

Left outer join

produces a complete set of records from Table A, with the matching records (where available) in Table B. If there is no match, the right side will contain null

A WHERE clause filters the data returned by a join. Therefore when your inner table has null data for a particular column, the corresponding rows get filtered out based on your specified condition. That is why you should move that logic to the ON clause instead.

For the performance issues, you could consider adding indexes on the columns used for joining and filtering.

For any field from an outer joined table used in the where clause you must also permit an IS NULL option for that same field, otherwise you negate the effect of the outer join and the result is the same as if you had used an inner join.

SELECT
      *
FROM bcharge charge
      LEFT OUTER JOIN chgHist history
                  ON charge.key1 = history.key1
                        AND charge.key2 = history.key2
                        AND charge.key3 = history.key3
                        AND charge.chargeType = history.chargeType
WHERE charge.chargeType = '2'
      AND (
            (charge.value <> history.value OR history.value IS NULL)
           OR 
            (charge.date <> history.date OR history.date IS NULL)
          )
ORDER BY
      key1, key2, key3

Edit: Appears that this is the same query structure used by Rene above, so treat this one as in support of that please.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM