0

I have the following example table:

customer data

Each customer_number may have one or several debtor_id, and vice versa each debtor_id may have one or more customer_numbers. Now I basically need a way to retrieve all customer_numbers or debtor_ids from any given customer_number or debtor_id

A more specific example:

Say you want to know all customer_numbers that are connected to the debtor_id 24.

  • Step1: debtor_id 24 is connected to customer_number customer12
  • Step2: customer_number customer12 is connected to debtor_id 23 and 24 (the starting point)
  • Step3: debtor_id 23 is connected to customer_number customer12 and customer11
  • Step4: customer_number customer11 is connected to debtor_id 22 and 23 etc.

So in the end when inputting the debtor_id 24, you'd expect to retrieve the customer_number customer10, customer11 and customer12 as a result.

I know it'll probably require several self-joins, but it needs to be flexible and work dynamically for any given "depth". My first thought was that this heavily smells like recursion. Basically something like "keep self-joining until there are no new customer_numbers or debtor_id returned"

I don't have much experience with recursion, same goes for writing SQL Functions :-(

Does anybody have some tips or helpful advice on this?

Example code to generate the same table:

DECLARE @customers TABLE
                   (
                       customer_number VARCHAR(16),
                       debtor_id INT
                   );

INSERT INTO @customers SELECT 'customer10', 20;
INSERT INTO @customers SELECT 'customer10', 22;
INSERT INTO @customers SELECT 'customer11', 22;
INSERT INTO @customers SELECT 'customer11', 23;
INSERT INTO @customers SELECT 'customer12', 23;
INSERT INTO @customers SELECT 'customer12', 24;
INSERT INTO @customers SELECT 'customer15', 30;
INSERT INTO @customers SELECT 'customer16', 31;
INSERT INTO @customers SELECT 'customer16', 32;
INSERT INTO @customers SELECT 'customer21', 31;
INSERT INTO @customers SELECT 'customer21', 35;

SELECT * 
FROM @customers;
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
gluecks
  • 1,375
  • 1
  • 6
  • 6
  • Does this answer your question? [How to create a MySQL hierarchical recursive query?](https://stackoverflow.com/questions/20215744/how-to-create-a-mysql-hierarchical-recursive-query) – philipxy Jun 26 '21 at 03:00
  • Not exactly, but it's still nice insight. Thanks for the link! – gluecks Jun 28 '21 at 13:50

1 Answers1

2

You can accomplish this with recursive CTE's like the ones below

-- Find all customers for debtor
WITH CTE AS (
    SELECT [debtor_id] AS [Root],
        [debtor_id],
        [customer_number],
        CAST('' AS VARCHAR(2000)) AS [Path]
    FROM @customers AS [b]
    UNION ALL
    SELECT [b].[Root],
        [c].[debtor_id],
        [d].[customer_number],
        CAST([b].[Path] + CAST([c].[debtor_id] AS VARCHAR(10)) + '||' AS VARCHAR(2000)) AS [Path]
    FROM [CTE] AS [b]
        INNER JOIN @customers AS [c] ON [b].[customer_number] = [c].[customer_number]
        INNER JOIN @customers AS [d] ON [d].[debtor_id] = [c].[debtor_id]
    WHERE [c].[debtor_id] != [b].[Root]
        AND [Path] NOT LIKE '%' + CAST([c].[debtor_id] AS VARCHAR(10)) + '||%'
)
SELECT DISTINCT
    [customer_number]
FROM [CTE] AS [c]
WHERE [Root] = 24;

-- Find all debtors for customer
WITH CTE AS (
    SELECT [customer_number] AS [Root],
        [debtor_id],
        [customer_number],
        CAST('' AS VARCHAR(2000)) AS [Path]
    FROM @customers AS [b]
    UNION ALL
    SELECT [b].[Root],
        [d].[debtor_id],
        [c].[customer_number],
        CAST([b].[Path] + [c].[customer_number] + '||' AS VARCHAR(2000)) AS [Path]
    FROM [CTE] AS [b]
        INNER JOIN @customers AS [c] ON [b].[debtor_id] = [c].[debtor_id]
        INNER JOIN @customers AS [d] ON [d].[customer_number] = [c].[customer_number]
    WHERE [c].[customer_number] != [b].[Root]
        AND [Path] NOT LIKE '%' + [c].[customer_number] + '||%'
)
SELECT DISTINCT [debtor_id]
FROM [CTE] AS [c]
WHERE [Root] = 'customer10';
jon antoine
  • 396
  • 1
  • 4
  • 16
  • Hi again Jon antoine, thanks a lot. Just tested it and it works like a charm! I've added a depth limit when applying it to the realdata in some severe cases I may have many (50+) customer numbers and several selfjoins will quickly skyrocket then. – gluecks Jun 28 '21 at 11:14