The Power of LEFT OUTER JOIN

The Power of LEFT OUTER JOIN

In the last letter, I made a big mistake. I made a jump in technique that I should not have made. I didn't explain when to use a LEFT JOIN. 

LEFT OUTER JOINS or LEFT JOINS for short are one of those very confusing things for many beginners. So much so I left it out of SAP Business One Essential training. However, it is a very important join that you really should know. 

So let's take a look at this valuable part of SQL. I want to start with a bit of a side quest first. Let's look at this query which gives information about a customer's default bank and the Bank's country. 

SELECT 
   T0.CardCode,
   T0.CardName,
   T0.BankCountry AS "Bank Country",
   T0.DflBankKey AS "Default Bank" 

FROM OCRD T0

WHERE 
   T0.CardType = 'C'

Run this, and you'll see some blank spaces. 

Table


There are two reasons those rows have blanks: SAP Business One's terrible formatting for a zero value or a null. NULL does not mean zero. NULL means there is no data. The spot is indeed empty. I'll replace BankCountr and DflBankKey with two CASE expressions to check for NULL. The operator IS NULL will do this. 

CASE WHEN T0.BankCountr IS NULL 

   THEN 'NULL' ELSE T0.BankCountr 

END as "Bank Country", 

CASE WHEN t0.dflBankKey IS NULL 

  THEN 'NULL' ELSE Format(t0.dflBankKey,'#') END 

AS "Default Bank"

Rerun the query. Now we can see the NULLs.  

Table

I want the name of the country and the bank on my report, not the id as I have now. I'd assume I'd add two joins to my report.

FROM OCRD T0

INNER JOIN OCRY t2 ON t0.BankCountr = t2.code

INNER JOIN ODSC t1 ON t0.dflBankKey = t1.AbsEntry

When I Run this, I have fewer rows:

Table

INNER JOIN finds rows in two tables with a field in that row the same on both tables. Inner joins require an equal value in both tables. If a row in OCRD.Bankcountry has the same values as a row from OCRY. Code, SQL adds a row with data from both to the result table.

No alt text provided for this image


What happened at Row 6 and 7 on OCRD? Those are NULL, and nothing matches on OCRY. That excludes ROws 6 and 7 in the result table.

If I want all the customers and be able to Join where I have relevant information, I need a join that will show all rows found and add the information to those that match. That's what left joins do. WE call them left because you were to write the join on the same line.

FROM OCRD T0 LEFT JOIN ODSC t1 ON t0.dflBankKey = t1.AbsEntry

OCRD is to the left of ODSC. You'll get all of the selected records from OCRD and the extra information necessary from ODSC. 

Try it by changing INNER to LEFT. 

LEFT JOIN ODSC t1 ON t0.dflBankKey = t1.AbsEntry

LEFT JOIN OCRY t2 ON t0.BANKCountr = t2.code

Once again, we have 14 rows.

Table

I'll add two more fields to the select clause to make this work

SELECT 
   T0.Cardcode,
   T0.CardName,
   CASE WHEN T0.BankCountr IS NULL 
      THEN 'NULL' ELSE T0.BankCountr 
   END as "Bank Country", 
   T2.Name,
   CASE WHEN t0.dflBankKey IS NULL 
      THEN 'NULL' ELSE Format(t0.dflBankKey,'#') 
   END AS "Default Bank", 
   T1.BankName

FROM OCRD T0
   LEFT JOIN ODSC t1 ON t0.dflBankKey = t1.AbsEntry
   LEFT JOIN OCRY t2 ON t0.BANKCountr = t2.code

WHERE 
   T0.CardType = 'C'

Running again, I get this

Table

One more example, going back to a previous newsletter. Consider this Query for a sales order and its rows, with a pointer to Invoices:

SELECT  
   T0.DocNum,
   T0.DocDate,
   T1.LineNum + 1,
   T1.ItemCode,
   T1.TargetType,
   CASE  WHEN T1.TrgetEntry IS NULL THEN  'NULL' ELSE FORMAT(T1.TrgetEntry,'0') END as "Target Entry"
FROM ORDR T0
   INNER JOIN RDR1 T1 ON t0.docentry = t1.docentry
WHERE 
   t0.docdate >= '01/01/2020'


running ti gets me many rows.

Notice the document type. I have Delivery documents (15) INvoices (13) and Open sales order which have no target (-1). If I want a report with a column with a golden arrow to invoices, I'll modify the Query to this, filtering for Invoices:

SELECT  
   T0.DocNum,
   T0.DocDate,
   T1.LineNum + 1,
   T1.ItemCode,
   T1.TargetType,
   CASE  WHEN T1.TrgetEntry IS NULL THEN  'NULL' ELSE FORMAT(T1.TrgetEntry,'0') END as "Invoice #",
   T2.DocEntry as "Invoice Link"
