How to get value higher or lower from outer reference (SQL) - sql

I have two tables, one with data for materials and what costing lot size they currently have. Then I have another table containing purchase scales for the same materials. I then need to fetch the purchase scale that are the same or smaller than my costing lot size from the original table and the purchase scale just above it. This works for me as a correlated sub query within my select sentence:
Select
mbew.Matnr as Material
,mbew.bwkey as Plant
,mbew.STPRS/mbew.peinh as Standard_price
,mbew.verpr/mbew.peinh as Average_price
,keko.Costing_lot_size
,Keko.Costing_date
,(select max(info.scale_quantity_konm) as Scale_quantity from dwh.inforecords info where mbew.matnr = info.material and keko.costing_lot_size >= info.scale_quantity_konm) as Current_Costing_Lot_Size
,(select min(info.scale_quantity_konm) as Scale_quantity from dwh.inforecords info where mbew.matnr = info.material and keko.costing_lot_size < info.scale_quantity_konm) as Next_Costing_Lot_Size
,inforecords_larger_price.amount_dkk_konm as Next_Costing_Lot_Size_Price
from
mbew mbew
left join
(Select kekoa.Material, kekoa.Plant, kekoa.Costing_date, kekoa.Costing_lot_size
from sap.keko Kekoa
inner join
(select Material, Plant, max(costing_date) as Lates_costing_date from sap.keko
group by material, plant) kekob
on kekoa.costing_date = kekob.Lates_costing_date
and kekoa.Material = kekob.material
and kekoa.plant = kekob.plant) as keko
on
mbew.matnr = keko.material
and mbew.bwkey = keko.Plant
But it is highly inefficient. Can it somehow be made smarter/optimized?
Thanks in advance

Related

SQL Server - Need to SUM values in across multiple returned records

In the following query I am trying to get TotalQty to SUM across both the locations for item 6112040, but so far I have been unable to make this happen. I do need to keep both lines for 6112040 separate in order to capture the different location.
This query feeds into a Jasper ireport using something called Java.Groovy. Despite this, none of the PDFs printed yet have been either stylish or stained brown. Perhaps someone could address that issue as well, but this SUM issue takes priority
I know Gordon Linoff will get on in about an hour so maybe he can help.
DECLARE #receipt INT
SET #receipt = 20
SELECT
ent.WarehouseSku AS WarehouseSku,
ent.PalletId AS [ReceivedPallet],
ISNULL(inv.LocationName,'') AS [ActualLoc],
SUM(ISNULL(inv.Qty,0)) AS [LocationQty],
SUM(ISNULL(inv.Qty,0)) AS [TotalQty],
MAX(CAST(ent.ReceiptLineNumber AS INT)) AS [LineNumber],
MAX(ent.WarehouseLotReference) AS [WarehouseLot],
LEFT(SUM(ent.WeightExpected),7) AS [GrossWeight],
LEFT(SUM(inv.[Weight]),7) AS [NetWeight]
FROM WarehouseReceiptDetail AS det
INNER JOIN WarehouseReceiptDetailEntry AS ent
ON det.ReceiptNumber = ent.ReceiptNumber
AND det.FacilityName = ent.FacilityName
AND det.WarehouseName = ent.WarehouseName
AND det.ReceiptLineNumber = ent.ReceiptLineNumber
LEFT OUTER JOIN Inventory AS inv
ON inv.WarehouseName = det.WarehouseName
AND inv.FacilityName = det.FacilityName
AND inv.WarehouseSku = det.WarehouseSku
AND inv.CustomerLotReference = ent.CustomerLotReference
AND inv.LotReferenceOne = det.ReceiptNumber
AND ISNULL(ent.CaseId,'') = ISNULL(inv.CaseId,'')
WHERE
det.WarehouseName = $Warehouse
AND det.FacilityName = $Facility
AND det.ReceiptNumber = #receipt
GROUP BY
ent.PalletId
, ent.WarehouseSku
, inv.LocationName
, inv.Qty
, inv.LotReferenceOne
ORDER BY ent.WarehouseSku
The lines I need partially coalesced are 4 and 5 in the above return.
Create a second dataset with a subquery and join to that subquery - you can extrapolate from the following to apply to your situation:
First the Subquery:
SELECT
WarehouseSku,
SUM(Qty)
FROM
Inventory
GROUP BY
WarehouseSku
Now apply to your query - insert into the FROM clause:
...
LEFT JOIN (
SELECT
WarehouseSKU,
SUM(Qty)
FROM
Inventory
GROUP BY
WarehouseSKU
) AS TotalQty
ON Warehouse.WarehouseSku = TotalQty.WarehouseSku
Without seeing the actual schema DDL it is hard to know the exact cardinality, but I think this will point you in the right direction.

