We have a system that keeps track of packages in an MS SQL database. Each package contains 1-3 boxes. All packages have at least one box, "BoxSide". Additionally, they might also have a "BoxOuter" next to it, and that box optionally might have "BoxInner" inside of it. Each box has contents that we keep the data on.
So there are five separate tables total: One with the package information, one for each box (Side, Outer and Inner) and one table that has the data about the contents of each. They relate to each other as shown in the following diagram:
What I want to do is run a query that puts all of that data together in a report with a single record for each package and fields for the contents of each box, leaving non-applicable fields blank. Something like:
Package.*, BoxSide.Data1, Boxside.Data2, BoxOuter.Data1, BoxOuter.Data2, BoxInner.Data1, BoxInner.Data2
To reiterate:
I've tried various joins to link this data back together, but I seem to always end up with missing packages (if they didn't have a certain box type) or duplicate records of the same package multiple times for different box types. Too many failed attempts to list here.
Can somebody with some SQL-fu please help me with a query that would do this?
You need to use LEFT JOIN
to get every record in Package
regardless if it has corresponding values in the other tables:
SELECT P.ID, p.Time, P.Type, P.Name, P.location,
s.ID, sc.ID, sc.Data1, sc.Data2,sc.Data3
o.ID, oc.ID, oc.Data1, oc.Data2, oc.Data3
i.ID, ic.ID, ic.Data1, ic.Data2, ic.Data3
FROM Package p
LEFT JOIN BoxSide s ON p.ID = s.PackageID
LEFT JOIN Contents sc ON s.ID = sc.ParentID
LEFT JOIN BoxOuter o ON p.ID = o.PackageID
LEFT JOIN Contents oc ON o.ID = oc.ParentID
LEFT JOIN BoxInner i ON o.ID = i.BoxOuterID
LEFT JOIN Contents ic ON i.ID = ic.ParentID
Note that you also have to LEFT JOIN
the Contents
table multiple times, each time with a different alias to link it to each parent table.