Suppress ENTIRE customer if they contain 1 shipment within a range - sql

Hopefully this makes sense. First post here.
I am trying to suppress all instances of a parent while my parameters affect only the child. I run into a problem where I would like to see all customers that had a shipment outside of a date range and ONLY the customers with shipments outside of that range.
With my current formula below, I will return customers with shipments outside of that date range, but it is possible they have a shipment inside it as well.
Ex.
{customer.arcustname} ={?Customer}
AND
{jobshipment.ccdate} <> {?DateRange}
DateRange = 7/1/2014 to 7/31/2014
CUST1's last shipment was on 6/25/2014, this record returns true
CUST2 has a shipment on 7/25/2014, this record returns false
CUST2 also a shipment on 6/25/2014, this record returns true and is displayed on my report. -not wanted
I would like my report to display only CUST1, since CUST2 had a shipment inside of that range, but my report is showing CUST1 and CUST2 because it is only filtering the {jobshipment.ccdate} and not the entire {customer.arcustname}.
Any help would be appreciated. Thanks!
EDIT: In my details all I have is {customer.arcustname}. All I want my report to display is a list of customers (by salesperson prompt) who have not ordered in a designated time period. All answers I've seen are only showing the shipments not in the range, where I just want to see the customers who have not had a shipment in the date range. If they had a shipment, I want the {customer.arcustname} omitted from my report.
HERE is the raw SQL:
SELECT customer."armasterid",customer."arcustname",
salesperson."arsalesname",jobshipment."ccdate"
FROM ( ( "public".customer customer LEFT OUTER JOIN "public".salesperson
salesperson ON customer.arsalesid=salesperson.arsalesid ) LEFT
OUTER JOIN "public".job job ON customer.armasterid=job.armasterid )
LEFT OUTER JOIN "public".jobshipment jobshipment ON
job.ccmasterid=jobshipment.ccmasterid
WHERE ((#NUMBER CONSTANT# = customer."arsalesid")) AND ((NOT (
(customer."araccountstatus" = 'I') )))
ORDER BY customer."arcustname"