T-SQL JOIN Table On Self Based on Closest Date

Thank you in advance for reading!
The question I'm trying to answer is: "How much do parts really cost to make?" We manufacture by machining raw metal billets down to metal parts. Final parts are sold to a customer and scrap metal from the process is sold to the scrap yard.
For business/ERP configuration reasons our scrap vendor is listed as a customer and we ship him 'parts' like our other customers. These dummy parts are simply for each of the metal alloys we work with, so there is one dummy scrap part for each alloy we use. The scrap shipments are made whenever we fill our scrap bins so there's no defined time interval.
I'm trying to connect the ship date of a real part to a real customer to the closest scrap ship date of the same alloy. Then I can grab the scrap value per pound we were paid and include it in our revenue for the parts we make. If I can ask for the world it would be helpful to know how to grab the scrap shipment immediately before or immediately after the shipment of a real part - I'm sure management will change their minds several times debating if they want to use the 'before' or 'after' number.
I've tried other solutions and can't get them to work. I'm crying uncle, I simply can't get it to work....the web SQL interface our ERP uses claims it's T-SQL... thank you for reading this far!
What I'd like the output to look like is:
Customer Part Price Alloy Weight_Lost Scrap_Value Ship_Date
ABC Widget1 99.99 C182 63 2.45 10-01-2016
Here's the simplest I can boil the tables down to:
SELECT
tbl_Regular_Sales.Customer
tbl_Regular_Sales.Part
tbl_Regular_Sales.Price
tbl_Regular_Sales.Alloy
tbl_Regular_Sales.Weight_Lost
tbl_Scrap_Sales.Price AS 'Scrap_Value'
tbl_Regular_Sales.Ship_Date
FROM
(SELECT P.Part
,P.Alloy
,P.Price
,S.Ship_Date
,S.Customer
FROM Part AS P
JOIN S AS S
ON S.Part_Key = P.Part_Key
WHERE Shipper.Customer = 'Scrap_Yard'
) AS tbl_Scrap_Sales
JOIN
(SELECT P.Part
,P.Weight_Lost
,P.Alloy
,P.Price
,S.Ship_Date
,S.Customer
FROM Part AS P
JOIN S AS S
ON S.Part_Key = P.Part_Key
WHERE Shipper.Customer <> 'Scrap_Yard' ) AS tbl_Regular_Sales
ON
tbl_Regular_Sales.Alloy = tbl_Scrap_Sales.Alloy
AND <Some kind of date JOIN to get the closest scrap shipment value>
Something like this may do the trick:
WITH cteScrapSales AS (
SELECT
P.Alloy
,P.Price
,S.Ship_Date
FROM Part AS P
JOIN Shipper AS S ON S.Part_Key = P.Part_Key
WHERE S.Customer = 'Scrap_Yard'
), cteRegularSales AS (
SELECT
P.Part_Key
,P.Part
,P.Weight_Lost
,P.Alloy
,P.Price
,S.Ship_Date
,S.Customer
FROM Part AS P
JOIN Shipper AS S ON S.Part_Key = P.Part_Key
WHERE S.Customer <> 'Scrap_Yard'
)
SELECT
C.Customer
,C.Part
,C.Price
,C.Alloy
,C.Weight_Lost
,C.Scrap_Value
,C.Ship_Date
FROM (
SELECT R.*, S.Price AS Scrap_Value, ROW_NUMBER() OVER (PARTITION BY R.Part_Key ORDER BY DATEDIFF(SECOND, R.Ship_Date, S.Ship_Date)) ix
FROM cteRegularSales R
JOIN cteScrapSales S ON S.Allow = R.Allow AND S.Ship_Date > R.Ship_Date
) AS C
WHERE C.ix = 1;