FROM ORDR T0
   INNER JOIN RDR1 T1 ON t0.docentry = t1.docentry
   INNER JOIN OINV T2 ON T1.TrgetEntry = T2.DocEntry AND T1.TargetType = 13
WHERE 
   t0.docdate >= '01/01/2020'

I'd get only the two Invoice rows connected to Sales order 1181. Everything else went through a delivery document or has no value yet. Here it is not just the null but a compound boolean expression that could be false.

No alt text provided for this image

Change that to a left join like this.

SELECT  
   T0.DocNum,
   T0.DocDate,
   T1.LineNum + 1,
   T1.ItemCode,
   T1.TargetType,
   CASE  WHEN T1.TrgetEntry IS NULL THEN  'NULL' ELSE FORMAT(T1.TrgetEntry,'0') END as "Invoice #",
   T2.DocEntry AS "Invoice Link"
FROM ORDR T0
   INNER JOIN RDR1 T1 ON t0.docentry = t1.docentry
   LEFT JOIN OINV T2 ON T1.TrgetEntry = T2.DocEntry AND T1.TargetType = 13
WHERE 
  t0.docdate >= '01/01/2020'


And you get

No alt text provided for this image

I can even add the Delivery link with a LEFT JOIN

SELECT  
   T0.DocNum,
   T0.DocDate,
   T1.LineNum + 1,
   T1.ItemCode,
   T1.TargetType,
   CASE  WHEN T1.TrgetEntry IS NULL THEN  'NULL' ELSE FORMAT(T1.TrgetEntry,'0') END as "Invoice #",
   T2.DocEntry AS "Invoice Link",
   T3.DocEntry AS "Delivery Doc Link"
FROM ORDR T0
   INNER JOIN RDR1 T1 ON t0.docentry = t1.docentry
   LEFT JOIN OINV T2 ON T1.TrgetEntry = T2.DocEntry AND T1.TargetType = 13
   LEFT JOIN ODLN T3 ON T1.TrgetEntry = T3.DocEntry AND T1.TargetType = 15
WHERE 
  t0.docdate >= '01/01/2020'

and get

No alt text provided for this image

Left Joins are handy when you want to see all rows of the first table, but there is no one-to-one correspondence in the second table of a join. There are plenty of examples, but these two should give you the idea.


This was a Biz Oneness PowerTip. For more on SAP Business One, Check out my courses in the LinkedIn Learning Library

Subscribe to BizOneness on LinkedIn above or find out more about all of this at BizOneness.com

要查看或添加评论,请登录

Steven Lipton的更多文章

  • Predicates and Predicate functions in HANA

    Predicates and Predicate functions in HANA

    #Bizoneness: Over the last few newsletters, we reviewed functions in HANA and their SQL equivalents. Our last in this…

  • LucaERP part 5: Building A Form

    LucaERP part 5: Building A Form

    In this series of biweekly columns, we're building an ERP from scratch, starting with the general ledger. We've learned…

  • BizOneness: Aggregate Functions in HANA

    BizOneness: Aggregate Functions in HANA

    #HANA #Bizoneness Over the last few newsletters, we've been looking at the basics of HANA. This time, I'd like to look…

  • LucaP: The Anatomy of User Interfaces for ERP

    LucaP: The Anatomy of User Interfaces for ERP

    #LucaP In the last installment of building the LucaP ERP, we discussed the part of the general journal. We have yet to…

  • Bizoneness: Common SQL and HANA types, Operators, and Functions

    Bizoneness: Common SQL and HANA types, Operators, and Functions

    Bizoneness: Common SQL and HANA types, operators, and Functions #Bizoneness #HANA Two weeks ago, I wrote the first of…

    1 条评论
  • LucaP ERP part 3: Adding General Journal Entries

    LucaP ERP part 3: Adding General Journal Entries

    #LucaP *Note:As I've gained a few followers and subscriptions in the last few weeks, I want to remind everyone that I…

  • Bizoneness: Introducing HANA

    Bizoneness: Introducing HANA

    #Bizoneness While I had planned something about the General Ledger for this newsletter, circumstances changed, so I'll…

    3 条评论
  • LucaP ERP part2: The Chart of Accounts

    LucaP ERP part2: The Chart of Accounts

    #LucaP #ERP In the ERP application, we have established credits and debits on a ledger with the five major accounts…

  • The Bizoneness Migration Guide

    The Bizoneness Migration Guide

    #Bizoneness Data migration is taking data from one source and merging it into another source. If you're very lucky, it…

  • LucaP ERP Part 1: The Basic Equation

    LucaP ERP Part 1: The Basic Equation

    #LucaP How do you start to understand the workings of an ERP system? By making one. In this biweekly column, we’ll make…

社区洞察

其他会员也浏览了