SQL 服务器:我怎样才能实现这个...可能使用递归函数?
SQL Server : how can I achieve this...possibly with a recursive function?
我有下面的例子table:
每个customer_number可能有一个或多个debtor_id,反之亦然每个debtor_id可能有一个或多个customer_number。现在我基本上需要一种方法来从任何给定的 customer_number 或 debtor_id
中检索所有 customer_numbers 或 debtor_ids
更具体的例子:
假设您想知道连接到 debtor_id 24.
的所有 customer_number
- 第 1 步:debtor_id24 连接到 customer_numbercustomer12
- Step2:customer_numbercustomer12连接到debtor_id23和24(起点)
- 第 3 步:debtor_id23 连接到 customer_numbercustomer12 和 customer11
- Step4: customer_number customer11 连接到 debtor_id 22 和 23
等等
所以最后当输入 debtor_id 24 时,您希望检索到 customer_number customer10、customer11 和 customer12 作为结果。
我知道它可能需要多个自连接,但它需要灵活并针对任何给定的“深度”动态工作。我的第一个想法是,这闻起来很像递归。基本上类似于“保持自连接,直到没有新的 customer_number 或 debtor_id 返回”
我对递归没有太多经验,编写SQL函数也是如此:-(
有人对此有一些提示或有用的建议吗?
生成相同内容的示例代码 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;
您可以使用如下所示的递归 CTE 来完成此操作
-- 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';
我有下面的例子table:
每个customer_number可能有一个或多个debtor_id,反之亦然每个debtor_id可能有一个或多个customer_number。现在我基本上需要一种方法来从任何给定的 customer_number 或 debtor_id
中检索所有 customer_numbers 或 debtor_ids更具体的例子:
假设您想知道连接到 debtor_id 24.
的所有 customer_number- 第 1 步:debtor_id24 连接到 customer_numbercustomer12
- Step2:customer_numbercustomer12连接到debtor_id23和24(起点)
- 第 3 步:debtor_id23 连接到 customer_numbercustomer12 和 customer11
- Step4: customer_number customer11 连接到 debtor_id 22 和 23 等等
所以最后当输入 debtor_id 24 时,您希望检索到 customer_number customer10、customer11 和 customer12 作为结果。
我知道它可能需要多个自连接,但它需要灵活并针对任何给定的“深度”动态工作。我的第一个想法是,这闻起来很像递归。基本上类似于“保持自连接,直到没有新的 customer_number 或 debtor_id 返回”
我对递归没有太多经验,编写SQL函数也是如此:-(
有人对此有一些提示或有用的建议吗?
生成相同内容的示例代码 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;
您可以使用如下所示的递归 CTE 来完成此操作
-- 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';