Hierarchy trouble - sql

I have a set of data pulling from two joined tables that are built on joined tables, it ends up with a path/hierarchy that the data should sit under but the root folders aren't included because of the joins so getting the recursive hierarchy to work correctly isn't happening. One of the tables in the 1st round of joins actually has the full hierarchy clearly laid out but because entries for the root folders aren't used in tables that have been joined later the structure isn't there. Is there a way to get the full hierarchy back into the data for the folder structure?
I have also tried use the results from the first query below to build a recursive hierarchy using the ElementID and ParentElementID relationships in SSRS, and it works for the hierarchy levels 6 and 7 but it still looks flat for the rest, so level 8 stuff loses its parent folder and ends up at the bottom of all the children at level 6. Similar things are happening at other levels, but this always happens at level 8.
2nd level join statement. Ends up with EHLevel always 4-8:
SELECT ppd.tag
, ppd.descriptor
, ppd.instrumenttag
, afi.AFPath + '\' + afi.AFElement AS RelativePath
, afi.EHLevel
, afi.EHLevel + 1 AS TagLevel
, afi.PIServer
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 1, '\') AS [AFModel]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 2, '\') AS [Plant]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 3, '\') AS [Level3]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 4, '\') AS [Level4]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 5, '\') AS [Level5]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 6, '\') AS [Level6]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 7, '\') AS [Level7]
, MasterTagList.dbo.UFN_SEPARATES_COLUMNS(afi.RelativePath, 8, '\') AS [Level8]
, afi.ElementID
, afi.ParentElementID
, afi.AFPath
, afi.AFElement
, afi.AttributeName
, ppd.pointtypex
, ppd.engunits
, ppd.displaydigits
, ppd.digitalset
, ppd.zero
, ppd.span
, ppd.typicalvalue
, ppd.pointsource
, ppd.location1
, ppd.location2
, ppd.location3
, ppd.location4
, ppd.location5
, ppd.scan
, ppd.creationdate
, ppd.changedate
FROM [PIPointData] AS ppd
LEFT JOIN [AFInfo] AS afi ON afi.Tag = ppd.tag
First Level Table with full hierarchy (Levels 0-8)
SELECT [Path] -- This is the same as the AFPath above
,[Name] -- This is the same as the AFElement above
,[Level] -- This is the same as the EHLevel above
,[ElementID]
,[ParentElementID]
FROM [TAGAUSWARPIDEV02D].[IOPS US Devlopment Database].[Asset].[ElementHierarchy]

Related

Oracle get UNIQUE constraint violation error too late

What should I check why Oracle server takes more then 20 sec to return UNIQUE constraint violation error for specific data?
One of our processes is processing over 30000 data one day with multi process and some time gets UNIQUE constraint violation error in 1 sec
but it takes more then 20 sec to return UNIQUE constraint violation error for specific data.
Query is same as below. (Modified only table name)
MERGE
INTO TableA S
USING (
SELECT NVL(:sccm_cd , ' ') SCCM_CD
, NVL(:oder_dt , ' ') ODER_DT
, NVL(:mrkt_dstn_cd, ' ') MRKT_DSTN_CD
, NVL(:oder_no , ' ') ODER_NO
, NVL(:cncd_unpr , 0) CNCD_UNPR
, B.SLBY_FEE_GRD_CD
, B.ACCT_MNGR_EMPL_NO
, C.AO_FEE_GRD_CD
FROM DUAL A
, TableB B
, TableC C
WHERE 1 = 1
AND B.SCCM_CD = :sccm_cd
AND B.ACNO = :acno
AND C.SCCM_CD(+) = B.SCCM_CD
AND C.EMPL_NO(+) = B.ACCT_MNGR_EMPL_NO
) T
ON ( S.sccm_cd = T.sccm_cd
AND S.oder_dt = T.oder_dt
AND S.mrkt_dstn_cd = T.mrkt_dstn_cd
AND S.oder_no = T.oder_no
AND S.cncd_unpr = T.cncd_unpr
)
WHEN MATCHED THEN
UPDATE
SET S.cncd_qty = S.cncd_qty + NVL(:cncd_qty ,0)
, S.slby_fee = S.slby_fee + NVL(:slby_fee ,0)
, S.slby_fee_srtx = S.slby_fee_srtx + NVL(:slby_fee_srtx,0)
, S.idx_fee_amt = S.idx_fee_amt + NVL(:idx_fee_amt ,0)
, S.cltr_fee = S.cltr_fee + NVL(:cltr_fee ,0)
, S.trtx = S.trtx + NVL(:trtx ,0)
, S.otc_fee = S.otc_fee + NVL(:otc_fee ,0)
, S.wht_fee = S.wht_fee + NVL(:wht_fee ,0)
WHEN NOT MATCHED THEN
INSERT (
sccm_cd
, oder_dt
, mrkt_dstn_cd
, oder_no
, cncd_unpr
, acno
, item_cd
, slby_dstn_cd
, md_dstn_cd
, cncd_qty
, stlm_dt
, trtx_txtn_dstn_cd
, proc_cmpl_dstn_cd
, item_dstn_cd
, slby_fee_grd_cd
, slby_fee
, slby_fee_srtx
, idx_fee_amt
, cltr_fee
, trtx
, wht_fee
, otc_fee
, acct_mngr_empl_no
, ao_fee_grd_cd
)
VALUES
( T.sccm_cd
, T.oder_dt
, T.mrkt_dstn_cd
, T.oder_no
, T.cncd_unpr
, :acno
, :item_cd
, :slby_dstn_cd
, :md_dstn_cd
, NVL(:cncd_qty ,0)
, DECODE(:mrkt_dstn_cd, 'TN', T.oder_dt, :stlm_dt)
, :trtx_txtn_dstn_cd
, '0'
, :item_dstn_cd
, NVL(:slby_fee_grd_cd, T.SLBY_FEE_GRD_CD)
, NVL(:slby_fee ,0)
, NVL(:slby_fee_srtx ,0)
, NVL(:idx_fee_amt ,0)
, NVL(:cltr_fee ,0)
, NVL(:trtx ,0)
, NVL(:wht_fee , 0)
, NVL(:otc_fee , 0)
, T.acct_mngr_empl_no
, T.ao_fee_grd_cd
)
There could be multiple reasons for it. I will list here some of the possible causes for this behavior.
Concurrency issue
Your insert might be waiting for other operations, like other inserts or updated or deletions.
Network issues
It is possible that for some reason your network is overwhelmed with requests or, if the server is remote, this could be an internet speed issue as well.
Server load
The server might be overwhelmed with lots of jobs to do.
Slow query
It's also possible that the select you use in your insert command is very slow. It would make sense to test its speed. Also, it would make sense to test insert speed as well.

Oracle SQL Loader discarding data and showing NULL values ins

I have this issue with SQLLoader. I am working with a dataset with 99 columns. Everything is being loaded to a VARCHAR2(500 BYTE) - I went through the data manually to make sure there was enough space in each column.
CSV Properties
Comma delimited
Line terminated by CRLF
Text Qualifier '"'
The issue is, when I load the data manually (I use Toad for Oracle) - the data appears just fine. However, using my SQLLoader - it "successfully" loads all the data however when you query the table, the table has all the rows but all the data is missing. (Null values appear) - Can anyone help with this?
This is the ctl file code:
OPTIONS (direct=true)
LOAD DATA
INFILE 'C:\Paths\DATA_PRCS\MarketData\FitchRatings\DBUpload\test.csv'
DISCARDFILE 'C:\Paths\DATA_PRCS\MarketData\FitchRatings\DBUploadProcess\ErrorFiles\FitchIssue_Errors.csv'
TRUNCATE INTO TABLE MARKETDATA.PRLD_FITCH_ISSUE_DATA
fields terminated by "," OPTIONALLY ENCLOSED BY '"' trailing nullcols
(
REPORT_DATE_TIME
, AGENT_COMMON_ID
, AGENT_CUSIP
, AGENT_LEI
, CUSTOMER_IDENTIFIER
, MARKET_SECTOR_ID
, COUNTRY_NAME
, ISSUER_ID
, ISSUER_NAME
, ISSUE_RECORD_CHANGE_CODE_DATE
, FITCH_ISSUE_ID_NUMBER
, COUNTRY_CODE
, STATE_PROVINCE
, CUSIP_IDENTIFIER
, ISIN_IDENTIFIER
, ISMA_IDENTIFIER
, LOANX_ID
, COMMON_NUMBER
, WERTPAPIER_IDENTIFIER
, RECORD_GROUP_TYPE_CODE
, ISSUE_DEBT_LEVEL_CODE
, CLASS_TYPE
, ISSUE_DESCRIPTION
, ISSUE_MATURITY_DATE
, ISSUE_TRANCHE_SERIES
, ISSUE_CLASS
, ISSUE_CURRENCY_CODE
, ISSUE_AMOUNT
, ISSUE_COUPON_TYPE
, ISSUE_COUPON_FIXED_RATE
, ISSUE_COUP_NON_FIXED_RATE_DESC
, ISSUE_COUPON_INDEX_DESCRIPTION
, ISSUE_COUPON_SPREAD
, ISSUE_COUPON_CAPPED_RATE
, ENHANCEMENT_TYPE
, ENHANCEMENT_PROVIDER
, PROJECT
, PRIVATE_PLACEMENT_144A_CODE
, US_FED_TAX_EXEMPT_STATUS_CODE
, ISSUE_RECORD_CHANGE_CODE
, LT_ISSUE_RATING
, LT_ISSUE_RATING_ACTION
, LT_ISSUE_RATING_EFFECTIVE_DATE
, LT_ISSUE_RATING_ALERT_CODE
, LT_ISSUE_RATING_SOL_STATUS
, ISSUE_RECOVERY_RATING
, ISSUE_DISTRESSED_RECOV_RATING
, UNENHANCED_LT_ISSUE_RATING
, UNENHANCED_LTR_ACTION
, UNENHANCED_LTR_EFFECTIVE_DATE
, UNENHANCED_LTR_ALERT_CODE
, UNENHANCED_LTR_SOL_STATUS
, LT_NATIONAL_ISSUE_RATING
, LT_NATIONAL_RATING_ACTION
, LT_NATL_RATING_EFFECTIVE_DATE
, LT_NATIONAL_RATING_ALERT_CODE
, LT_NATIONAL_RATING_SOL_STATUS
, ST_ISSUE_RATING
, ST_ISSUE_RATING_ACTION
, ST_ISSUE_RATING_EFFECTIVE_DATE
, ST_ISSUE_RATING_ALERT_CODE
, ST_ISSUE_RATING_SOL_STATUS
, UNENHANCED_ST_ISSUE_RATING
, UNENHANCED_STR_ACTION
, UNENHANCED_STR_EFFECTIVE_DATE
, UNENHANCED_STR_ALERT_CODE
, UNENHANCED_STR_SOL_STATUS
, ST_NATIONAL_ISSUE_RATING
, ST_NATIONAL_RATING_ACTION
, ST_NATL_RATING_EFFECTIVE_DATE
, ST_NATIONAL_RATING_ALERT_CODE
, ST_NATIONAL_RATING_SOL_STATUS
, ENHANCED_LTR
, ENHANCED_LTR_ACTION
, ENHANCED_LTR_EFFECTIVE_DATE
, ENHANCED_LTR_ALERT_CODE
, ENHANCED_LTR_SOL_STATUS
, ENHANCED_STR
, ENHANCED_STR_ACTION
, ENHANCED_STR_EFFECTIVE_DATE
, ENHANCED_STR_ALERT_CODE
, ENHANCED_STR_SOL_STATUS
, SECURITY_IDENTIFIER_TYPE
, ENDORSEMENT_COMPLIANCE
, RATINGS_SUFFIX
, CLO_SECTOR
, CLO_INDUSTRY
, ALTERNATE_CUSIP
, ALTERNATE_ISIN
, DATA_ENTRY_TIMESTAMP expression "(select SYSDATE from dual)"
)
Rather simple in the end. The most important thing to realize was that the file was using Unicode characters. You have to specify in the ctl file CHARACTERSET UT16 in this example. Thank for trying to help all!
load data CHARACTERSET UTF8 TRUNCATE INTO TABLE "GLOBALIZATIONRESOURCE" FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"' TRAILING NULLCOLS

How to find errors in nested SELECT request in SQL?

I want to make a sum on field created using different columns of my table so I have make 2 nested SELECT.
My nested SELECT works good alone, but when I put it inside the other one I show errors and I can't find them out
I've tested my nested SELECT and it works.
DECLARE #Debut datetime ='2019-03-18'
DECLARE #Fin datetime = '2019-03-31'
SELECT Secteur,
Site_Theo,
Techno,
SUM(Trafic) as Trafic_Hebdo
FROM (
SELECT [TRAFIC_VOIX_HEBDO].Trafic_voix as Trafic ,
[INFO_CELL_N].SITE_THEO,
[INFO_CELL_N].TECHNO,
CONCAT('A' , right(SITE_THEO,5) , REPLACE( REPLACE( REPLACE( right([TRAFIC_VOIX_HEBDO].Cellname, 1) , 'D' , 'A' ) , 'E' , 'B' ) , 'F' , 'C' ) ) as Secteur
FROM [KIWI].[dbo].[TRAFIC_VOIX_HEBDO] INNER JOIN [KIWI].[dbo].[INFO_CELL_N]
ON [KIWI].[dbo].[TRAFIC_VOIX_HEBDO].Cellname = [KIWI].[dbo].[INFO_CELL_N].CELLNAME
WHERE ( right([TRAFIC_VOIX_HEBDO].cellname,1)='A' OR
right([TRAFIC_VOIX_HEBDO].cellname,1)='B' OR
right([TRAFIC_VOIX_HEBDO].cellname,1)='C' OR
right([TRAFIC_VOIX_HEBDO].cellname,1)='D' OR
right([TRAFIC_VOIX_HEBDO].cellname,1)='E' OR
right([TRAFIC_VOIX_HEBDO].cellname,1)='F' )
AND ( [TRAFIC_VOIX_HEBDO].TSTAMP BETWEEN #Debut AND #Fin )
)
GROUP BY Secteur, Site_Teho, Techno
Error Message:
Msg 156, Level 15, State 1, Line 34 Incorrect syntax near the keyword
'GROUP'.
I would like to understand why I have errors.
To me the code looks good
Give a ALIAS to you sub query as -
SELECT ....
FROM (
SELECT...
)A -- A is the alias
GROUP BY Secteur, Site_Teho, Techno
Secondly, you can write your WHERE as below-
WHERE RIGHT([TRAFIC_VOIX_HEBDO].cellname, 1) IN ( 'A','B','C','D','E','F')
AND [TRAFIC_VOIX_HEBDO].TSTAMP BETWEEN #Debut AND #Fin
A derived table must have a name - provide it immediately after the closing parenthesis and before "group by ".
select Secteur,
...
from ( SELECT [TRAFIC_VOIX_HEBDO].Trafic_voix as Trafic ,
...
) as usefulnamehere
group by Secteur, Site_Teho, Techno
order by ...;

Having Trouble with FOR XML Path - No Concatenating

I have a situation where an order can contain multiple license purchases - and if the order does contain multiple licenses, I want to display the license descriptions in a single cell with the values separated by commas. If we were on SQL 2017, I could use STRING_AGG but we are on SQL 2016 so I am trying the tried and true STUFF / FOR XML Path method.
From the screenshot below, Customer 4341073 had two license purchases on Order ID 18519173:
When I add the STUFF / FOR XML Path to the T-SQL, I am not able to achieve the desired result of showing the license description in the same record - each license still has it's own row.
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM dbo.LicenseTypes AS lt
--INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
WHERE lt.id = x.OrderLicenseTypeID
--GROUP BY ',' + lt.description
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
--GROUP BY x.CustomerID ,
-- x.ATOLicenseTypeID ,
-- x.ATOLicense ,
-- x.AuthorizationBeginDate ,
-- x.AuthorizationEndDate ,
-- x.OrderID ,
-- x.OrderDate ,
-- x.OrderLicenseTypeID;
I've tried different ways to join the sub-query to the outer query and added and removed GROUP BY to achieve the desired result but nothing is working for me.
Any suggestions on where I am going wrong with this query?
Sample dataset:
DROP TABLE IF EXISTS #XMLPATH;
CREATE TABLE #XMLPATH
(
CustomerID INT ,
ATOLicenseTypeID INT ,
ATOLicense VARCHAR (500) ,
AuthorizationBeginDate DATE ,
AuthorizationEndDate DATE ,
OrderID INT ,
OrderDate DATETIME ,
OrderLicenseTypeID INT
);
INSERT INTO #XMLPATH
VALUES ( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519136, N'2019-01-07T12:01:55.317', 2141 ) ,
( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 204 ) ,
( 4341073, 52, 'Temporary Resident Fishing', N'2019-01-07T00:00:00', N'2019-01-07T00:00:00', 18519173, N'2019-01-07T12:34:13.107', 2141 );
SELECT * FROM #XMLPATH;
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM dbo.LicenseTypes AS lt
--INNER JOIN #XMLPATH ON lt.id = x.OrderLicenseTypeID
WHERE lt.id = x.OrderLicenseTypeID
--GROUP BY ',' + lt.description
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
GROUP BY x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
x.OrderLicenseTypeID;
In order to get all rows of one OrderID as one result-row, you must not include the separating information (the OrderLicenseTypeID) into the GROUP BY. But then you have the issue you've encountered: You cannot use this ID within your FOR XML construct.
The trick is (as your out-commented trials show), to add the source table to the sub-select and filter there with a grouped column. But you have to use different aliases to deal with them as two different sets. Try this:
(I had to add one more temp table to test this...)
SELECT x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate ,
STUFF ( (
SELECT ',' + lt.description
FROM #XMLPATH x2
INNER JOIN #LicenseTypes AS lt ON lt.id=x2.OrderLicenseTypeID
WHERE x2.OrderID = x.OrderID --you might need to add more columns here....
--in most cases we want to add an ORDER BY
FOR XML PATH ( '' )
) , 1 , 1 , '' ) AS Licenses
FROM #XMLPATH AS x
GROUP BY x.CustomerID ,
x.ATOLicenseTypeID ,
x.ATOLicense ,
x.AuthorizationBeginDate ,
x.AuthorizationEndDate ,
x.OrderID ,
x.OrderDate;
Btw: Starting with v2017 there is STRING_AGG(), which makes this much easier...

Stop Recursion Once Condition Satisfied

I am using a CTE to explode out a Bill of Materials and need to locate all those materials that have recursive components.
What I was attempting, was to limit the number of cycles (levels) deep, by setting BOM_Level in the child node to a maximum bound:
exec pr_sys_drop_object '#BOMExploded'
;with BOM
as
(
select
Prod_Plant_CD
, Demand_Plant_CD
, material_cd
, component_cd
, component_quantity
, component_quantity AS Calculated_Component_Quantity
, BOM_Level
, Demand_Quantity
, CONVERT(float,1) AS Produced_Ratio
, Material_CD AS Demand_Material_CD
from #firstLevel a
UNION ALL
SELECT
b.Plant_CD as 'Prod_Plant_CD'
, a.Demand_Plant_CD
, b.Material_CD
, b.Component_CD
, b.component_quantity
, b.component_quantity
, a.BOM_Level + 1
, a.Demand_Quantity
, a.Produced_Ratio * a.Component_Quantity -- Produced Quantity for the current level = Produced Quantity (level -1) * Component_Quantity (level -1)
, a.Demand_Material_CD
FROM BOM a
inner join #BOM_ProdVersion_Priority b
on a.component_cd = b.material_cd
inner join #base_routes c
on a.Demand_Plant_CD = c.Recipient_Plant_CD
and b.Plant_CD = c.Source_Plant_CD
and c.Material_CD = b.Material_CD -- Need to have material_cd to link
where b.Material_CD != b.Component_CD
and b.Component_Quantity > 0
and BOM_Level < 5 -- Give the max number of levels deep we are allowed to cyncle to
)
select *
into #BOMExploded
from BOM
OPTION (MAXRECURSION 20)
Using this method however, would require a post-process to locate when the cycling on the recursive component level started, then back trace.
How can a CTE recursive query be stopped given a certain condition?
ie. when top-level material_cd = component_cd for a deeper BOM_Level
If I understand you correctly, you don't need to stop at a certain depth/level, or rather you want to stop at a certain level, but you also need to stop in case you start cycling through materials repeatedly.
In the case of the following recursive path: mat_1->mat_2->mat_3->mat_1, you would want to stop before that last mat_1 starts cycling again to mat_2 and so on.
If that's correct, then your best bet is to add a Path field to your recursive query that tracks each term that it finds as it moves down the recursive path:
exec pr_sys_drop_object '#BOMExploded'
;with BOM
as
(
select
Prod_Plant_CD
, Demand_Plant_CD
, material_cd
, component_cd
, component_quantity
, component_quantity AS Calculated_Component_Quantity
, BOM_Level
, Demand_Quantity
, CONVERT(float,1) AS Produced_Ratio
, Material_CD AS Demand_Material_CD
, CAST(material_cd AS VARCHAR(100)) AS Path
from #firstLevel a
UNION ALL
SELECT
b.Plant_CD as 'Prod_Plant_CD'
, a.Demand_Plant_CD
, b.Material_CD
, b.Component_CD
, b.component_quantity
, b.component_quantity
, a.BOM_Level + 1
, a.Demand_Quantity
, a.Produced_Ratio * a.Component_Quantity -- Produced Quantity for the current level = Produced Quantity (level -1) * Component_Quantity (level -1)
, a.Demand_Material_CD
, a.Path + '|' + b.material_cd
FROM BOM a
inner join #BOM_ProdVersion_Priority b
on a.component_cd = b.material_cd
inner join #base_routes c
on a.Demand_Plant_CD = c.Recipient_Plant_CD
and b.Plant_CD = c.Source_Plant_CD
and c.Material_CD = b.Material_CD -- Need to have material_cd to link
where b.Material_CD != b.Component_CD
and b.Component_Quantity > 0
and BOM_Level < 5 -- Give the max number of levels deep we are allowed to cyncle to
and a.path NOT LIKE '%' + b.material_cd + '%'
)
select *
into #BOMExploded
from BOM
OPTION (MAXRECURSION 20)
Now you have a path that is pipe delimited and you can test your current material_cd to see if it's already in the path. If it is, then you end that leg of the recursion to prevent cycling.
Updating to include a version where we capture material_cd cycles and only report those at the end of the recursion:
exec pr_sys_drop_object '#BOMExploded'
;with BOM
as
(
select
Prod_Plant_CD
, Demand_Plant_CD
, material_cd
, component_cd
, component_quantity
, component_quantity AS Calculated_Component_Quantity
, BOM_Level
, Demand_Quantity
, CONVERT(float,1) AS Produced_Ratio
, Material_CD AS Demand_Material_CD
, CAST(material_cd AS VARCHAR(100)) AS Path
, CAST(NULL AS CHAR(5)) as Cycle_Flag
, 0 as Cycle_Depth
from #firstLevel a
UNION ALL
SELECT
b.Plant_CD as 'Prod_Plant_CD'
, a.Demand_Plant_CD
, b.Material_CD
, b.Component_CD
, b.component_quantity
, b.component_quantity
, a.BOM_Level + 1
, a.Demand_Quantity
, a.Produced_Ratio * a.Component_Quantity -- Produced Quantity for the current level = Produced Quantity (level -1) * Component_Quantity (level -1)
, a.Demand_Material_CD
, a.Path + '|' + b.material_cd
, CASE WHEN a.path NOT LIKE '%' + b.material_cd + '%' then 'Cycle' END AS Cycle_Flag,
, CASE WHEN a.path NOT LIKE '%' + b.material_cd + '%' then a.Cycle_Depth + 1 END as Cycle_Depth
FROM BOM a
inner join #BOM_ProdVersion_Priority b
on a.component_cd = b.material_cd
inner join #base_routes c
on a.Demand_Plant_CD = c.Recipient_Plant_CD
and b.Plant_CD = c.Source_Plant_CD
and c.Material_CD = b.Material_CD -- Need to have material_cd to link
where b.Material_CD != b.Component_CD
and b.Component_Quantity > 0
and a.cycle_depth < 2 --stop the query if we start cycling, but only after we capture at least one full cycle
)
select *
into #BOMExploded
from BOM
WHERE cycle_flag IS NOT NULL
OPTION (MAXRECURSION 20)
This will capture cycle_depth which is a counter that measures how deep into a cycle we get. We stop the recursion after we get to cycle_depth of 1 so the cycle can be captures in the final select.