elroyskimms
Member
- Joined
- Jul 10, 2015
- Messages
- 19
- Programming Experience
- 10+
I'm having trouble wrapping my head around Recursive CTE's in SQL Server. My dataset (simplified version below for copy/paste) is a large table containing hundreds of thousands of chains. Each chain is made up of a number of components, linked together in a specific order for each chain. I've added both a ParentID column AND a DisplayOrder column to the table. I can keep one or both of those columns as needed.
The goal is to take a 2[SUP]nd[/SUP] list of chains (input) and search/compare them to the existing chains. The input chains can be 1 component chains or they can be multiple components linked together in a specific order. The end results need to show which chains in the main table contain matches for the input chains, and they must match the components in the same order.
If Chain #1 in the table is A, B, C, D, E and I am searching for B, it will match. If I am searching for C, D, E, it will also match. But if I am searching for A, C, D, it will not match as the input chain is not the same order as the chain in the table. I also want to be able to use multiple chains in the input at once. So I can search for B and B, C, D and also A, C, D at the same time and generate the results.
I have a solution already for this using a recursive function in VB.Net which grabs each match where the ParentID = 0 (start of a chain) and then navigates down each chain until it reaches the end OR it finds something that doesn't match. It's more or less a brute force procedural solution. It works, but it handles one chain at a time. That's not very efficient when matching a list of 30,000 chains on the input and 500,000 chains in the database table. I can also do this with an SQL Cursor, but again, that's a very procedural solution. I'm hoping to find a Recursive CTE that will be more efficient and allow me to search multiple input chains at the same time, rather than iterating through each input chain individually. Inline table functions might as well be sorcery to me. This is not my area of expertise. Any help would be greatly appreciated.
-E
Copy/Paste
The goal is to take a 2[SUP]nd[/SUP] list of chains (input) and search/compare them to the existing chains. The input chains can be 1 component chains or they can be multiple components linked together in a specific order. The end results need to show which chains in the main table contain matches for the input chains, and they must match the components in the same order.
If Chain #1 in the table is A, B, C, D, E and I am searching for B, it will match. If I am searching for C, D, E, it will also match. But if I am searching for A, C, D, it will not match as the input chain is not the same order as the chain in the table. I also want to be able to use multiple chains in the input at once. So I can search for B and B, C, D and also A, C, D at the same time and generate the results.
I have a solution already for this using a recursive function in VB.Net which grabs each match where the ParentID = 0 (start of a chain) and then navigates down each chain until it reaches the end OR it finds something that doesn't match. It's more or less a brute force procedural solution. It works, but it handles one chain at a time. That's not very efficient when matching a list of 30,000 chains on the input and 500,000 chains in the database table. I can also do this with an SQL Cursor, but again, that's a very procedural solution. I'm hoping to find a Recursive CTE that will be more efficient and allow me to search multiple input chains at the same time, rather than iterating through each input chain individually. Inline table functions might as well be sorcery to me. This is not my area of expertise. Any help would be greatly appreciated.
-E
Copy/Paste
VB.NET:
DECLARE @Chains TABLE (ID int, Component varchar(20), ParentID int, DisplayOrder int, ChainID int)
DECLARE @SearchChains TABLE (Component varchar(20), DisplayOrder int, GroupID int)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (1, 'Head bone', 0, 0, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (2, 'Neck bone', 1, 1, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (3, 'Shoulder bone', 2, 2, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (4, 'Back bone', 3, 3, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (5, 'Hip bone', 4, 4, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (6, 'Thigh bone', 5, 5, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (7, 'Knee bone', 6, 6, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (8, 'Shin bone', 7, 7, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (9, 'Ankle bone', 8, 8, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (10, 'Heel bone', 9, 9, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (11, 'Foot bone', 10, 10, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (12, 'Toe bone', 11, 11, 1)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (13, 'Knee bone', 0, 0, 2)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (14, 'Shin bone', 13, 1, 2)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (15, 'Head bone', 0, 0, 3)
INSERT INTO @Chains (ID, Component, ParentID, DisplayOrder, ChainID) VALUES (16, 'Toe bone', 15, 1, 3)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Head bone', 0, 1)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Neck bone', 1, 1)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Shoulder bone', 2, 1)
--Perform recursive search with 1 3-part chain
--Should only match ChainID 1
DELETE FROM @SearchChains
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Head bone', 0, 2)
--Perform recursive search with 1 1-part chain
--Should match both ChainID 1 and ChainID 3
DELETE FROM @SearchChains
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Shin bone', 0, 3)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Head bone', 0, 4)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Neck bone', 1, 4)
INSERT INTO @SearchChains(Component, DisplayOrder, GroupID) VALUES ('Shoulder bone', 2, 4)
--Perform recursive search with both 1-part and 3-part chains
--SearchChain GroupID 3 should match ChainID 1 and ChainID 2
--SearchChain GroupID 4 should match ChainID 1