- sp_WHSOnHand
- sp_WHSOnHandWithDelta
In our environment (with certain amount of data), it tooks around 250ms to execute, although this number looks small, but when you have 100 of them being executed, that's 25,000ms (25 seconds), it is a different story then. A wait of 25s isn't something nice for the user.
Analyzing the query plan shows that it starts from InventDim, getting a large number of records and then nested loop to WHSInventReserve and so on. Looking at the thickness of the arrow next to InventDim, that's an indicator that a large number of rows are returned from that operator. That means it is operating that large number of rows against the WHSInventReserve.
This is the major bottleneck of the query.
We've tried update statistics and reindex and clear the cache to make sure it generate a new plan, but it still generate the same execution plan.
Due to this stored procedure has an ItemId provided, it should limit the number of rows from the WHSInventReserve, using this limited number of rows and nested loop against the InventDim would be much quicker, but somehow the optimizer didn't think so.
Bad query plan |
To resolve this problem, I'm splitting this query into two parts.
First, filter the WHSInventReserve with the ItemId provided and insert it into a table variable.
Then join this table variable to the InventDim. Although the sum of the estimated subtree cost of the original query and the new 2-parts query is similar, but it runs much quicker than the original version.
Better query plan |
With this new change, the stored procedure completed in 7ms instead of 250ms.
Original query join |
New query join |
The stored procedure should be changed from within AX at the 'WHSOnHandSPHelper' class. When synchronization is run, it regenerate this stored procedure. It also regenerate when stock dimension setup is changed.
Below is a sample of complete stored procedure code generated by the 'WHSOnHandSPHelper' class (Do take note, the selection field changed based on the stock dimension setup).
=================================================
CREATE PROCEDURE [dbo].[sp_WHSOnHand]
@PARTITION bigint,
@LEVEL int,
@DATAAREAID
nvarchar (4),
@ITEMID nvarchar (20),
@INVENTSITEID
nvarchar (10) = NULL,
@INVENTSITEIDLEVEL
int = 1024,
@INVENTLOCATIONID
nvarchar (10) = NULL,
@INVENTLOCATIONIDLEVEL int
= 1024,
@WMSLOCATIONID
nvarchar (10) = NULL,
@WMSLOCATIONIDLEVEL
int = 1024,
@WMSPALLETID
nvarchar (18) = NULL,
@WMSPALLETIDLEVEL
int = 1024,
@INVENTSTATUSID
nvarchar (10) = NULL,
@INVENTSTATUSIDLEVEL
int = 1024,
@LICENSEPLATEID
nvarchar (25) = NULL,
@LICENSEPLATEIDLEVEL
int = 1024,
@INVENTBATCHID
nvarchar (20) = NULL,
@INVENTBATCHIDLEVEL
int = 1024,
@INVENTSERIALID
nvarchar (20) = NULL,
@INVENTSERIALIDLEVEL
int = 1024,
@INVENTPROFILEID_RU
nvarchar (10) = NULL,
@INVENTPROFILEID_RULEVEL
int = 1024,
@INVENTOWNERID_RU
nvarchar (20) = NULL,
@INVENTOWNERID_RULEVEL
int = 1024,
@INVENTGTDID_RU
nvarchar (30) = NULL,
@INVENTGTDID_RULEVEL
int = 1024,
@CONFIGID nvarchar (10) = NULL,
@INVENTSIZEID
nvarchar (10) = NULL,
@INVENTCOLORID
nvarchar (10) = NULL,
@INVENTSTYLEID
nvarchar (10) = NULL,
-- Output
parameters
@AVAILPHYSICAL numeric(32, 16) OUTPUT,
@AVAILORDERED numeric(32, 16) OUTPUT
AS
--
Without nocount on the procedure will return number of affected rows in the
result set which is
--
harmful to performance and requires us to adjust field retrieval when calling
the stored procedure
SET NOCOUNT ON;
-- We
need to supress warnings when trying to aggregate NULL columns. This is a valid
business scenario
-- and
happens e.g. for a non-LP controlled location with batch below item.
SET ANSI_WARNINGS OFF;
-- The
@RESULT table variable is used to store intermediate quantities.
DECLARE @RESULT TABLE(
AVAILPHYSICALRESULT
numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
AVAILORDEREDRESULT
numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
AVAILPHYSICALFOUND
numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
AVAILORDEREDFOUND
numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
HIERARCHYLEVEL
int NOT NULL,
CONFIGID nvarchar (10) NULL,
INVENTSIZEID
nvarchar (10) NULL,
INVENTCOLORID
nvarchar (10) NULL,
INVENTSTYLEID
nvarchar (10) NULL,
INVENTSITEID
nvarchar (10) NULL,
INVENTLOCATIONID
nvarchar (10) NULL,
WMSLOCATIONID
nvarchar (10) NULL,
WMSPALLETID
nvarchar (18) NULL,
INVENTSTATUSID
nvarchar (10) NULL,
LICENSEPLATEID
nvarchar (25) NULL,
INVENTBATCHID
nvarchar (20) NULL,
INVENTSERIALID
nvarchar (20) NULL,
INVENTPROFILEID_RU
nvarchar (10) NULL,
INVENTOWNERID_RU
nvarchar (20) NULL,
INVENTGTDID_RU
nvarchar (30) NULL);
DECLARE @DIMLIST TABLE(
INVENTDIMID
nvarchar (20) NULL,
AVAILPHYSICAL
numeric(32, 16) NOT NULL,
AVAILORDERED
numeric(32, 16) NOT NULL);
-- The
algorithm of the stored procedure is as follows:
-- 1. Initialize
the @RESULT table with aggregated qtys in WHSInventReserve for the level
requested by user
-- 2.
Traverse the hierarchy up and for each level:
-- 1) Aggregate qtys from previous level in
@RESULT grouping by dimensions of current hierarchy level
-- 2) Aggregate qtys from current level in
WHSInventReserve grouping by dimensions of current hierarchy level
-- 3) Select the minimum of the above qtys
and insert into @RESULT
-- 3.
When hierarchy level 0 is reached, return the sum of aggregated qtys in @RESULT
-- In the
original query (the one after below query), it is joining InventDim and
WHSInventReserve and filter records based on some criteria.
-- But in
the execution plan, it doesn't seems to generate a good plan (even after UPDATE
STATISTICS). In the original execution plan, it always
-- Get
records from InventDim first, which returns lot of rows, then only join it to
WHSInventReserve and continue filter from there.
-- If we
makes it get records from WHSInventReserve first, filter it, then with lesser
rows from here, join it to InventDim, it will be quicker.
-- So the
optimization is to filter WHSInventResreve first, then use this result at the
original query. In the test, this has reduce the execution
-- time
from ~250ms to ~7ms
INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)
SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED
FROM WHSINVENTRESERVE WHSINVENTRESERVE
WHERE WHSINVENTRESERVE.ITEMID = @ITEMID
AND WHSINVENTRESERVE.PARTITION = @PARTITION
AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
AND WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL
--
Initialize the @RESULT variable.
-- Loads
aggregated data for the lowest level requested by user.
INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
SELECT SUM(DIMLIST.AVAILPHYSICAL),
SUM(DIMLIST.AVAILORDERED),
NULL,
NULL,
@LEVEL,
INVENTDIM.CONFIGID,
INVENTDIM.INVENTSIZEID,
INVENTDIM.INVENTCOLORID,
INVENTDIM.INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN INVENTDIM.INVENTSITEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN INVENTDIM.WMSPALLETID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
FROM INVENTDIM INVENTDIM
JOIN @DIMLIST DIMLIST
ON INVENTDIM.INVENTDIMID = DIMLIST.INVENTDIMID
WHERE INVENTDIM.DATAAREAID = @DATAAREAID
AND INVENTDIM.PARTITION = @PARTITION
AND (@CONFIGID IS NULL OR INVENTDIM.CONFIGID = @CONFIGID)
AND (@INVENTSIZEID IS NULL OR INVENTDIM.INVENTSIZEID = @INVENTSIZEID)
AND (@INVENTCOLORID IS NULL OR INVENTDIM.INVENTCOLORID = @INVENTCOLORID)
AND (@INVENTSTYLEID IS NULL OR INVENTDIM.INVENTSTYLEID = @INVENTSTYLEID)
AND (@LEVEL < @INVENTSITEIDLEVEL OR
@INVENTSITEID IS
NULL OR @INVENTSITEID = INVENTDIM.INVENTSITEID)
AND (@LEVEL < @INVENTLOCATIONIDLEVEL OR
@INVENTLOCATIONID IS
NULL OR @INVENTLOCATIONID = INVENTDIM.INVENTLOCATIONID)
AND (@LEVEL < @WMSLOCATIONIDLEVEL OR
@WMSLOCATIONID IS
NULL OR @WMSLOCATIONID = INVENTDIM.WMSLOCATIONID)
AND (@LEVEL < @WMSPALLETIDLEVEL OR @WMSPALLETID IS NULL OR @WMSPALLETID = INVENTDIM.WMSPALLETID)
AND (@LEVEL < @INVENTSTATUSIDLEVEL OR
@INVENTSTATUSID IS
NULL OR @INVENTSTATUSID = INVENTDIM.INVENTSTATUSID)
AND (@LEVEL < @LICENSEPLATEIDLEVEL OR
@LICENSEPLATEID IS
NULL OR @LICENSEPLATEID = INVENTDIM.LICENSEPLATEID)
AND (@LEVEL < @INVENTBATCHIDLEVEL OR
@INVENTBATCHID IS
NULL OR @INVENTBATCHID = INVENTDIM.INVENTBATCHID)
AND (@LEVEL < @INVENTSERIALIDLEVEL OR
@INVENTSERIALID IS
NULL OR @INVENTSERIALID = INVENTDIM.INVENTSERIALID)
AND (@LEVEL < @INVENTPROFILEID_RULEVEL OR
@INVENTPROFILEID_RU IS
NULL OR @INVENTPROFILEID_RU =
INVENTDIM.INVENTPROFILEID_RU)
AND (@LEVEL < @INVENTOWNERID_RULEVEL OR
@INVENTOWNERID_RU IS
NULL OR @INVENTOWNERID_RU = INVENTDIM.INVENTOWNERID_RU)
AND (@LEVEL < @INVENTGTDID_RULEVEL OR
@INVENTGTDID_RU IS
NULL OR @INVENTGTDID_RU = INVENTDIM.INVENTGTDID_RU)
GROUP BY
INVENTDIM.CONFIGID,
INVENTDIM.INVENTSIZEID,
INVENTDIM.INVENTCOLORID,
INVENTDIM.INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN INVENTDIM.INVENTSITEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN INVENTDIM.WMSPALLETID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END;
WHILE (@LEVEL > 0)
BEGIN
DELETE FROM @DIMLIST
INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)
SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED
FROM WHSINVENTRESERVE WHSINVENTRESERVE
WHERE WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL + -1
AND WHSINVENTRESERVE.ITEMID = @ITEMID
AND WHSINVENTRESERVE.PARTITION = @PARTITION
AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
SELECT SUM(CASE WHEN RESULT.AVAILPHYSICALFOUND <
RESULT.AVAILPHYSICALRESULT THEN
RESULT.AVAILPHYSICALFOUND ELSE
RESULT.AVAILPHYSICALRESULT END),
SUM(CASE WHEN RESULT.AVAILORDEREDFOUND < RESULT.AVAILORDEREDRESULT THEN RESULT.AVAILORDEREDFOUND ELSE RESULT.AVAILORDEREDRESULT END),
SUM(FOUND.AVAILPHYSICAL),
SUM(FOUND.AVAILORDERED),
@LEVEL + -1,
RESULT.CONFIGID AS CONFIGID,
RESULT.INVENTSIZEID AS INVENTSIZEID,
RESULT.INVENTCOLORID AS INVENTCOLORID,
RESULT.INVENTSTYLEID AS INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN RESULT.INVENTSITEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN RESULT.INVENTLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN RESULT.WMSLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN RESULT.WMSPALLETID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN RESULT.INVENTSTATUSID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN RESULT.LICENSEPLATEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN RESULT.INVENTBATCHID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN RESULT.INVENTSERIALID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN RESULT.INVENTGTDID_RU ELSE NULL END
FROM @RESULT RESULT
LEFT OUTER JOIN (
SELECT SUM(DIMLIST.AVAILPHYSICAL) AS AVAILPHYSICAL,
SUM(DIMLIST.AVAILORDERED) AS AVAILORDERED,
INVENTDIM.CONFIGID AS CONFIGID,
INVENTDIM.INVENTSIZEID AS INVENTSIZEID,
INVENTDIM.INVENTCOLORID AS INVENTCOLORID,
INVENTDIM.INVENTSTYLEID AS INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN INVENTDIM.INVENTSITEID ELSE NULL END AS INVENTSITEID,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END AS INVENTLOCATIONID,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN INVENTDIM.WMSLOCATIONID ELSE NULL END AS WMSLOCATIONID,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN INVENTDIM.WMSPALLETID ELSE NULL END AS WMSPALLETID,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN INVENTDIM.INVENTSTATUSID ELSE NULL END AS INVENTSTATUSID,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN INVENTDIM.LICENSEPLATEID ELSE NULL END AS LICENSEPLATEID,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN INVENTDIM.INVENTBATCHID ELSE NULL END AS INVENTBATCHID,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN INVENTDIM.INVENTSERIALID ELSE NULL END AS INVENTSERIALID,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END AS INVENTPROFILEID_RU,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END AS INVENTOWNERID_RU,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END AS INVENTGTDID_RU
FROM INVENTDIM INVENTDIM
JOIN @DIMLIST DIMLIST
ON INVENTDIM.PARTITION = @PARTITION
AND INVENTDIM.DATAAREAID = @DATAAREAID
AND INVENTDIM.INVENTDIMID = DIMLIST.INVENTDIMID
GROUP BY
INVENTDIM.CONFIGID,
INVENTDIM.INVENTSIZEID,
INVENTDIM.INVENTCOLORID,
INVENTDIM.INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN INVENTDIM.INVENTSITEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN INVENTDIM.WMSPALLETID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
) AS FOUND ON (RESULT.CONFIGID = FOUND.CONFIGID)
AND (RESULT.INVENTSIZEID = FOUND.INVENTSIZEID)
AND (RESULT.INVENTCOLORID = FOUND.INVENTCOLORID)
AND (RESULT.INVENTSTYLEID = FOUND.INVENTSTYLEID)
AND (@LEVEL + -1 < @INVENTSITEIDLEVEL OR
RESULT.INVENTSITEID = FOUND.INVENTSITEID)
AND (@LEVEL + -1 < @INVENTLOCATIONIDLEVEL OR
RESULT.INVENTLOCATIONID = FOUND.INVENTLOCATIONID)
AND (@LEVEL + -1 < @WMSLOCATIONIDLEVEL OR
RESULT.WMSLOCATIONID = FOUND.WMSLOCATIONID)
AND (@LEVEL + -1 < @WMSPALLETIDLEVEL OR RESULT.WMSPALLETID = FOUND.WMSPALLETID)
AND (@LEVEL + -1 < @INVENTSTATUSIDLEVEL OR
RESULT.INVENTSTATUSID = FOUND.INVENTSTATUSID)
AND (@LEVEL + -1 < @LICENSEPLATEIDLEVEL OR
RESULT.LICENSEPLATEID = FOUND.LICENSEPLATEID)
AND (@LEVEL + -1 < @INVENTBATCHIDLEVEL OR
RESULT.INVENTBATCHID = FOUND.INVENTBATCHID)
AND (@LEVEL + -1 < @INVENTSERIALIDLEVEL OR
RESULT.INVENTSERIALID = FOUND.INVENTSERIALID)
AND (@LEVEL + -1 < @INVENTPROFILEID_RULEVEL OR
RESULT.INVENTPROFILEID_RU = FOUND.INVENTPROFILEID_RU)
AND (@LEVEL + -1 < @INVENTOWNERID_RULEVEL OR
RESULT.INVENTOWNERID_RU = FOUND.INVENTOWNERID_RU)
AND (@LEVEL + -1 < @INVENTGTDID_RULEVEL OR
RESULT.INVENTGTDID_RU = FOUND.INVENTGTDID_RU)
WHERE RESULT.HIERARCHYLEVEL = @LEVEL
GROUP BY
RESULT.CONFIGID,
RESULT.INVENTSIZEID,
RESULT.INVENTCOLORID,
RESULT.INVENTSTYLEID,
CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL
THEN RESULT.INVENTSITEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL
THEN RESULT.INVENTLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL
THEN RESULT.WMSLOCATIONID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL
THEN RESULT.WMSPALLETID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL
THEN RESULT.INVENTSTATUSID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL
THEN RESULT.LICENSEPLATEID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL
THEN RESULT.INVENTBATCHID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL
THEN RESULT.INVENTSERIALID ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL
THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL
THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL
THEN RESULT.INVENTGTDID_RU ELSE NULL END;
SET @LEVEL = @LEVEL - 1
END; -- WHILE
SELECT @AVAILPHYSICAL = SUM(CASE WHEN AVAILPHYSICALFOUND <
AVAILPHYSICALRESULT THEN
AVAILPHYSICALFOUND ELSE
AVAILPHYSICALRESULT END),
@AVAILORDERED
= SUM(CASE WHEN AVAILORDEREDFOUND
< AVAILORDEREDRESULT
THEN AVAILORDEREDFOUND
ELSE AVAILORDEREDRESULT
END)
FROM @RESULT
WHERE HIERARCHYLEVEL = 0;
GO
=================================================
Below is the XPO extract of the updated 'WHSOnHandSPHelper' class
=================================================
Exportfile for AOT version 1.0 or later
Formatversion: 1
***Element: CLS
; Microsoft Dynamics AX Class: WHSOnHandSPHelper unloaded
; --------------------------------------------------------------------------------
CLSVERSION 1
CLASS #WHSOnHandSPHelper
PROPERTIES
Name #WHSOnHandSPHelper
Origin #{E0CDDBB5-8AE5-4BEF-9B5B-A41A300F36E5}
ENDPROPERTIES
METHODS
SOURCE #buildCreateSPStmt
#private str buildCreateSPStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator;
# ListEnumerator productDimensionsEnumerator;
# FieldId dimFieldId;
# str dimFieldName;
# boolean isSerialEnabled;
#
# if(useOptimizedVersion)
# {
# ret = this.TEC_buildCreateSPStmt(_includeDelta);
# }
# else
# {
# InventDimMetaDataCache::clearCache(); //in some cases the cache is not updated before sync making below SP
#
# enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# productDimensionsEnumerator = this.productDimensions().getEnumerator();
# isSerialEnabled = this.getEnabledDimsParametersMap().exists(fieldNum(InventDim, InventSerialId));
#
# /*
#CREATE PROCEDURE [sp_WHSOnHand]
# @PARTITION bigint,
# @LEVEL int,
# @DATAAREAID nvarchar (4),
# @ITEMID nvarchar (20),
# @INVENTSITEID nvarchar (10) = NULL,
# @INVENTSITEIDLEVEL int = 1024,
# @INVENTLOCATIONID nvarchar (10) = NULL,
# @INVENTLOCATIONIDLEVEL int = 1024,
# @WMSLOCATIONID nvarchar (10) = NULL,
# @WMSLOCATIONIDLEVEL int = 1024,
# @WMSPALLETID nvarchar (18) = NULL,
# @WMSPALLETIDLEVEL int = 1024,
# @INVENTSTATUSID nvarchar (10) = NULL,
# @INVENTSTATUSIDLEVEL int = 1024,
# @LICENSEPLATEID nvarchar (25) = NULL,
# @LICENSEPLATEIDLEVEL int = 1024,
# @INVENTBATCHID nvarchar (20) = NULL,
# @INVENTBATCHIDLEVEL int = 1024,
# @INVENTSERIALID nvarchar (20) = NULL,
# @INVENTSERIALIDLEVEL int = 1024,
# @INVENTPROFILEID_RU nvarchar (10) = NULL,
# @INVENTPROFILEID_RULEVEL int = 1024,
# @INVENTOWNERID_RU nvarchar (20) = NULL,
# @INVENTOWNERID_RULEVEL int = 1024,
# @INVENTGTDID_RU nvarchar (30) = NULL,
# @INVENTGTDID_RULEVEL int = 1024,
# @CONFIGID nvarchar (10) = NULL,
# @INVENTSIZEID nvarchar (10) = NULL,
# @INVENTCOLORID nvarchar (10) = NULL,
# @INVENTSTYLEID nvarchar (10) = NULL,
# -- Output parameters
# @AVAILPHYSICAL numeric(32, 16) OUTPUT,
# @AVAILORDERED numeric(32, 16) OUTPUT
#AS
#
#-- Without nocount on the procedure will return number of affected rows in the result set which is
#-- harmful to performance and requires us to adjust field retrieval when calling the stored procedure
#SET NOCOUNT ON;
#
#-- We need to supress warnings when trying to aggregate NULL columns. This is a valid business scenario
#-- and happens e.g. for a non-LP controlled location with batch below item.
#SET ANSI_WARNINGS OFF;
#
#-- The @RESULT table variable is used to store intermediate quantities.
#DECLARE @RESULT TABLE(
# AVAILPHYSICALRESULT numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
# AVAILORDEREDRESULT numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
# AVAILPHYSICALFOUND numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
# AVAILORDEREDFOUND numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
# HIERARCHYLEVEL int NOT NULL,
# CONFIGID nvarchar (10) NULL,
# INVENTSIZEID nvarchar (10) NULL,
# INVENTCOLORID nvarchar (10) NULL,
# INVENTSTYLEID nvarchar (10) NULL,
# INVENTSITEID nvarchar (10) NULL,
# INVENTLOCATIONID nvarchar (10) NULL,
# WMSLOCATIONID nvarchar (10) NULL,
# WMSPALLETID nvarchar (18) NULL,
# INVENTSTATUSID nvarchar (10) NULL,
# LICENSEPLATEID nvarchar (25) NULL,
# INVENTBATCHID nvarchar (20) NULL,
# INVENTSERIALID nvarchar (20) NULL,
# INVENTPROFILEID_RU nvarchar (10) NULL,
# INVENTOWNERID_RU nvarchar (20) NULL,
# INVENTGTDID_RU nvarchar (30) NULL);
#
#-- The algorithm of the stored procedure is as follows:
#-- 1. Initialize the @RESULT table with aggregated qtys in WHSInventReserve for the level requested by user
#-- 2. Traverse the hierarchy up and for each level:
#-- 1) Aggregate qtys from previous level in @RESULT grouping by dimensions of current hierarchy level
#-- 2) Aggregate qtys from current level in WHSInventReserve grouping by dimensions of current hierarchy level
#-- 3) Select the minimum of the above qtys and insert into @RESULT
#-- 3. When hierarchy level 0 is reached, return the sum of aggregated qtys in @RESULT
#
#-- Initialize the @RESULT variable.
#-- Loads aggregated data for the lowest level requested by user.
#INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
#SELECT SUM(WHSINVENTRESERVE.AVAILPHYSICAL),
# SUM(WHSINVENTRESERVE.AVAILORDERED),
# NULL,
# NULL,
# @LEVEL,
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
# FROM WHSINVENTRESERVE WHSINVENTRESERVE
# JOIN INVENTDIM ON INVENTDIM.INVENTDIMID = WHSINVENTRESERVE.INVENTDIMID AND INVENTDIM.DATAAREAID = WHSINVENTRESERVE.DATAAREAID AND INVENTDIM.PARTITION = WHSINVENTRESERVE.PARTITION
# WHERE WHSINVENTRESERVE.ITEMID = @ITEMID
# AND WHSINVENTRESERVE.PARTITION = @PARTITION
# AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
# AND WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL
# AND (@CONFIGID IS NULL OR INVENTDIM.CONFIGID = @CONFIGID)
# AND (@INVENTSIZEID IS NULL OR INVENTDIM.INVENTSIZEID = @INVENTSIZEID)
# AND (@INVENTCOLORID IS NULL OR INVENTDIM.INVENTCOLORID = @INVENTCOLORID)
# AND (@INVENTSTYLEID IS NULL OR INVENTDIM.INVENTSTYLEID = @INVENTSTYLEID)
# AND (@LEVEL < @INVENTSITEIDLEVEL OR @INVENTSITEID IS NULL OR @INVENTSITEID = INVENTDIM.INVENTSITEID)
# AND (@LEVEL < @INVENTLOCATIONIDLEVEL OR @INVENTLOCATIONID IS NULL OR @INVENTLOCATIONID = INVENTDIM.INVENTLOCATIONID)
# AND (@LEVEL < @WMSLOCATIONIDLEVEL OR @WMSLOCATIONID IS NULL OR @WMSLOCATIONID = INVENTDIM.WMSLOCATIONID)
# AND (@LEVEL < @WMSPALLETIDLEVEL OR @WMSPALLETID IS NULL OR @WMSPALLETID = INVENTDIM.WMSPALLETID)
# AND (@LEVEL < @INVENTSTATUSIDLEVEL OR @INVENTSTATUSID IS NULL OR @INVENTSTATUSID = INVENTDIM.INVENTSTATUSID)
# AND (@LEVEL < @LICENSEPLATEIDLEVEL OR @LICENSEPLATEID IS NULL OR @LICENSEPLATEID = INVENTDIM.LICENSEPLATEID)
# AND (@LEVEL < @INVENTBATCHIDLEVEL OR @INVENTBATCHID IS NULL OR @INVENTBATCHID = INVENTDIM.INVENTBATCHID)
# AND (@LEVEL < @INVENTSERIALIDLEVEL OR @INVENTSERIALID IS NULL OR @INVENTSERIALID = INVENTDIM.INVENTSERIALID)
# AND (@LEVEL < @INVENTPROFILEID_RULEVEL OR @INVENTPROFILEID_RU IS NULL OR @INVENTPROFILEID_RU = INVENTDIM.INVENTPROFILEID_RU)
# AND (@LEVEL < @INVENTOWNERID_RULEVEL OR @INVENTOWNERID_RU IS NULL OR @INVENTOWNERID_RU = INVENTDIM.INVENTOWNERID_RU)
# AND (@LEVEL < @INVENTGTDID_RULEVEL OR @INVENTGTDID_RU IS NULL OR @INVENTGTDID_RU = INVENTDIM.INVENTGTDID_RU)
#GROUP BY
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END;
#
#WHILE (@LEVEL > 0)
#BEGIN
# INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
#SELECT SUM(CASE WHEN RESULT.AVAILPHYSICALFOUND < RESULT.AVAILPHYSICALRESULT THEN RESULT.AVAILPHYSICALFOUND ELSE RESULT.AVAILPHYSICALRESULT END),
# SUM(CASE WHEN RESULT.AVAILORDEREDFOUND < RESULT.AVAILORDEREDRESULT THEN RESULT.AVAILORDEREDFOUND ELSE RESULT.AVAILORDEREDRESULT END),
# SUM(FOUND.AVAILPHYSICAL),
# SUM(FOUND.AVAILORDERED),
# @LEVEL + -1,
# RESULT.CONFIGID AS CONFIGID,
# RESULT.INVENTSIZEID AS INVENTSIZEID,
# RESULT.INVENTCOLORID AS INVENTCOLORID,
# RESULT.INVENTSTYLEID AS INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN RESULT.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN RESULT.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN RESULT.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN RESULT.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN RESULT.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN RESULT.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN RESULT.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN RESULT.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN RESULT.INVENTGTDID_RU ELSE NULL END
#FROM @RESULT RESULT
#LEFT OUTER JOIN (
#SELECT SUM(WHSINVENTRESERVE.AVAILPHYSICAL) AS AVAILPHYSICAL,
# SUM(WHSINVENTRESERVE.AVAILORDERED) AS AVAILORDERED,
# INVENTDIM.CONFIGID AS CONFIGID,
# INVENTDIM.INVENTSIZEID AS INVENTSIZEID,
# INVENTDIM.INVENTCOLORID AS INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID AS INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END AS INVENTSITEID,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END AS INVENTLOCATIONID,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END AS WMSLOCATIONID,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END AS WMSPALLETID,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END AS INVENTSTATUSID,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END AS LICENSEPLATEID,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END AS INVENTBATCHID,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END AS INVENTSERIALID,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END AS INVENTPROFILEID_RU,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END AS INVENTOWNERID_RU,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END AS INVENTGTDID_RU
#FROM WHSINVENTRESERVE WHSINVENTRESERVE
#JOIN INVENTDIM ON INVENTDIM.PARTITION = WHSINVENTRESERVE.PARTITION
# AND INVENTDIM.DATAAREAID = WHSINVENTRESERVE.DATAAREAID
# AND INVENTDIM.INVENTDIMID = WHSINVENTRESERVE.INVENTDIMID
#WHERE WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL + -1
# AND WHSINVENTRESERVE.ITEMID = @ITEMID
# AND WHSINVENTRESERVE.PARTITION = @PARTITION
# AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
#GROUP BY
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
# ) AS FOUND ON (RESULT.CONFIGID = FOUND.CONFIGID)
# AND (RESULT.INVENTSIZEID = FOUND.INVENTSIZEID)
# AND (RESULT.INVENTCOLORID = FOUND.INVENTCOLORID)
# AND (RESULT.INVENTSTYLEID = FOUND.INVENTSTYLEID)
# AND (@LEVEL + -1 < @INVENTSITEIDLEVEL OR RESULT.INVENTSITEID = FOUND.INVENTSITEID)
# AND (@LEVEL + -1 < @INVENTLOCATIONIDLEVEL OR RESULT.INVENTLOCATIONID = FOUND.INVENTLOCATIONID)
# AND (@LEVEL + -1 < @WMSLOCATIONIDLEVEL OR RESULT.WMSLOCATIONID = FOUND.WMSLOCATIONID)
# AND (@LEVEL + -1 < @WMSPALLETIDLEVEL OR RESULT.WMSPALLETID = FOUND.WMSPALLETID)
# AND (@LEVEL + -1 < @INVENTSTATUSIDLEVEL OR RESULT.INVENTSTATUSID = FOUND.INVENTSTATUSID)
# AND (@LEVEL + -1 < @LICENSEPLATEIDLEVEL OR RESULT.LICENSEPLATEID = FOUND.LICENSEPLATEID)
# AND (@LEVEL + -1 < @INVENTBATCHIDLEVEL OR RESULT.INVENTBATCHID = FOUND.INVENTBATCHID)
# AND (@LEVEL + -1 < @INVENTSERIALIDLEVEL OR RESULT.INVENTSERIALID = FOUND.INVENTSERIALID)
# AND (@LEVEL + -1 < @INVENTPROFILEID_RULEVEL OR RESULT.INVENTPROFILEID_RU = FOUND.INVENTPROFILEID_RU)
# AND (@LEVEL + -1 < @INVENTOWNERID_RULEVEL OR RESULT.INVENTOWNERID_RU = FOUND.INVENTOWNERID_RU)
# AND (@LEVEL + -1 < @INVENTGTDID_RULEVEL OR RESULT.INVENTGTDID_RU = FOUND.INVENTGTDID_RU)
#WHERE RESULT.HIERARCHYLEVEL = @LEVEL
#GROUP BY
# RESULT.CONFIGID,
# RESULT.INVENTSIZEID,
# RESULT.INVENTCOLORID,
# RESULT.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN RESULT.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN RESULT.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN RESULT.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN RESULT.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN RESULT.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN RESULT.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN RESULT.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN RESULT.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN RESULT.INVENTGTDID_RU ELSE NULL END;
#
#
# SET @LEVEL = @LEVEL - 1
#END; -- WHILE
#
#SELECT @AVAILPHYSICAL = SUM(CASE WHEN AVAILPHYSICALFOUND < AVAILPHYSICALRESULT THEN AVAILPHYSICALFOUND ELSE AVAILPHYSICALRESULT END),
# @AVAILORDERED = SUM(CASE WHEN AVAILORDEREDFOUND < AVAILORDEREDRESULT THEN AVAILORDEREDFOUND ELSE AVAILORDEREDRESULT END)
#FROM @RESULT
#WHERE HIERARCHYLEVEL = 0;
# */
#
# ret += strFmt('CREATE PROCEDURE [%1]\n', WhsOnHandSPHelper::storedProcedureName(_includeDelta));
# ret += ' @PARTITION bigint,\n';
# ret += strFmt(' %1 int,\n', this.levelExpression(0));
# ret += strFmt(' @DATAAREAID %1,\n', this.sqlTypeNameForField(tableNum(InventTable), fieldNum(InventTable, DataAreaId)));
# ret += strFmt(' @ITEMID %1,\n', this.sqlTypeNameForField(tableNum(InventTable), fieldNum(InventTable, ItemId)));
# if (_includeDelta)
# {
# ret += strFmt(' %1 %2,\n', #TTSIdParmName, this.sqlTypeNameForField(tableNum(WHSInventReserveDelta), fieldNum(WHSInventReserveDelta, TTSId)));
# }
#
# // Generate parameters for supported dimensions
# enabledDimsEnumerator.reset();
# while (enabledDimsEnumerator.moveNext())
# {
# [dimFieldId, dimFieldName] = enabledDimsEnumerator.current();
# ret += strFmt(' %1 %2 = NULL,\n', this.dimensionParm(dimFieldName), this.sqlTypeNameForField(tableNum(InventDim), dimFieldId));
# ret += strFmt(' %1 int = %2,\n', this.dimensionLevelParm(dimFieldName), #INVALIDHIERARCHYLEVEL);
# }
#
# // Generate parameters for product dimensions
# productDimensionsEnumerator.reset();
# while (productDimensionsEnumerator.moveNext())
# {
# [dimFieldId, dimFieldName] = productDimensionsEnumerator.current();
# ret += strFmt(' %1 %2 = NULL,\n', this.dimensionParm(dimFieldName), this.sqlTypeNameForField(tableNum(InventDim), dimFieldId));
# }
#
# ret += ' -- Output parameters\n';
# ret += strFmt(' %1 numeric(32, 16) OUTPUT,\n', #AvailPhysicalParmName);
# ret += strFmt(' %1 numeric(32, 16) OUTPUT\n', #AvailOrderedParmName);
# ret += 'AS\n\n';
#
# ret += '-- Without nocount on the procedure will return number of affected rows in the result set which is\n';
# ret += '-- harmful to performance and requires us to adjust field retrieval when calling the stored procedure\n';
# ret += 'SET NOCOUNT ON;\n\n';
#
# ret += '-- We need to supress warnings when trying to aggregate NULL columns. This is a valid business scenario\n';
# ret += '-- and happens e.g. for a non-LP controlled location with batch below item.\n';
# ret += 'SET ANSI_WARNINGS OFF;\n\n';
#
# ret += this.declareResultTableVariable() + '\n';
#
# ret += '-- The algorithm of the stored procedure is as follows:\n';
# ret += '-- 1. Initialize the @RESULT table with aggregated qtys in WHSInventReserve for the level requested by user\n';
# ret += '-- 2. Traverse the hierarchy up and for each level:\n';
# ret += '-- 1) Aggregate qtys from previous level in @RESULT grouping by dimensions of current hierarchy level\n';
# ret += '-- 2) Aggregate qtys from current level in WHSInventReserve grouping by dimensions of current hierarchy level\n';
# ret += '-- 3) Select the minimum of the above qtys and insert into @RESULT\n';
# ret += '-- 3. When hierarchy level 0 is reached, return the sum of aggregated qtys in @RESULT\n\n';
#
# ret += '-- Initialize the @RESULT variable.\n';
# ret += '-- Loads aggregated data for the lowest level requested by user.\n';
# ret += 'INSERT INTO @RESULT (' + this.resultTableVariableFields() + ')\n';
#
# ret += this.selectFromWHSInventReserveStmt(_includeDelta) + '\n';
#
# ret += strFmt('WHILE (%1 > 0)\n', this.levelExpression(0));
# ret += 'BEGIN\n';
# ret += strFmt(' INSERT INTO @RESULT (%1)\n', this.resultTableVariableFields());
#
# ret += this.selectFromResultJoinWHSInventReserveStmt(_includeDelta) + '\n\n';
#
# ret += strFmt(' SET %1 = %1 - 1\n', this.levelExpression(0));
# ret += 'END; -- WHILE\n\n';
#
# ret += strFmt('SELECT %1 = SUM(CASE WHEN %2 < %3 THEN %2 ELSE %3 END),\n',
# #AvailPhysicalParmName,
# #AVAILPHYSICALFOUNDFieldName,
# #AVAILPHYSICALRESULTFieldName);
# ret += strFmt(' %1 = SUM(CASE WHEN %2 < %3 THEN %2 ELSE %3 END)\n',
# #AvailOrderedParmName,
# #AVAILORDEREDFOUNDFieldName,
# #AVAILORDEREDRESULTFieldName);
# ret += 'FROM @RESULT\n';
# ret += strFmt('WHERE %1 = 0;\n', #HIERARCHYLEVELFieldName);
# }
#
# return ret;
#}
ENDSOURCE
SOURCE #classDeclaration
#///
#/// The WHSOnHandSPHelper class contains helper methods to manipulate the WHS on-hand stored procedure.
#///
#public class WhsOnHandSPHelper
#{
# #Define.CacheScope('WHSOnHandSPHelper')
# #Define.EnabledDimsParametersCacheKey('EnabledDimensionsCache')
# #Define.ProductDimsParametersCacheKey('ProductDimensionsCache')
#
# #Define.AvailPhysicalParmName('@AVAILPHYSICAL')
# #Define.AvailPhysicalMinName('@AVAILPHYSICALMIN')
# #Define.AvailOrderedParmName('@AVAILORDERED')
# #Define.AvailOrderedMinName('@AVAILORDERMIN')
# #Define.TTSIdParmName('@TTSId')
#
# #Define.AVAILPHYSICALRESULTFieldName('AVAILPHYSICALRESULT')
# #Define.AVAILORDEREDRESULTFieldName('AVAILORDEREDRESULT')
# #Define.AVAILPHYSICALFOUNDFieldName('AVAILPHYSICALFOUND')
# #Define.AVAILORDEREDFOUNDFieldName('AVAILORDEREDFOUND')
# #Define.HIERARCHYLEVELFieldName('HIERARCHYLEVEL')
#
# #WHSOnHandSP
# #WHSReservationHierarchy
#
# str resultTableVariableFields; // access using the resultTableVariableFields() method
#
# boolean useOptimizedVersion;
#}
ENDSOURCE
SOURCE #new
#protected void new()
#{
# resultTableVariableFields = '';
#
# useOptimizedVersion = true;
#}
ENDSOURCE
SOURCE #selectFromWHSInventReserveStmt
#private str selectFromWHSInventReserveStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# ListEnumerator productDimsEnumerator = this.productDimensions().getEnumerator();
# str dimFieldName;
# str levelExpr = this.levelExpression(-1);
# str inventReserveAlias = this.whsInventReserveTableAlias(_includeDelta);
# boolean hasDoneFirstIteration;
#
# if(useOptimizedVersion)
# {
# ret = this.TEC_selectFromWHSInventReserveStmt(_includeDelta);
# }
# else
# {
# ret += strFmt('SELECT SUM(%1.AVAILPHYSICAL),\n', inventReserveAlias);
# ret += strFmt(' SUM(%1.AVAILORDERED),\n', inventReserveAlias);
# ret += ' NULL,\n';
# ret += ' NULL,\n';
# ret += strFmt(' %1,\n', this.levelExpression(0));
#
# // Select product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Select enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# this.levelExpression(-1),
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
#
# ret += strFmt(' FROM %1 %2\n', this.whsInventReserveTableName(_includeDelta), inventReserveAlias);
# ret += strFmt(' JOIN INVENTDIM ON INVENTDIM.INVENTDIMID = %1.INVENTDIMID AND INVENTDIM.DATAAREAID = %1.DATAAREAID AND INVENTDIM.PARTITION = %1.PARTITION\n', inventReserveAlias);
# ret += strFmt(' WHERE %1.ITEMID = @ITEMID\n', inventReserveAlias);
# ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n', inventReserveAlias);
# ret += strFmt(' AND %1.HIERARCHYLEVEL = %2\n', inventReserveAlias, this.levelExpression(0));
#
# // Add product dimensions range
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' AND (%2 IS NULL OR INVENTDIM.%1 = %2)\n',
# dimFieldName,
# this.dimensionParm(dimFieldName));
# }
#
# // Add enabled dimensions range
# enabledDimsEnumerator.reset();
# while (enabledDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' AND (%1 < %2 OR %3 IS NULL OR %3 = INVENTDIM.%4)\n',
# this.levelExpression(0),
# this.dimensionLevelParm(dimFieldName),
# this.dimensionParm(dimFieldName),
# dimFieldName);
# }
#
# ret += 'GROUP BY\n';
#
# // Add grouping by product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Add grouping by enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# this.levelExpression(-1),
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
#
# ret += ';\n';
# }
#
# return ret;
#}
ENDSOURCE
SOURCE #selectInnerFromWHSInventReserveStmt
#private str selectInnerFromWHSInventReserveStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# ListEnumerator productDimsEnumerator = this.productDimensions().getEnumerator();
# str dimFieldName;
# str levelExpr = this.levelExpression(-1);
# str inventReserveAlias = this.whsInventReserveTableAlias(_includeDelta);
# boolean hasDoneFirstIteration;
#
# if(useOptimizedVersion)
# {
# ret = this.TEC_selectInnerFromWHSInventReserveStmt(_includeDelta);
# }
# else
# {
# ret += strFmt('SELECT SUM(%1.AVAILPHYSICAL) AS AVAILPHYSICAL,\n', inventReserveAlias);
# ret += strFmt(' SUM(%1.AVAILORDERED) AS AVAILORDERED,\n', inventReserveAlias);
#
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1 AS %1,\n', dimFieldName);
# }
#
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END AS %3',
# levelExpr,
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
#
# ret += strFmt('FROM %1 %2\n', this.whsInventReserveTableName(_includeDelta), inventReserveAlias);
# ret += strFmt('JOIN INVENTDIM ON INVENTDIM.PARTITION = %1.PARTITION\n', inventReserveAlias);
# ret += strFmt(' AND INVENTDIM.DATAAREAID = %1.DATAAREAID\n', inventReserveAlias);
# ret += strFmt(' AND INVENTDIM.INVENTDIMID = %1.INVENTDIMID\n', inventReserveAlias);
# ret += strFmt('WHERE %1.HIERARCHYLEVEL = %2\n', inventReserveAlias, levelExpr);
# ret += strFmt(' AND %1.ITEMID = @ITEMID\n', inventReserveAlias);
# ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n', inventReserveAlias);
# ret += 'GROUP BY\n';
#
# // Add groupping by product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Add groupping by enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# levelExpr,
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
# }
#
# return ret;
#}
ENDSOURCE
SOURCE #TEC_buildCreateSPStmt
#private str TEC_buildCreateSPStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator;
# ListEnumerator productDimensionsEnumerator;
# FieldId dimFieldId;
# str dimFieldName;
# boolean isSerialEnabled;
# str inventReserveAlias = this.whsInventReserveTableAlias(_includeDelta);
#
# InventDimMetaDataCache::clearCache(); //in some cases the cache is not updated before sync making below SP
#
# enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# productDimensionsEnumerator = this.productDimensions().getEnumerator();
# isSerialEnabled = this.getEnabledDimsParametersMap().exists(fieldNum(InventDim, InventSerialId));
#
# /*
#CREATE PROCEDURE [dbo].[sp_WHSOnHand]
# @PARTITION bigint,
# @LEVEL int,
# @DATAAREAID nvarchar (4),
# @ITEMID nvarchar (20),
# @INVENTSITEID nvarchar (10) = NULL,
# @INVENTSITEIDLEVEL int = 1024,
# @INVENTLOCATIONID nvarchar (10) = NULL,
# @INVENTLOCATIONIDLEVEL int = 1024,
# @WMSLOCATIONID nvarchar (10) = NULL,
# @WMSLOCATIONIDLEVEL int = 1024,
# @WMSPALLETID nvarchar (18) = NULL,
# @WMSPALLETIDLEVEL int = 1024,
# @INVENTSTATUSID nvarchar (10) = NULL,
# @INVENTSTATUSIDLEVEL int = 1024,
# @LICENSEPLATEID nvarchar (25) = NULL,
# @LICENSEPLATEIDLEVEL int = 1024,
# @INVENTBATCHID nvarchar (20) = NULL,
# @INVENTBATCHIDLEVEL int = 1024,
# @INVENTSERIALID nvarchar (20) = NULL,
# @INVENTSERIALIDLEVEL int = 1024,
# @INVENTPROFILEID_RU nvarchar (10) = NULL,
# @INVENTPROFILEID_RULEVEL int = 1024,
# @INVENTOWNERID_RU nvarchar (20) = NULL,
# @INVENTOWNERID_RULEVEL int = 1024,
# @INVENTGTDID_RU nvarchar (30) = NULL,
# @INVENTGTDID_RULEVEL int = 1024,
# @CONFIGID nvarchar (10) = NULL,
# @INVENTSIZEID nvarchar (10) = NULL,
# @INVENTCOLORID nvarchar (10) = NULL,
# @INVENTSTYLEID nvarchar (10) = NULL,
# -- Output parameters
# @AVAILPHYSICAL numeric(32, 16) OUTPUT,
# @AVAILORDERED numeric(32, 16) OUTPUT
#AS
#
#-- Without nocount on the procedure will return number of affected rows in the result set which is
#-- harmful to performance and requires us to adjust field retrieval when calling the stored procedure
#SET NOCOUNT ON;
#
#-- We need to supress warnings when trying to aggregate NULL columns. This is a valid business scenario
#-- and happens e.g. for a non-LP controlled location with batch below item.
#SET ANSI_WARNINGS OFF;
#
#-- The @RESULT table variable is used to store intermediate quantities.
#DECLARE @RESULT TABLE(
# AVAILPHYSICALRESULT numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
# AVAILORDEREDRESULT numeric(32, 16) NOT NULL, -- Aggregated minimum qtys from lower level in @RESULT
# AVAILPHYSICALFOUND numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
# AVAILORDEREDFOUND numeric(32, 16), -- Aggregated qty for current level in WHSInventReserve
# HIERARCHYLEVEL int NOT NULL,
# CONFIGID nvarchar (10) NULL,
# INVENTSIZEID nvarchar (10) NULL,
# INVENTCOLORID nvarchar (10) NULL,
# INVENTSTYLEID nvarchar (10) NULL,
# INVENTSITEID nvarchar (10) NULL,
# INVENTLOCATIONID nvarchar (10) NULL,
# WMSLOCATIONID nvarchar (10) NULL,
# WMSPALLETID nvarchar (18) NULL,
# INVENTSTATUSID nvarchar (10) NULL,
# LICENSEPLATEID nvarchar (25) NULL,
# INVENTBATCHID nvarchar (20) NULL,
# INVENTSERIALID nvarchar (20) NULL,
# INVENTPROFILEID_RU nvarchar (10) NULL,
# INVENTOWNERID_RU nvarchar (20) NULL,
# INVENTGTDID_RU nvarchar (30) NULL);
#
#DECLARE @DIMLIST TABLE(
# INVENTDIMID nvarchar (20) NULL,
# AVAILPHYSICAL numeric(32, 16) NOT NULL,
# AVAILORDERED numeric(32, 16) NOT NULL);
#
#-- The algorithm of the stored procedure is as follows:
#-- 1. Initialize the @RESULT table with aggregated qtys in WHSInventReserve for the level requested by user
#-- 2. Traverse the hierarchy up and for each level:
#-- 1) Aggregate qtys from previous level in @RESULT grouping by dimensions of current hierarchy level
#-- 2) Aggregate qtys from current level in WHSInventReserve grouping by dimensions of current hierarchy level
#-- 3) Select the minimum of the above qtys and insert into @RESULT
#-- 3. When hierarchy level 0 is reached, return the sum of aggregated qtys in @RESULT
#
#-- In the original query (the one after below query), it is joining InventDim and WHSInventReserve and filter records based on some criteria.
#-- But in the execution plan, it doesn't seems to generate a good plan (even after UPDATE STATISTICS). In the original execution plan, it always
#-- Get records from InventDim first, which returns lot of rows, then only join it to WHSInventReserve and continue filter from there.
#-- If we makes it get records from WHSInventReserve first, filter it, then with lesser rows from here, join it to InventDim, it will be quicker.
#-- So the optimization is to filter WHSInventResreve first, then use this result at the original query. In the test, this has reduce the execution
#-- time from ~250ms to ~7ms
# INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)
# SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED
# FROM WHSINVENTRESERVE WHSINVENTRESERVE
# WHERE WHSINVENTRESERVE.ITEMID = @ITEMID
# AND WHSINVENTRESERVE.PARTITION = @PARTITION
# AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
# AND WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL
#
#-- Initialize the @RESULT variable.
#-- Loads aggregated data for the lowest level requested by user.
#INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
#SELECT SUM(DIMLIST.AVAILPHYSICAL),
# SUM(DIMLIST.AVAILORDERED),
# NULL,
# NULL,
# @LEVEL,
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
# FROM INVENTDIM INVENTDIM
# JOIN @DIMLIST DIMLIST
# ON INVENTDIM.INVENTDIMID = DIMLIST.INVENTDIMID
# WHERE INVENTDIM.DATAAREAID = @DATAAREAID
# AND INVENTDIM.PARTITION = @PARTITION
# AND (@CONFIGID IS NULL OR INVENTDIM.CONFIGID = @CONFIGID)
# AND (@INVENTSIZEID IS NULL OR INVENTDIM.INVENTSIZEID = @INVENTSIZEID)
# AND (@INVENTCOLORID IS NULL OR INVENTDIM.INVENTCOLORID = @INVENTCOLORID)
# AND (@INVENTSTYLEID IS NULL OR INVENTDIM.INVENTSTYLEID = @INVENTSTYLEID)
# AND (@LEVEL < @INVENTSITEIDLEVEL OR @INVENTSITEID IS NULL OR @INVENTSITEID = INVENTDIM.INVENTSITEID)
# AND (@LEVEL < @INVENTLOCATIONIDLEVEL OR @INVENTLOCATIONID IS NULL OR @INVENTLOCATIONID = INVENTDIM.INVENTLOCATIONID)
# AND (@LEVEL < @WMSLOCATIONIDLEVEL OR @WMSLOCATIONID IS NULL OR @WMSLOCATIONID = INVENTDIM.WMSLOCATIONID)
# AND (@LEVEL < @WMSPALLETIDLEVEL OR @WMSPALLETID IS NULL OR @WMSPALLETID = INVENTDIM.WMSPALLETID)
# AND (@LEVEL < @INVENTSTATUSIDLEVEL OR @INVENTSTATUSID IS NULL OR @INVENTSTATUSID = INVENTDIM.INVENTSTATUSID)
# AND (@LEVEL < @LICENSEPLATEIDLEVEL OR @LICENSEPLATEID IS NULL OR @LICENSEPLATEID = INVENTDIM.LICENSEPLATEID)
# AND (@LEVEL < @INVENTBATCHIDLEVEL OR @INVENTBATCHID IS NULL OR @INVENTBATCHID = INVENTDIM.INVENTBATCHID)
# AND (@LEVEL < @INVENTSERIALIDLEVEL OR @INVENTSERIALID IS NULL OR @INVENTSERIALID = INVENTDIM.INVENTSERIALID)
# AND (@LEVEL < @INVENTPROFILEID_RULEVEL OR @INVENTPROFILEID_RU IS NULL OR @INVENTPROFILEID_RU = INVENTDIM.INVENTPROFILEID_RU)
# AND (@LEVEL < @INVENTOWNERID_RULEVEL OR @INVENTOWNERID_RU IS NULL OR @INVENTOWNERID_RU = INVENTDIM.INVENTOWNERID_RU)
# AND (@LEVEL < @INVENTGTDID_RULEVEL OR @INVENTGTDID_RU IS NULL OR @INVENTGTDID_RU = INVENTDIM.INVENTGTDID_RU)
#GROUP BY
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END;
#
#WHILE (@LEVEL > 0)
#BEGIN
#
# DELETE FROM @DIMLIST
#
# INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)
# SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED
# FROM WHSINVENTRESERVE WHSINVENTRESERVE
# WHERE WHSINVENTRESERVE.HIERARCHYLEVEL = @LEVEL + -1
# AND WHSINVENTRESERVE.ITEMID = @ITEMID
# AND WHSINVENTRESERVE.PARTITION = @PARTITION
# AND WHSINVENTRESERVE.DATAAREAID = @DATAAREAID
#
#INSERT INTO @RESULT (AVAILPHYSICALRESULT, AVAILORDEREDRESULT, AVAILPHYSICALFOUND, AVAILORDEREDFOUND, HIERARCHYLEVEL, CONFIGID, INVENTSIZEID, INVENTCOLORID, INVENTSTYLEID, INVENTSITEID, INVENTLOCATIONID, WMSLOCATIONID, WMSPALLETID, INVENTSTATUSID, LICENSEPLATEID, INVENTBATCHID, INVENTSERIALID, INVENTPROFILEID_RU, INVENTOWNERID_RU, INVENTGTDID_RU)
#SELECT SUM(CASE WHEN RESULT.AVAILPHYSICALFOUND < RESULT.AVAILPHYSICALRESULT THEN RESULT.AVAILPHYSICALFOUND ELSE RESULT.AVAILPHYSICALRESULT END),
# SUM(CASE WHEN RESULT.AVAILORDEREDFOUND < RESULT.AVAILORDEREDRESULT THEN RESULT.AVAILORDEREDFOUND ELSE RESULT.AVAILORDEREDRESULT END),
# SUM(FOUND.AVAILPHYSICAL),
# SUM(FOUND.AVAILORDERED),
# @LEVEL + -1,
# RESULT.CONFIGID AS CONFIGID,
# RESULT.INVENTSIZEID AS INVENTSIZEID,
# RESULT.INVENTCOLORID AS INVENTCOLORID,
# RESULT.INVENTSTYLEID AS INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN RESULT.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN RESULT.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN RESULT.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN RESULT.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN RESULT.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN RESULT.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN RESULT.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN RESULT.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN RESULT.INVENTGTDID_RU ELSE NULL END
#FROM @RESULT RESULT
#LEFT OUTER JOIN (
#SELECT SUM(DIMLIST.AVAILPHYSICAL) AS AVAILPHYSICAL,
# SUM(DIMLIST.AVAILORDERED) AS AVAILORDERED,
# INVENTDIM.CONFIGID AS CONFIGID,
# INVENTDIM.INVENTSIZEID AS INVENTSIZEID,
# INVENTDIM.INVENTCOLORID AS INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID AS INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END AS INVENTSITEID,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END AS INVENTLOCATIONID,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END AS WMSLOCATIONID,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END AS WMSPALLETID,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END AS INVENTSTATUSID,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END AS LICENSEPLATEID,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END AS INVENTBATCHID,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END AS INVENTSERIALID,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END AS INVENTPROFILEID_RU,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END AS INVENTOWNERID_RU,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END AS INVENTGTDID_RU
#FROM INVENTDIM INVENTDIM
#JOIN @DIMLIST DIMLIST
# ON INVENTDIM.PARTITION = @PARTITION
# AND INVENTDIM.DATAAREAID = @DATAAREAID
# AND INVENTDIM.INVENTDIMID = DIMLIST.INVENTDIMID
#GROUP BY
# INVENTDIM.CONFIGID,
# INVENTDIM.INVENTSIZEID,
# INVENTDIM.INVENTCOLORID,
# INVENTDIM.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN INVENTDIM.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN INVENTDIM.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN INVENTDIM.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN INVENTDIM.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN INVENTDIM.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN INVENTDIM.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN INVENTDIM.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN INVENTDIM.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN INVENTDIM.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN INVENTDIM.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN INVENTDIM.INVENTGTDID_RU ELSE NULL END
# ) AS FOUND ON (RESULT.CONFIGID = FOUND.CONFIGID)
# AND (RESULT.INVENTSIZEID = FOUND.INVENTSIZEID)
# AND (RESULT.INVENTCOLORID = FOUND.INVENTCOLORID)
# AND (RESULT.INVENTSTYLEID = FOUND.INVENTSTYLEID)
# AND (@LEVEL + -1 < @INVENTSITEIDLEVEL OR RESULT.INVENTSITEID = FOUND.INVENTSITEID)
# AND (@LEVEL + -1 < @INVENTLOCATIONIDLEVEL OR RESULT.INVENTLOCATIONID = FOUND.INVENTLOCATIONID)
# AND (@LEVEL + -1 < @WMSLOCATIONIDLEVEL OR RESULT.WMSLOCATIONID = FOUND.WMSLOCATIONID)
# AND (@LEVEL + -1 < @WMSPALLETIDLEVEL OR RESULT.WMSPALLETID = FOUND.WMSPALLETID)
# AND (@LEVEL + -1 < @INVENTSTATUSIDLEVEL OR RESULT.INVENTSTATUSID = FOUND.INVENTSTATUSID)
# AND (@LEVEL + -1 < @LICENSEPLATEIDLEVEL OR RESULT.LICENSEPLATEID = FOUND.LICENSEPLATEID)
# AND (@LEVEL + -1 < @INVENTBATCHIDLEVEL OR RESULT.INVENTBATCHID = FOUND.INVENTBATCHID)
# AND (@LEVEL + -1 < @INVENTSERIALIDLEVEL OR RESULT.INVENTSERIALID = FOUND.INVENTSERIALID)
# AND (@LEVEL + -1 < @INVENTPROFILEID_RULEVEL OR RESULT.INVENTPROFILEID_RU = FOUND.INVENTPROFILEID_RU)
# AND (@LEVEL + -1 < @INVENTOWNERID_RULEVEL OR RESULT.INVENTOWNERID_RU = FOUND.INVENTOWNERID_RU)
# AND (@LEVEL + -1 < @INVENTGTDID_RULEVEL OR RESULT.INVENTGTDID_RU = FOUND.INVENTGTDID_RU)
#WHERE RESULT.HIERARCHYLEVEL = @LEVEL
#GROUP BY
# RESULT.CONFIGID,
# RESULT.INVENTSIZEID,
# RESULT.INVENTCOLORID,
# RESULT.INVENTSTYLEID,
# CASE WHEN @LEVEL + -1 >= @INVENTSITEIDLEVEL THEN RESULT.INVENTSITEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTLOCATIONIDLEVEL THEN RESULT.INVENTLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSLOCATIONIDLEVEL THEN RESULT.WMSLOCATIONID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @WMSPALLETIDLEVEL THEN RESULT.WMSPALLETID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSTATUSIDLEVEL THEN RESULT.INVENTSTATUSID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @LICENSEPLATEIDLEVEL THEN RESULT.LICENSEPLATEID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTBATCHIDLEVEL THEN RESULT.INVENTBATCHID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTSERIALIDLEVEL THEN RESULT.INVENTSERIALID ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTPROFILEID_RULEVEL THEN RESULT.INVENTPROFILEID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTOWNERID_RULEVEL THEN RESULT.INVENTOWNERID_RU ELSE NULL END,
# CASE WHEN @LEVEL + -1 >= @INVENTGTDID_RULEVEL THEN RESULT.INVENTGTDID_RU ELSE NULL END;
#
#
# SET @LEVEL = @LEVEL - 1
#END; -- WHILE
#
#SELECT @AVAILPHYSICAL = SUM(CASE WHEN AVAILPHYSICALFOUND < AVAILPHYSICALRESULT THEN AVAILPHYSICALFOUND ELSE AVAILPHYSICALRESULT END),
# @AVAILORDERED = SUM(CASE WHEN AVAILORDEREDFOUND < AVAILORDEREDRESULT THEN AVAILORDEREDFOUND ELSE AVAILORDEREDRESULT END)
#FROM @RESULT
#WHERE HIERARCHYLEVEL = 0;
# */
#
# ret += strFmt('CREATE PROCEDURE [%1]\n', WhsOnHandSPHelper::storedProcedureName(_includeDelta));
# ret += ' @PARTITION bigint,\n';
# ret += strFmt(' %1 int,\n', this.levelExpression(0));
# ret += strFmt(' @DATAAREAID %1,\n', this.sqlTypeNameForField(tableNum(InventTable), fieldNum(InventTable, DataAreaId)));
# ret += strFmt(' @ITEMID %1,\n', this.sqlTypeNameForField(tableNum(InventTable), fieldNum(InventTable, ItemId)));
# if (_includeDelta)
# {
# ret += strFmt(' %1 %2,\n', #TTSIdParmName, this.sqlTypeNameForField(tableNum(WHSInventReserveDelta), fieldNum(WHSInventReserveDelta, TTSId)));
# }
#
# // Generate parameters for supported dimensions
# enabledDimsEnumerator.reset();
# while (enabledDimsEnumerator.moveNext())
# {
# [dimFieldId, dimFieldName] = enabledDimsEnumerator.current();
# ret += strFmt(' %1 %2 = NULL,\n', this.dimensionParm(dimFieldName), this.sqlTypeNameForField(tableNum(InventDim), dimFieldId));
# ret += strFmt(' %1 int = %2,\n', this.dimensionLevelParm(dimFieldName), #INVALIDHIERARCHYLEVEL);
# }
#
# // Generate parameters for product dimensions
# productDimensionsEnumerator.reset();
# while (productDimensionsEnumerator.moveNext())
# {
# [dimFieldId, dimFieldName] = productDimensionsEnumerator.current();
# ret += strFmt(' %1 %2 = NULL,\n', this.dimensionParm(dimFieldName), this.sqlTypeNameForField(tableNum(InventDim), dimFieldId));
# }
#
# ret += ' -- Output parameters\n';
# ret += strFmt(' %1 numeric(32, 16) OUTPUT,\n', #AvailPhysicalParmName);
# ret += strFmt(' %1 numeric(32, 16) OUTPUT\n', #AvailOrderedParmName);
# ret += 'AS\n\n';
#
# ret += '-- Without nocount on the procedure will return number of affected rows in the result set which is\n';
# ret += '-- harmful to performance and requires us to adjust field retrieval when calling the stored procedure\n';
# ret += 'SET NOCOUNT ON;\n\n';
#
# ret += '-- We need to supress warnings when trying to aggregate NULL columns. This is a valid business scenario\n';
# ret += '-- and happens e.g. for a non-LP controlled location with batch below item.\n';
# ret += 'SET ANSI_WARNINGS OFF;\n\n';
#
# ret += this.declareResultTableVariable() + '\n';
#
# ret += 'DECLARE @DIMLIST TABLE(\n';
# ret += ' INVENTDIMID nvarchar (20) NULL,\n';
# ret += ' AVAILPHYSICAL numeric(32, 16) NOT NULL,\n';
# ret += ' AVAILORDERED numeric(32, 16) NOT NULL);\n\n';
#
# ret += '-- The algorithm of the stored procedure is as follows:\n';
# ret += '-- 1. Initialize the @RESULT table with aggregated qtys in WHSInventReserve for the level requested by user\n';
# ret += '-- 2. Traverse the hierarchy up and for each level:\n';
# ret += '-- 1) Aggregate qtys from previous level in @RESULT grouping by dimensions of current hierarchy level\n';
# ret += '-- 2) Aggregate qtys from current level in WHSInventReserve grouping by dimensions of current hierarchy level\n';
# ret += '-- 3) Select the minimum of the above qtys and insert into @RESULT\n';
# ret += '-- 3. When hierarchy level 0 is reached, return the sum of aggregated qtys in @RESULT\n\n';
#
# ret += '-- In the original query (the one after below query), it is joining InventDim and WHSInventReserve and filter records based on some criteria.\n';
# ret += '-- But in the execution plan, it doesn\'t seems to generate a good plan (even after UPDATE STATISTICS). In the original execution plan, it always\n';
# ret += '-- Get records from InventDim first, which returns lot of rows, then only join it to WHSInventReserve and continue filter from there.\n';
# ret += '-- If we makes it get records from WHSInventReserve first, filter it, then with lesser rows from here, join it to InventDim, it will be quicker.\n';
# ret += '-- So the optimization is to filter WHSInventResreve first, then use this result at the original query. In the test, this has reduce the execution\n';
# ret += '-- time from ~250ms to ~7ms\n';
# ret += ' INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)\n';
# ret += ' SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED\n';
# ret += strFmt(' FROM %1 %2\n', this.whsInventReserveTableName(_includeDelta), inventReserveAlias);
# ret += strFmt(' WHERE %1.ITEMID = @ITEMID\n', inventReserveAlias);
# ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n', inventReserveAlias);
# ret += strFmt(' AND %1.HIERARCHYLEVEL = %2\n\n', inventReserveAlias, this.levelExpression(0));
#
# ret += '-- Initialize the @RESULT variable.\n';
# ret += '-- Loads aggregated data for the lowest level requested by user.\n';
# ret += 'INSERT INTO @RESULT (' + this.resultTableVariableFields() + ')\n';
#
# ret += this.selectFromWHSInventReserveStmt(_includeDelta) + '\n';
#
# ret += strFmt('WHILE (%1 > 0)\n', this.levelExpression(0));
# ret += 'BEGIN\n';
#
# ret += strFmt(' DELETE FROM @DIMLIST\n\n');
#
# ret += strFmt(' INSERT INTO @DIMLIST(INVENTDIMID, AVAILPHYSICAL, AVAILORDERED)\n');
# ret += strFmt(' SELECT INVENTDIMID, AVAILPHYSICAL, AVAILORDERED\n');
# ret += strFmt(' FROM %1 %2\n', this.whsInventReserveTableName(_includeDelta), inventReserveAlias);
# ret += strFmt(' WHERE %1.HIERARCHYLEVEL = %2 + -1\n', inventReserveAlias, this.levelExpression(0));
# ret += strFmt(' AND %1.ITEMID = @ITEMID\n', inventReserveAlias);
# ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n\n', inventReserveAlias);
#
# ret += strFmt(' INSERT INTO @RESULT (%1)\n', this.resultTableVariableFields());
#
# ret += this.selectFromResultJoinWHSInventReserveStmt(_includeDelta) + '\n\n';
#
# ret += strFmt(' SET %1 = %1 - 1\n', this.levelExpression(0));
# ret += 'END; -- WHILE\n\n';
#
# ret += strFmt('SELECT %1 = SUM(CASE WHEN %2 < %3 THEN %2 ELSE %3 END),\n',
# #AvailPhysicalParmName,
# #AVAILPHYSICALFOUNDFieldName,
# #AVAILPHYSICALRESULTFieldName);
# ret += strFmt(' %1 = SUM(CASE WHEN %2 < %3 THEN %2 ELSE %3 END)\n',
# #AvailOrderedParmName,
# #AVAILORDEREDFOUNDFieldName,
# #AVAILORDEREDRESULTFieldName);
# ret += 'FROM @RESULT\n';
# ret += strFmt('WHERE %1 = 0;\n', #HIERARCHYLEVELFieldName);
#
# return ret;
#}
ENDSOURCE
SOURCE #TEC_selectFromWHSInventReserveStmt
#private str TEC_selectFromWHSInventReserveStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# ListEnumerator productDimsEnumerator = this.productDimensions().getEnumerator();
# str dimFieldName;
# str levelExpr = this.levelExpression(-1);
# str inventReserveAlias = this.whsInventReserveTableAlias(_includeDelta);
# str dimList = 'DIMLIST';
# boolean hasDoneFirstIteration;
#
# ret += strFmt('SELECT SUM(%1.AVAILPHYSICAL),\n', dimList);
# ret += strFmt(' SUM(%1.AVAILORDERED),\n', dimList);
# ret += ' NULL,\n';
# ret += ' NULL,\n';
# ret += strFmt(' %1,\n', this.levelExpression(0));
#
# // Select product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Select enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# this.levelExpression(-1),
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
#
# //ret += strFmt(' FROM %1 %2\n', this.whsInventReserveTableName(_includeDelta), inventReserveAlias);
# //ret += strFmt(' JOIN INVENTDIM ON INVENTDIM.INVENTDIMID = %1.INVENTDIMID AND INVENTDIM.DATAAREAID = %1.DATAAREAID AND INVENTDIM.PARTITION = %1.PARTITION\n', inventReserveAlias);
# //ret += strFmt(' WHERE %1.ITEMID = @ITEMID\n', inventReserveAlias);
# //ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# //ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n', inventReserveAlias);
# //ret += strFmt(' AND %1.HIERARCHYLEVEL = %2\n', inventReserveAlias, this.levelExpression(0));
# ret += strFmt(' FROM INVENTDIM INVENTDIM\n');
# ret += strFmt(' JOIN @DIMLIST %1\n', dimList);
# ret += strFmt(' ON INVENTDIM.INVENTDIMID = %1.INVENTDIMID\n', dimList);
# ret += strFmt(' WHERE INVENTDIM.DATAAREAID = @DATAAREAID\n');
# ret += strFmt(' AND INVENTDIM.PARTITION = @PARTITION\n');
#
# // Add product dimensions range
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' AND (%2 IS NULL OR INVENTDIM.%1 = %2)\n',
# dimFieldName,
# this.dimensionParm(dimFieldName));
# }
#
# // Add enabled dimensions range
# enabledDimsEnumerator.reset();
# while (enabledDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' AND (%1 < %2 OR %3 IS NULL OR %3 = INVENTDIM.%4)\n',
# this.levelExpression(0),
# this.dimensionLevelParm(dimFieldName),
# this.dimensionParm(dimFieldName),
# dimFieldName);
# }
#
# ret += 'GROUP BY\n';
#
# // Add grouping by product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Add grouping by enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# this.levelExpression(-1),
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
#
# ret += ';\n';
#
# return ret;
#}
ENDSOURCE
SOURCE #TEC_selectInnerFromWHSInventReserveStmt
#private str TEC_selectInnerFromWHSInventReserveStmt(boolean _includeDelta)
#{
# str ret = '';
# ListEnumerator enabledDimsEnumerator = this.enabledDimensions().getEnumerator();
# ListEnumerator productDimsEnumerator = this.productDimensions().getEnumerator();
# str dimFieldName;
# str levelExpr = this.levelExpression(-1);
# str inventReserveAlias = this.whsInventReserveTableAlias(_includeDelta);
# str dimList = 'DIMLIST';
# boolean hasDoneFirstIteration;
#
# ret += strFmt('SELECT SUM(%1.AVAILPHYSICAL) AS AVAILPHYSICAL,\n', dimList);
# ret += strFmt(' SUM(%1.AVAILORDERED) AS AVAILORDERED,\n', dimList);
#
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1 AS %1,\n', dimFieldName);
# }
#
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END AS %3',
# levelExpr,
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
#
# //ret += strFmt('FROM %1 %2\n', this.whsInventReserveTableName(includeDelta), inventReserveAlias);
# //ret += strFmt('JOIN INVENTDIM ON INVENTDIM.PARTITION = %1.PARTITION\n', inventReserveAlias);
# //ret += strFmt(' AND INVENTDIM.DATAAREAID = %1.DATAAREAID\n', inventReserveAlias);
# //ret += strFmt(' AND INVENTDIM.INVENTDIMID = %1.INVENTDIMID\n', inventReserveAlias);
# //ret += strFmt('WHERE %1.HIERARCHYLEVEL = %2\n', inventReserveAlias, levelExpr);
# //ret += strFmt(' AND %1.ITEMID = @ITEMID\n', inventReserveAlias);
# //ret += strFmt(' AND %1.PARTITION = @PARTITION\n', inventReserveAlias);
# //ret += strFmt(' AND %1.DATAAREAID = @DATAAREAID\n', inventReserveAlias);
# ret += strFmt('FROM INVENTDIM INVENTDIM\n');
# ret += strFmt('JOIN @DIMLIST %1\n', dimList);
# ret += strFmt(' ON INVENTDIM.PARTITION = @PARTITION\n');
# ret += strFmt(' AND INVENTDIM.DATAAREAID = @DATAAREAID\n');
# ret += strFmt(' AND INVENTDIM.INVENTDIMID = DIMLIST.INVENTDIMID\n');
# ret += 'GROUP BY\n';
#
# // Add groupping by product dimensions
# productDimsEnumerator.reset();
# while (productDimsEnumerator.moveNext())
# {
# dimFieldName = conPeek(productDimsEnumerator.current(), 2);
# ret += strFmt(' INVENTDIM.%1,\n', dimFieldName);
# }
#
# // Add groupping by enabled dimensions
# enabledDimsEnumerator.reset();
# hasDoneFirstIteration = false;
# while (enabledDimsEnumerator.moveNext())
# {
# if (hasDoneFirstIteration)
# {
# ret += ',\n';
# }
#
# dimFieldName = conPeek(enabledDimsEnumerator.current(), 2);
# ret += strFmt(' CASE WHEN %1 >= %2 THEN INVENTDIM.%3 ELSE NULL END',
# levelExpr,
# this.dimensionLevelParm(dimFieldName),
# dimFieldName);
#
# hasDoneFirstIteration = true;
# }
# ret += '\n';
#
# return ret;
#}
ENDSOURCE
ENDMETHODS
ENDCLASS
***Element: END
=================================================
This comment has been removed by a blog administrator.
ReplyDelete