SQL Inner Outer Join confusion - sql

I'm having a little confusion with a certain example.
I am supposed to list all orders and their corresponding details.
This is what I'm doing:
SELECT *
FROM Orders
LEFT OUTER JOIN [Order Details]
ON Orders.OrderID=[Order Details].OrderID;
This gives the number of rows = 2155.
Now the problem is, the number of rows in Orders Table is 830...how can left outer join create more rows ?
By definition of left outer join, all the rows from the left table are taken and matching records from the second table are added.
I checked the number of rows in the Order Details table..that is 2155.
Why is left outer join using all rows from Order Details table?

LEFT JOIN takes all the details from the table you define on the left side of the join and match records from the right table.
If there's no match, all columns of the right table have NULL values.
If there's a match, all matching records from the right table are returned. If your relationship is 1-to-many (as in your case), it means that there may be more than one record returned from the right table for each record in the left table.

LEFT OUTER JOIN will match all records in the right table, just as an INNER JOIN will. The difference is a LEFT JOIN will preserve records from the left table with no match in the right table.
In this scenario, all records in [ORDER DETAILS] have a corresponding entry in ORDERS, which is why the total number of records matches the number of rows in ORDER DETAILS
Based on the table descriptions, this is exactly what you want. Having an ORDER DETAIL without an ORDER would be a much more serious issue.

Related

How to return no duplicates for records that have many-to-many values

I am trying to find the correct join construction to join together the relevant customer info from the Rentals table with the Accidents table. I often run into this issue where my joining fields aren't unique but not sure what else to join on. The accidents table only has about 1500 records but when I join it to pull in more customer data, I get like 35k records. I can do some joins but frequently have joins like this at work and I feel like a dummy because I am not sure how to troubleshoot...
SELECT a.*,
r.market,
r.date_of_birth,
r.is_blocked,
r.rate_type
FROM `accidents` a
LEFT JOIN `rentals` r -- I also tried an INNER JOIN
USING (customer_id) -- Other fields I tried to match on: Full Name
ORDER BY accident_dt DESC

Query for Linking Purchase Orders with Sales Orders

I'm writing a report that includes sales order info + delivery notes. What I'm trying to do is add information from the purchase orders (ex. PO # & Price) table (I believe it is OPOR). How do I link this table to one or more of the tables I already have? Please see my query below:
SELECT o0.NumAtCard AS OrderNo
,i0.DocNum
,i0.TrackNo AS TrackingNo
,i0.CardName
, o0.DocNum AS DelivDoc
FROM ODLN d0
INNER JOIN DLN1 d1 ON d0.DocEntry = d1.DocEntry
LEFT OUTER JOIN INV1 i1 ON d1.TrgetEntry = i1.DocEntry
LEFT OUTER JOIN OINV i0 ON i1.DocEntry = i0.DocEntry
INNER JOIN ORDR o0 ON d1.BaseEntry = o0.DocEntry
INNER JOIN OITM itm ON i1.ItemCode = itm.ItemCode
WHERE o0.CANCELED = 'N' AND
i0.TrackNo IS NOT NULL
GROUP BY o0.NumAtCard
|,i0.DocNum
|,i0.TrackNo
,i0.CardName
,o0.DocNum
ORDER BY o0.NumAtCard
Ok so on the back and forth, it is clear the real question is about how to go about adding the information to the query.
A SQL consists of several major pieces in order:
The column list
The table/join specification (FROM and JOIN clauses)
The where section (WHERE...)
Aggregate rules (GROUP BY/Having)
Limit and offset (LIMIT/OFFSET)
In your case you need to start by identifying the information in the database you want to add, and how it relates to what you have already. So in this case you are going to:
Add the columns as necessary to the column list (the part between SELECT and FROM)
Add the table to the join list (via a LEFT JOIN, with the join condition following ON). So if you have a so_docnum field that matches the sales order docnum field it would be something like LEFT OUTER JOIN OPOR po ON po.so_docnum = o0.docnum)
Add anything needed to the GROUP BY clause (probably the fields you are adding from the PO).
However, your first step is to map out the data so that these steps can be executed because it is clear you don't have all the information you need to add it yet.

Sql tables need help please

I'm trying to build a sql query which worked for the previous one which had 2 tables and it was pretty straight forward. This one though, has been driving me insane for 6 hours now.
The problem I have is that the results are only displayed should ALL criteria match and I don't want that. I would like the field to result back blank if it does not have an entry in the database.
I have a table and I want to display the orderrefno. At this point I want to check to see if a delivery note has been created and if so, I want to then see if an invoice has been created. Then report back to the report with the numbers of each but if they don't exist, the. It should just have the order no and the others would be both blank or just the invoice would be blank, should a delivery note been done.
I've tried building a query in crystal using inner, left join, right join, full but if an invoice does NOT exist I want it to list the delivery no and order no, but it won't.
I can do this in datasources and master sources in delphi and v studio, but would like to do a sql because the other easy is slow.
My tables are
Project
Order
Calloff
Calltodeliverylink
Delivery
Deliverytoinvoicelink
Invoice
Tables are linked as follows.
Project.id is the main point of entry.
Then
Order.projectid -- project.id
Calloff.orderid -- order.id
Callofftodeliverylink.deliveryid -- call off.id
Delivery.id -- callofftodeliverylink.deliveryid
Deliverytoinvoicelink.deliveryid -- delivery.id
Invoice.id -- deliverytoinvoicelink.invoiceid
Many many thanks
EDIT:
Added Code. Sorry for FROM section being a mess. In crystal drew the linking fields and asked it to show me the query and this is what it gave me.
SELECT
"Projects"."ID", "Orders"."IntOrderNo", "Deliveries"."DeliveryNo", "Projects"."InternalRef",
"CallOffs"."ID", "Customers"."Name", "Contacts"."Name", "Invoices"."InvoiceNo"
FROM
{oj (((((("GNManager"."dbo"."Invoices" "Invoices" LEFT OUTER JOIN "GNManager"."dbo"."DeliveryToInvoiceLink" "DeliveryToInvoiceLink" ON "Invoices"."ID"="DeliveryToInvoiceLink"."InvoiceID") LEFT OUTER JOIN "GNManager"."dbo"."Deliveries" "Deliveries" ON "DeliveryToInvoiceLink"."DeliveryID"="Deliveries"."ID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffToDeliveryLink" "CallOffToDeliveryLink" ON "Deliveries"."ID"="CallOffToDeliveryLink"."DeliveryID") LEFT OUTER JOIN "GNManager"."dbo"."CallOffs" "CallOffs" ON "CallOffToDeliveryLink"."CallOffID"="CallOffs"."ID") LEFT OUTER JOIN ("GNManager"."dbo"."Projects" "Projects" LEFT OUTER JOIN "GNManager"."dbo"."Orders" "Orders" ON "Projects"."ID"="Orders"."ProjectID") ON "CallOffs"."OrderID"="Orders"."ID") INNER JOIN "GNManager"."dbo"."Customers" "Customers" ON "Orders"."CustomerID"="Customers"."ID") INNER JOIN "GNManager"."dbo"."Contacts" "Contacts" ON "Orders"."ContactID"="Contacts"."ID"}
WHERE
"Projects"."InternalRef"='12/4169'
ORDER BY
"Projects"."InternalRef" DESC, "Orders"."IntOrderNo" DESC
The above statement does work and produces everything that I need, but only if Invoices has an entry. If invoices is blank, nothing gets displayed.
The order of the tables in your join statement is the issue. Invoices being the first table is the one that will drive the rest of the results.
If you need all orders associated with your projects, no matter if there are any invoices, here's what I would do. Please note that you need valid values in Projects, Orders, Customers and Contacts, but everything else could be null.
select
Projects.ID
,Orders.IntOrderNo
,Deliveries.DeliveryNo
,Projects.InternalRef
,CallOffs.ID
,Customers.Name
,Contacts.Name
,Invoices.InvoiceNo
from
Projects
join Orders on Orders.ProjectID = Projects.ID
join Customers on Orders.CustomerID = Customers.ID
join Contacts on Orders.ContactID = Contacts.ID
left join Callofs on Callofs.OrderID = Orders.ID
left join CallOffToDeliveryLink on CallOffToDeliveryLink.CallOffID = Callofs.ID
left join Deliveries on CallOffToDeliveryLink.DeliveryID = Deliveries.ID
left join DeliveryToInvoiceLink on DeliveryToInvoiceLink.DeliveryID = Deliveries.ID
left join Invoices on DeliveryToInvoiceLink.InvoiceID = Invoices.ID
where
Projects.InternalRef = '12/4169'
order by
Projects.InternalRef desc
,Orders.IntOrderNo desc

SQL like clause is not returning any results

I have following query, but it doesn't return any results for where clauses, even when there is row with that kind of name what is queried. If I remove where clause, then all records in Company table which have OfficeLocation table are returned. What is wrong in my query?
SELECT c.*
FROM [MyDb].[dbo].[Company] AS c
INNER JOIN [MyDb].[dbo].[CompanyOfficeLocation] AS col ON c.Id = col.CompanyId
INNER JOIN [MyDb].[dbo].[OfficeLocation] AS ol ON ol.Id = col.OfficeLocationId
WHERE ol.Name like '%Actual Name In This Table%';
Table structure :
Company
Id
etc ...
CompanyOfficeLocation
CompanyId
OfficeLocationId
OfficeLocation
Id
etc ...
Two things for a record to show up given your query:
The OfficeLocation you specified (given the ol.Name value) must have an Id value that is used by a record in the CompanyOfficeLocation table in its OfficeLocationId.
The CompanyOfficeLocation record that you got in #1 must have a CompanyId that exists in the Company table.
If any of those two criteria are not met, then no records will show up in your query result. The INNER JOIN is essentially an 'AND' clause. If a record could not be related to at least one INNER JOINed table, then that record will not show up at all.
If you want a record to show up despite not having any related records in the joined tables, you may want to consider using OUTER JOINs. A RIGHT JOIN in your case to be exact.
I do not find any mistake however I'd suggest you switch the columns after ON when joining to maintain standards.
Instead of - INNER JOIN [MyDb].[dbo].[OfficeLocation] AS ol ON ol.Id = col.OfficeLocationId
Do - INNER JOIN [MyDb].[dbo].[OfficeLocation] AS ol ON col.OfficeLocationId = ol.Id

Left Join with all rows from the left not matching the Where Clause

I have the following problem:
I have an account table and an entries for account table.
account_id
account_name
entry_id
account_idfk
entry_date
entry_amount
Now I want to query all entries for all accounts in a given period. Eg. I want all Entries for all accounts from October 2008 - October 2009. If there are no entries for this account at all, or there are only entries in other timeperiods for this account, I want the account returned as well.
My current query works, if there are no entries at all, or there are entries for this timeperiod for this account. However - it leaves out the Accounts which have only entries for other timeperiods.
SELECT * FROM Account a
LEFT JOIN Entries e ON e.account_idfk = a.account_id
WHERE e.entry_date BETWEEN '2009-08-13' AND '2009-08-13'
OR e.entry_date IS NULL
I know that the problem is in the where clause - I eliminate all Accounts for which only entries in other time periods exist.
But I have no idea how to restate the query to get the desired result...
Thanks,
Martin
Move that condition to the join:
SELECT
*
FROM
Account a
LEFT JOIN Entries e ON
e.account_idfk = a.account_id
AND e.entry_date BETWEEN '2009-08-13' AND '2009-08-13'
What you see here is the difference between a join and a where condition. The join will only join rows that meet that condition. However, with a left join, you still return all the rows in the left table. With the where clause, you're filtering rows after the join. In this case, you only want to join entries where the date is 8/13/09 (or 13/8/09, for those across the pond), but you want to return all accounts. Therefore, the condition needs to go into the join clause, and not the where.
This often gets confused with any outer join, because with an inner join, the result is the same no matter if the condition is in the join or where clause. However, this does not mean that they are equivalent, as demonstrated by you today!