Reputation: 3647
I have a query with a couple of semi-complicated formulas. I've removed a lot of extra bits and boiled it down to what is relevant to my question.
DECLARE @Company AS NVARCHAR(8) = 'Acme'
, @Plant AS VARCHAR(20) = 'Albuquerque'
, @Warehouse AS NVARCHAR(8) = 'TNT-WH1'
, @DaysAhead AS INT = 10
, @FulfillmentThreshold AS INT = 90;
SELECT
@Company AS 'Company'
, orel.SellingReqQty
, orel.OurJobShippedQty + orel.OurStockShippedQty AS 'ShippedQty'
, orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty) AS 'ReqQtyRemaining'
, CASE
WHEN ((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ (orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty)) * 100)
>= 100 THEN '100'
ELSE
((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ (orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty)) * 100)
END
AS 'PercentAvailToFulfill'
FROM
dbo.OrderRel AS orel WITH (NOLOCK)
INNER JOIN erp.PartWhse AS pw WITH (NOLOCK)
ON (pw.Company = orel.Company AND
pw.PartNum = orel.PartNum AND
pw.WarehouseCode = @Warehouse)
WHERE
orel.Company = @Company
AND orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty) > 0 -- ReqQtyRemaining
AND (orel.ReqDate <= DATEADD(DAY, @DaysAhead, GETDATE())
OR
orel.RushPart_c = 1 )
AND ((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ (orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty)) * 100)
> @FulfillmentThreshold
AND (orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty)) > (pw.AllocatedQty + pw.ReservedQty)
As you can see this bit of code which represents a remaining qty is repeated many times but is necessary to calculate for each record returned:
orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty)
I'm looking for a way to make this more readable by changing that into a single variable. Is it possible to set that as a variable calculated for each row so I can refer to it as @ReqQtyRemaining?
Upvotes: 1
Views: 279
Reputation: 1811
In your case if all these columns are in the same table you can use COMPUTED
column.
So, you just need to modify your table structure to add new computed column.
ALTER TABLE dbo.OrderRel ADD ReqQtyRemaining AS (SellingReqQty - OurJobShippedQty + OurStockShippedQty)
Once you create a computed column this column as a name said will be always automatically updated and it can be used in the query as all other columns, you just cannot update this column manually.
Then you don't need to do the calculation in the queries and the big thing that you can put an index on this column as well.
More information here: https://learn.microsoft.com/en-us/sql/relational-databases/tables/specify-computed-columns-in-a-table?view=sql-server-ver15
If you are unable to change table structure you can try with CTE (Common Table Expressions)
. However, you will not see any specific performance improvement, you will just improve readability and reusability of the same code. So, then your query should look like this:
DECLARE @Company AS NVARCHAR(8) = 'Acme'
, @Plant AS VARCHAR(20) = 'Albuquerque'
, @Warehouse AS NVARCHAR(8) = 'TNT-WH1'
, @DaysAhead AS INT = 10
, @FulfillmentThreshold AS INT = 90;
;WITH OrderRelWithComputedCTE AS
(
SELECT *, (SellingReqQty - OurJobShippedQty + OurStockShippedQty) ReqQtyRemaining
FROM dbo.OrderRel WITH (NOLOCK)
)
SELECT
@Company AS 'Company'
, orel.SellingReqQty
, orel.OurJobShippedQty + orel.OurStockShippedQty AS 'ShippedQty'
, orel.ReqQtyRemaining
, CASE
WHEN ((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ orel.ReqQtyRemaining * 100)
>= 100 THEN '100'
ELSE
((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ orel.ReqQtyRemaining * 100)
END
AS 'PercentAvailToFulfill'
FROM
OrderRelWithComputedCTE AS orel
INNER JOIN erp.PartWhse AS pw WITH (NOLOCK)
ON (pw.Company = orel.Company AND
pw.PartNum = orel.PartNum AND
pw.WarehouseCode = @Warehouse)
WHERE
orel.Company = @Company
AND orel.SellingReqQty - (orel.OurJobShippedQty + orel.OurStockShippedQty) > 0 -- ReqQtyRemaining
AND (orel.ReqDate <= DATEADD(DAY, @DaysAhead, GETDATE())
OR
orel.RushPart_c = 1 )
AND ((pw.OnHandQty - (pw.AllocatedQty + pw.ReservedQty))
/ orel.ReqQtyRemaining * 100)
> @FulfillmentThreshold
AND orel.ReqQtyRemaining > (pw.AllocatedQty + pw.ReservedQty)
Pay attention on CTE
command at the top of the SELECT statement and on this line:
FROM OrderRelWithComputedCTE AS orel
Upvotes: 1