Left Join Performance with addtional Left Table Filter

Hi I am wondering if putting additional conditions in left joing will improve performance.
Example Code is below.
I only need to know the Price data for certain offers but will need need all offers data.
Just wondering if it's worth putting the additional join conditions to speed up performance?
SELECT
*
FROM
OFFERS
LEFT JOIN PRICE ON (
PRICE.PH_SUBS_LINK_SK = ACTSUBS.PH_SUBS_LINK_SK and
PRICE.PRICE_END_DT= '09-09-9999' and
OFFERS.PERCENT_VALUE >0 and
OFFERS.VALUE_OR_PERCENT = 'PERCENT' and
OFFERS.PRODUCT_OFFER_TYPE = 'RC' and
OFFERS.OFFER_STATUS_CODE in ('ACT','PTM')
)
I suggest to change above code for this:
SELECT
*
FROM
OFFERS
LEFT JOIN PRICE ON
PRICE.PH_SUBS_LINK_SK = ACTSUBS.PH_SUBS_LINK_SK
WHERE PRICE.PRICE_END_DT= '09-09-9999' and
OFFERS.PERCENT_VALUE >0 and
OFFERS.VALUE_OR_PERCENT = 'PERCENT' and
OFFERS.PRODUCT_OFFER_TYPE = 'RC' and
OFFERS.OFFER_STATUS_CODE in ('ACT','PTM')
To improve performance create an index for the fields used on the where statement.

Joining multiple tables in Access and limiting to Top 1 result

I have three tables that need to be joined in order to get monthly inventory data in return.
Table 1: TargetInventory
Table 2: TargetValue
Table 3: TargetWeight
[TargetInventory] does not change after being added the first time.
[TargetValue] is just a small table that includes prices of various types of metal.
[TargetWeight] is updated monthly as part of our inventory process. We INSERT new data, we never UPDATE old data.
Below is the relationship between these tables. (Sorry, I don't have the reputation points to post an image. Brand new here, so hopefully this makes sense.)
(* = UniqueKey)
--TargetValue-- --TargetInventory-- --TargetWeight--
*MaterialID <===| *TargetID <=====| *ID
Material |===> MaterialID |===> TargetID
PricePerOunce Length RecordDate
Density Width Weight
Thickness
DateInInventory
The TargetWeight table contains multiple records for TargetID (since a new one is added every month at inventory). That's good for me to track historical usage, but for the current inventory value, I only need the most recent TargetWeight.Weight to be returned.
I don't know how to do a CROSS APPLY from within another INNER JOIN, so I'm at a loss for how to do this (without switching to mySQL and just doing a LIMIT 1...)
I think it needs to look something like what's below, but I'm not sure how to finish the query.
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(TargetValue
INNER JOIN TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
CROSS APPLY (
SELECT TOP 1 *
FROM .....
)
The following query works for me in Access 2010. It uses an INNER JOIN on a subquery to take the place of the CROSS APPLY (which Access SQL doesn't support). It assumes that there will be no more than one [TargetWeight] record for a given (TargetID, RecordDate):
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
LatestWeight.ID,
LatestWeight.TargetID AS TargetWeight_TargetID,
LatestWeight.RecordDate,
LatestWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
(
SELECT tw.*
FROM
TargetWeight AS tw
INNER JOIN
(
SELECT TargetID, MAX(RecordDate) AS LatestDate
FROM TargetWeight
GROUP BY TargetID
) AS latest
ON latest.TargetID=tw.TargetID
AND latest.LatestDate=tw.RecordDate
) AS LatestWeight
ON LatestWeight.TargetID = TargetInventory.TargetID
Alternative approach specifically for Access 2010 or later
If the above query bogs down with a large number of rows in [TargetWeight] then another possible solution for Access 2010+ would be to add a Yes/No field named [Current] to the [TargetWeight] table and use the following After Insert data macro to ensure that only the latest record for each [TargetID] is flagged as [Current]:
Once that is done, the query would simply be
SELECT
TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density,
TargetWeight.ID,
TargetWeight.TargetID AS TargetWeight_TargetID,
TargetWeight.RecordDate,
TargetWeight.Weight
FROM
(
TargetValue
INNER JOIN
TargetInventory
ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
)
INNER JOIN
TargetWeight
ON TargetInventory.TargetID = TargetWeight.TargetID
WHERE TargetWeight.Current = True;
To maximize performance, the [TargetWeight].[TargetID] and [TargetWeight].[Current] fields should be indexed.
SELECT TargetInventory.TargetID AS TargetInventory_TargetID,
TargetInventory.MaterialID AS TargetInventory_MaterialID,
TargetInventory.Length,
TargetInventory.Width,
TargetInventory.Thickness,
TargetValue.MaterialID AS TargetValue_MaterialID,
TargetValue.PricePerOunce,
TargetValue.Density, Weight.ID,
Weight.TargetID AS TargetWeight_TargetID,
Weight.RecordDate,
Weight.Weight
FROM TargetInventory
INNER JOIN TargetValue ON TargetValue.[MaterialID] = TargetInventory.[MaterialID]
CROSS APPLY (
SELECT TOP 1 *
FROM TargetWeight
WHERE TargetID = TargetInventory.TargetID
ORDER BY RecordDate DESC
) AS Weight

SQL AVG in subselect

I want to get rates from a product (productId) that is in a specific category (fk_rate_category) and the overall average rates from all products in the category.
To be more specific: I need the data for a chart. One line in the chart represents the rate of a product(y-axis = rate ; x-axis = date_added) and the other line shows the average rates of all products.
I had the following approach:
SELECT id, productId, rate, fk_rate_category, date_added,
(SELECT AVG(rate) AS Expr1
FROM rates
WHERE (fk_rate_category = r.fk_rate_category)) AS avgRate
FROM rates AS r
WHERE (productId = #productId) AND (fk_rate_category = #fk_rate_category)
The problem is, that with my approach the avgRates value is the same in every record returned.
Any idea?
Firstly, always try to avoid using a correlated subquery when you can achieve the same result with a join, the optimiser will deal with it much better and you'll get the results faster.
I think the problem could be because you are not linking the dates of the data as well as FK_Rate_Cateogry, I'd imagine if this is for graphical purposes you would want the average by date:
SELECT r.ID,
r.ProductID,
r.Rate,
r.FK_Rate_Category,
r.Date_Added,
ar.avgRate
FROM Rates r
LEFT JOIN
( SELECT r.Date_Added,
r.FK_Rate_Category,
AVG(r.Rate) AS avgRate
FROM Rates r
GROUP BY r.FK_Rate_Category, r.Date_Added
) ar
ON ar.FK_Rate_Category = r.FK_Rate_Category
AND ar.Date_Added = r.Date_Added
WHERE r.ProductID = #ProductID
AND r.FK_Rate_Category = #FK_Rate_Category;
You got the set of records which have the specific id and rate_category. And avgRate is an average value from all records with the same rate_category - this set has the outer one as subset(see conditions of both queries). So all returned records have the same avgRate value.
So I see some holes in your logic line.