Below solution works assuming you have a customer group and placed dates in detail as you haven't mentioned report structure.
Create a formula #count to count the occurences of dates that are not in range.
if {jobshipment.ccdate} <> {?DateRange}
then 0
else 1
2.Now create a summary field (named {#countSummary}) where we take the sum of #count. Place that in the group footer
3.Write the below supress condition in supress part of group header (Customer group), details and group footer (Customer group).
EvaluateAfter({#count});
if ({#countSummary}) <> 0
then true
else false

Related

SQL - join three tables based on (different) latest dates in two of them

Using Oracle SQL Developer, I have three tables with some common data that I need to join.
Appreciate any help on this!
Please refer to https://i.stack.imgur.com/f37Jh.png for the input and desired output (table formatting doesn't work on all tables).
These tables are made up in order to anonymize them, and in reality contain other data with millions of entries, but you could think of them as representing:
Product = Main product categories in a grocery store.
Subproduct = Subcategory products to the above. Each time the table is updated, the main product category may loses or get some new suproducts assigned to it. E.g. you can see that from May to June the Pulled pork entered while the Fishsoup was thrown out.
Issues = Status of the products, for example an apple is bad if it has brown spots on it..
What I need to find is: for each P_NAME, find the latest updated set of subproducts (SP_ID and SP_NAME), and append that information with the latest updated issue status (STATUS_FLAG).
Please note that each main product category gets its set of subproducts updated at individual occasions i.e. 1234 and 5678 might be "latest updated" on different dates.
I have tried multiple queries but failed each time. I am using combos of SELECT, LEFT OUTER JOIN, JOIN, MAX and GROUP BY.
Latest attempt, which gives me the combo of the first two tables, but missing the third:
SELECT
PRODUCT.P_NAME,
SUBPRODUCT.SP_PRODUCT_ID, SUBPRODUCT.SP_NAME, SUBPRODUCT.SP_ID, SUPPRODUCT.SP_VALUE_DATE
FROM SUBPRODUCT
LEFT OUTER JOIN PRODUCT ON PRODUCT.P_ID = SUBPRODUCT.SP_PRODUCT_ID
JOIN(SELECT SP_PRODUCT_ID, MAX(SP_VALUE_DATE) AS latestdate FROM SUBPRODUCT GROUP BY SP_PRODUCT_ID) sub ON
sub.SP_PRODUCT_ID = SUBPRODUCT.SP_PRODUCT_ID AND sub.latestDate = SUBPRODUCT.SP_VALUE_DATE;
Trying to find a row with a max value is a common SQL pattern - you can do it with a join, like your example, but it's usually more clear to use a subquery or a window function.
Correlated subquery example
select
PRODUCT.P_NAME,
SUBPRODUCT.SP_PRODUCT_ID, SUBPRODUCT.SP_NAME, SUBPRODUCT.SP_ID, SUPPRODUCT.SP_VALUE_DATE,
ISSUES.STATUS_FLAG, ISSUES.STATUS_LAST_UPDATED
from PRODUCT
join SUBPRODUCT
on PRODUCT.P_ID = SUBPRODUCT.SP_PRODUCT_ID
and SUBPRODUCT.SP_VALUE_DATE = (select max(S2.SP_VALUE_DATE) as latestDate
from SUBPRODUCT S2
where S2.SP_PRODUCT_ID = SUBPRODUCT.SP_PRODUCT_ID)
join ISSUES
on ISSUES.ISSUE_ID = SUBPRODUCT.SP_ID
and ISSUES.STATUS_LAST_UPDATED = (select max(I2.STATUS_LAST_UPDATED) as latestDate
from ISSUES I2
where I2.ISSUE_ID = ISSUES.ISSUE_ID)
Window function / inline view example
select
PRODUCT.P_NAME,
S.SP_PRODUCT_ID, S.SP_NAME, S.SP_ID, S.SP_VALUE_DATE,
I.STATUS_FLAG, I.STATUS_LAST_UPDATED
from PRODUCT
join (select SUBPRODUCT.*,
max(SP_VALUE_DATE) over (partition by SP_PRODUCT_ID) as latestDate
from SUBPRODUCT) S
on PRODUCT.P_ID = S.SP_PRODUCT_ID
and S.SP_VALUE_DATE = S.latestDate
join (select ISSUES.*,
max(STATUS_LAST_UPDATED) over (partition by ISSUE_ID) as latestDate
from ISSUES) I
on I.ISSUE_ID = S.SP_ID
and I.STATUS_LAST_UPDATED = I.latestDate
This often performs a bit better, but window functions can be tricky to understand.

Calculate differences between two columns of two different tables

I want to calculate the difference between purchase order amount and purchase invoice amount. But I am not able to fetch the purchase invoice amount i.e. "pi.grand_total" and hence also not able to fetch the difference of "(pi.grand_total - po.grand_total)" . Please help.Below is my query.
PO = Purchase Order
PI = Purchase Invoice
SELECT DISTINCT
po.name AS "PO #:Link/Purchase Order:120",
po.supplier AS "Supplier:Link/Supplier:120",
po.Company AS "Company:Data:120",
po.currency AS "Currency:Link/Currency:120",
po.base_grand_total AS "Grand Total:Currency:120",
po.status AS "Status:Data:120",
po.per_received AS "Per Received:Data:120",
CEILING(po.per_billed) AS "Per Billed:Data:120",
po.delivery_date AS "Delivery Date:Date:120",
pi.grand_total AS "Final PI Total:120",
(pi.grand_total - po.grand_total) AS "Amount Difference:120"
FROM
"tabPurchase Order" as po
LEFT JOIN "tabPurchase Invoice" as pi ON po.name = pi.parent
WHERE
po.per_received = 100
AND
CEILING(po.per_billed) < 100
ORDER BY po.delivery_date ASC
You are using LEFT JOIN. This means when your second table has no data which matches with your first table you will receive no data from second table but nonetheless your first table will return all of its data.
You probably should check your join condition. If you wanted to join these two tables the way you want then use NVL Function for pi.grand_total column. Because it is on the left join it could have a NULL value thus NULL minus po.grand_total will give you NULL. NVL function turns NULL values into intended values like NVL(pi.grand_total,0)
A good example how joins work

How to count the number of instances within a table (Countifs)

Thank you so much for looking!
Here is a link to the tables.
Normally this table would have a Field in Check Call name that is "Pickup - Actual" signalling that this has been picked up. However in certain circumstances the CheckCallName will bypass the pickup and move to delivered status. In cases like this I want to pull the query to treat the "Delivered" status in the same manner that Pickup Actual was being used.
So where kpo.loadtracking does not have Pickup - Actual in the Check Call Name field for any one order, I want to pull the date (KeypointStatusDate) the status changed to 'Delivered'.
I figured this would be something like "where the status count of Pickup-Actual is greater than 0 then pull the earliest status update date for pickup actual.
However when the count is = 0, I'd want it to pull the date relevant to the Delivered CheckCallName.
Table 1 should Pull 10/5 -
Table 2 should Pull 10/2
My current code is below:
SELECT DISTINCT
Load.LoadNumber
,CustomerName
,OrderStatus
,PickedUpOn
,CheckCallName
,Min(LoadTracking.KeypointStatusDate) AS Earliest_Check_Call
,CustomerRate
,CarrierCost
,Miles
FROM kpo.load
INNER JOIN kpo.LoadExtension ON LOAD.LoadId = LoadExtension.LoadId
INNER JOIN kpo.Customer ON customer.CustomerId = LOAD.CustomerID
INNER JOIN kpo.LoadTracking ON LoadTracking.LoadId = LOAD.LoadId
WHERE
DATEDIFF(MONTH, GETDATE(), LoadTracking.KeypointStatusDate) = - 2
AND OrderStatus <> 'VOID'
AND CheckCallName = 'Pickup - Actual'
--- WE NEED TO THEN LOOK AT EACH LOAD
--- AND IF THERE IS NO PICKUP-ACTUAL THEN IT PULLS IN THE DELIVERED DATE.
--- THERE ARE SOME ORDERS THAT GO STRAIGHT TO DELIVERED STATUS. (453653)
GROUP BY
Load.LoadNumber
,OrderStatus
,CustomerName
,CheckCallName
,PickedUpOn
,CustomerRate
,CarrierCost
,Miles
ORDER BY
Earliest_Check_Call

Access 2013 SQL, three tables, two using sum wrong results

Can someone please help me with this issue? I've scoured the Internet looking at dozens of examples, but i just can't find a solution that works.
I am using Access 2013. The problem is that I am trying to make a query that will highlight all part numbers from a supplier that either has customer back orders and/or overdue deliveries.
I am using three tables:
tbl_Inventory_Master which I require the part number, on hand stock value, and the supplier code.
For any back orders I need to join the tbl_Customer_Back_Order table as I need the count of back order lines and the sum of the back order quantity.
If the supplier has a late delivery, then I need to add the tbl_On_Order table showing the count of overdue deliveries and the sum of the overdue quantities.
The query is retrieving the data but the returned quantities are double what they should be.
SELECT
I.Inventory_Part_Num, I.Description, I.On_Hand_Stock,
COUNT (B.Part_Number) AS Back_Order_Count, SUM(B.Back_Order_Qty) as BO_Qty,
COUNT(O.Part_Number) AS Late_Deliveries_Count, SUM(O.Order_Qty) AS Late_Qty
FROM (tbl_Inventory_Master AS I
LEFT OUTER JOIN tbl_Customer_Back_Order AS B
ON I.Inventory_Part_Num = B.Part_Number)
LEFT OUTER tbl_On_Order AS O
ON I.Inventory_Part_Num = O.Part_Number
WHERE
I.Customer_Code = '274' AND
O.Due_Date < [ENTER TODAYS DATE IN FORMAT DD/MM/YYYY]
GROUP BY I.Inventory_Part_Num, I.Description, I.On_Hand_Stock
For example, for the part number 2022940 I should have 10 back order lines and an overdue quantity of 43. Instead, the query is returning 20 back order lines and an overdue quantity sum of 86.
From the on order table I have three orders totaling 144 pieces, instead the query is returning 960.
Can someone please advise, as this is driving me crazy?
You are joining along unrelated dimensions, so you need to aggregate before joining:
SELECT I.Inventory_Part_Num, I.Description, I.On_Hand_Stock,
B.Back_Order_Count, B.BO_Qty,
O.Late_Deliveries_Count, O.Late_Qty
FROM (tbl_Inventory_Master AS I LEFT OUTER JOIN
(SELECT B.Part_Number, COUNT(*) as Back_Order_Count,
SUM(B.Back_Order_Qty) as BO_Qty
FROM tbl_Customer_Back_Order AS B
GROUP BY B.Part_Number
) as B
ON I.Inventory_Part_Num = B.Part_Number
) LEFT JOIN
(SELECT O.Part_Number, COUNT(O.Part_Number) AS Late_Deliveries_Count,
SUM(O.Order_Qty) AS Late_Qty
FROM tbl_On_Order AS O
WHERE O.Due_Date < [ENTER TODAYS DATE IN FORMAT DD/MM/YYYY]
GROUP BY O.Part_Number
) as O
ON I.Inventory_Part_Num = O.Part_Number
WHERE I.Customer_Code = '274';
Notice the outer aggregation is no longer needed.

How to return 1st record from group by

Trying to return only the 1st supplier code and have all other fields unaffected.
`Select
Container.Part_Key,
Part.Part_No,
Part.Name,
Part.Revision,
Container.Quantity,
Container.Container_Status,
OP.Operation_No,
Opp.Operation_Code,
Part.Part_Status,
Supplier.Supplier_Code
From Part_v_Container as Container
Join Part_v_Part as Part
ON Part.Part_Key = Container.Part_Key
Join Part_v_Part_Operation as Op
On Op.Part_Operation_Key = Container.Part_Operation_Key
Join Part_v_Operation as OPP
On OPP.Operation_Key = OP.Operation_Key
Join part_v_approved_supplier as Approved
On Approved.part_key = container.part_key
Join common_v_Supplier as Supplier
On Supplier.supplier_no = Approved.Supplier_No
Where Container.Active = '1'
group by container.part_key`
There will be duplicate part numbers, revisions, etc. Not worried about that. I just want the part no to list only one approved supplier to the far right, even though for any given part, there are multiple approved suppliers listed in the database.
Furthermore, the order the database lists the approved suppliers does not matter.
Thanks!
Add a sub query in your select list
( select top 1 supplier.supplier_code
From supplier
Where Supplier.supplier_no = Approved.Supplier_No order by Supplier.supplier_no) as supplier code
This can be the last field in the select list
You could add An appropriate order by.
This would work in SQL Server