Skip to content
Advertisement

How to write an optional condition in SQL Join

I have two tables. One is the Transaction table and the other is the PriceBook table.

-Transaction Table-
|ItemID |   Assortment |UnitID|
|-------|--------------|------|
|A01    |           1  |ea    |
|A02    |           1  |kg    |
|A03    |           2  |pc    |

-PriceBook Table-
|ItemID |   Assortment  |UnitID |Price|
|-------|---------------|-------|-----|
|A01    |       1       |  ea   |1.5  |
|A02    |       1       |  pc   |2.5  |
|A03    |       2       |  kg   |5    |
|A03    |       2       |  pc   |1    |

I want to select the price from the PriceBook table, matching with the ItemID, Assortment and UnitID with Transaction table. But the UnitID match is optional, so if there is no match with UnitID, I want to have the matching result with only ItemID and Assortment.

-Result Table-
|ItemID|    UnitID| Price|
|------|----------|------|
|A01   |    ea    |1.5   |
|A02   |    pc    |2.5   |
|A03   |    pc    |1     |

I am using LEFT OUTER Join, but when I am matching ItemID and Assortment, I am getting two rows for Item A03 (I require only one), and if I am matching with ItemID, Assortment and UnitID, I am getting null for Item A02. Following is my query.

select DISTINCT Tx.ItemID, Pb.UnitID, Pb.Price
    from Transaction Tx with (nolock)
    LEFT OUTER JOIN PriceBook Pb With (NOLOCK)      
    ON Tx.ItemID = Pb.ItemID
    AND Tx.Assortment = Pb.Assortment
    AND Tx.UnitID = Pb.UnitID -- (This conditional should be optional)

How do I get my desired result?

Advertisement

Answer

You may use outer apply for rows that didn’t match by more columns:

with t(ItemID, Assortment, UnitID) as (
  select 'A01', 1, 'ea' union all
  select 'A02', 1, 'kg' union all
  select 'A03', 2, 'pc'
)
, pr(ItemID, Assortment, UnitID, Price) as (
  select 'A01', 1, 'ea', 1.5 union all
  select 'A02', 1, 'pc', 2.5 union all
  select 'A03', 2, 'kg', 5   union all
  select 'A03', 2, 'pc', 1
)
select
  t.itemid
  , t.assortment
  , coalesce(pr.unitid, pr2.unitid, t.unitid) as unitid
  , coalesce(pr.price, pr2.price) as price
from t
  left join pr
    on t.itemid = pr.itemid
      and t.assortment = pr.assortment
      and t.unitid = pr.unitid
  outer apply (
    select top 1 pr2.unitid, pr2.price
    from pr as pr2
    where t.itemid = pr2.itemid
      and t.assortment = pr2.assortment
      /*When no matches by unitid*/
      and pr.itemid is null
  ) as pr2
itemid | assortment | unitid | price
:----- | ---------: | :----- | ----:
A01    |          1 | ea     |   1.5
A02    |          1 | pc     |   2.5
A03    |          2 | pc     |   1.0

db<>fiddle here

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement