Query for Linking Purchase Orders with Sales Orders - sql

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.

Related

Getting repeats of output, possibly doing a join wrong?

I'm having an issue where I'm getting some incorrect values in my output. I am binding the below highlighted table column with the circled column down the bottom. The service_id on the highlighted column is what is unique, but I need to bind the booking_id to retrieve the info (if that makes sense. What I end up getting is the top table where I get repeats, or the price is wrong. I should be getting only 5 lines in the top table.
Here's my code. I suspect I might be doing the join wrong?
SELECT bad.agent as Agents,
dog.SUPPLIER as SUPPLIER,
bad.status as TheStatus,
country.analysis_master1 as Country,
ftb.booking_actual_retail as BookingActualRetail,
ftb.Booking_Actual_Cost as BookingCost,
ftb.Booking_Actual_Retail_inc as BookingRetailINC,
fts.Service_Id,
fts.Service_Actual_Retail_inc as ServiceActualCostInc,
Product.SERVICE,
Product.SL_STATUS as SLSTATUS,
cat.name as Product2,
bad.LAST_SERVICE_DATE as Servicedate,
bad.LW_DATE as LWDATE,
ftb.Entered_Date as DATEENTERED,
ftb.Booking_Pax as PEOPLE,
ftb.Booking_Children as KIDS,
bad.TRAVELDATE as TRAVELDATE,
bad.FULL_REFERENCE
from BHD bad
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
inner join FTS on FTB.Booking_Id = fts.Booking_Id
inner join DRM Country on bad.agent = country.code
inner join BSL Product on bad.BHD_ID = Product.BHD_ID
inner join SRV cat on Product.SERVICE = cat.CODE
inner join OPT dog on Product.OPT_ID = dog.OPT_ID
where bad.STATUS = 'IV' AND bad.FULL_REFERENCE = 'LTIT129488'
UPDATE:
Ok, so it looks like this join here causes the multiple outputs:
inner join FTS on FTB.Booking_Id = fts.Booking_Id
I have included the two tables, their headers, and sample data
You have somewhere put the join for the service or supplier in the wrong way.. Please check this line again.
inner join SRV cat on Product.SERVICE = cat.CODE
UPDATED SOLUTION :
As per your updated screenshots, I found the issue...
you have joined like this.
inner join FTB on bad.FULL_REFERENCE = ftb.booking_reference
In this join, your one table has single record against booking reference while another have multiple records against booking refrence. Thats why you are getting the multiple records in the output.
Remove this join and your problem will be solved. If you really want the data from this table then you can select in other way like using outer apply etc.

SQL: If there is No match on condition (row in table) return a default value and Rows which match from different tables

I have three tables: Clinic, Stock and StockLog.
I need to get all rows where Stock.stock < 5. I need to also show if an order has been placed and what amount it is; which is found in the table Stocklog.
The issue is that a user can set his stock level in the Stock table without placing an order which would go to Stocklog.
I need a query that can : return the rows in the Stock table and get the related order amounts in the Stocklog table. If no order has been placed in StockLog, then set amount to order amount to zero.
I have tried :
SELECT
Clinic.Name,
Stock.NameOfMedication, Stock.Stock,
StockLog.OrderAmount
FROM
Clinic
JOIN
Stock ON Stock.ClinicID = Clinic.ClinicID
JOIN
StockLog ON StockLog.StockID = Stock.StockID
WHERE
Stock.Stock <= 5
The issue with my query is that I lose rows which are not found in StockLog.
Any help on how to write this.
Thank you.
I am thinking the query should look like this:
SELECT c.Name, s.NameOfMedication, s.Stock,
COALESCE(sl.OrderAmount, 0) as OrderAmount
FROM Stock s LEFT JOIN
Clinic c
ON s.ClinicID = c.ClinicID LEFT JOIN
StockLog sl
ON sl.StockID = s.StockID
WHERE s.Stock <= 5 ;
You want to keep all rows in Stock (subject to the WHERE condition). So think: "make Stock the first table in the FROM and use LEFT JOIN for all the other tables."
If you want to keep all the rows that result from joining Clinic and Stock, then use a LEFT OUTER JOIN with StockLog. I don't know which SQL you're using (SQL Server, MySQL, PostgreSQL, Oracle), so I can't give you a precise example, but searching for "left outer join" in the relevant documentation should work.
See this Stack Overflow post for an explanation of the various kinds of joins.

SQL Inner Outer Join confusion

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.

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 Syntax for Complex Scenario (Deals)

i have a complex query to be written but cannot figure it out
here are my tables
Sales --one row for each sale made in the system
SaleProducts --one row for each line in the invoice (similar to OrderDetails in NW)
Deals --a list of possible deals/offers that a sale may be entitled to
DealProducts --a list of quantities of products that must be purchased in order to get a deal
now im trying to make a query which will tell me for each sale which deals he may get
the relevant fields are:
Sales: SaleID (PK)
SaleProducts: SaleID (FK), ProductID (FK)
Deals: DealID (PK)
DealProducts: DealID(FK), ProductID(FK), Mandatories (int) for required qty
i believe that i should be able to use some sort of cross join or outer join, but it aint working
here is one sample (of about 30 things i tried)
SELECT DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
FROM DealProducts
LEFT OUTER JOIN viwSaleProductCount
ON DealProducts.ProductID = viwSaleProductCount.ProductID
GROUP BY DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
The problem is that it doesn't show any product deals that are not fulfilled (probably because of the ProductID join). i need that also sales that don't have the requirements show up, then I can filter out any SaleID that exists in this query where AmountBought < Mandatories etc
Thank you for your help
I'm not sure how well I follow your question (where does viwSaleProductCount fit in?) but it sounds like you will want an outer join to a subquery that returns a list of deals along with their associated products. I think it would go something like this:
Select *
From Sales s Inner Join SaleProducts sp on s.SaleID = sp.SaleID
Left Join (
Select *
From Deals d Inner Join DealProducts dp on d.DealID = dp.DealId
) as sub on sp.ProductID = sub.ProductID
You may need to add logic to ensure that deals don't appear twice, and of course replace * with the specific column names you'd need in all cases.
edit: if you don't actually need any information from the sale or deal tables, something like this could be used:
Select sp.SaleID, sp.ProductID, sp.ProductCount, dp.DealID, dp.Mandatories
From SaleProducts sp
Left Join DealProducts as dp on sp.ProductID = dp.ProductID
If you need to do grouping/aggregation on this result you will need to be careful to ensure that deals aren't counted multiple times for a given sale (Count Distinct may be appropriate, depending on your grouping). Because it is a Left Join, you don't need to worry about excluding sales that don't have a match in DealProducts.