我需要一个查询,它将从任一列返回所有相关的别名id。这里显示的是一些别名客户ID,其中包括数千个其他行。如果查询的输入参数是id = 7,我需要一个返回5行(1,5,7,10,22)的查询。那是因为它们都是彼此的别名。例如,22和10是7的间接别名。
CustomerAlias
--------------------------
AliasCuID AliasCuID2
--------------------------
1 5
1 7
5 7
10 5
22 1
以下是客户表的摘录。
Customer
----------------------------------
CuID CuFirstName CuLastName
----------------------------------
1 Mike Jones
2 Fred Smith
3 Jack Jackson
4 Emily Simpson
5 Mike Jones
6 Beth Smith
7 Mike jones
8 Jason Robard
9 Emilie Jiklonmie
10 Michael jones
11 Mark Lansby
12 Scotty Slash
13 Emilie Jiklonmy
22 mike jones
我已经能够接近,但我似乎无法正确选择间接相关的别名。鉴于此查询:
SELECT DISTINCT Customer.CuID, Customer.CuFirstName, Customer.CuLastName
FROM Customer WHERE
(Customer.CuID = 7) OR (Customer.CuID IN
(SELECT AliasCuID2
FROM CustomerAlias AS CustomerAlias_2
WHERE (AliasCuID = 7))) OR (Customer.CuID IN
(SELECT AliasCuID
FROM CustomerAlias AS CustomerAlias_1
WHERE (AliasCuID2 = 7)))
当然,返回5个所需ID中的3个。这在结果行中缺少间接相关的别名id 10和22.
1 Mike Jones
5 Mike Jones
7 Mike jones
* 根据以下建议,我正在尝试CTE分层查询。
在遵循一些建议之后我现在有了这个。它适用于某些人,只要表中的记录引用足够的直接ID。但是,如果查询使用id = 10,那么它仍然很短,只是数据的性质。
DECLARE @id INT
SET @id = 10;
DECLARE @tmp TABLE ( a1 INT, a2 INT, Lev INT );
WITH Results (AliasCuID, AliasCuID2, [Level]) AS (
SELECT AliasCuID,
AliasCuID2,
0 as [Level]
FROM CustomerAlias
WHERE AliasCuID = @id OR AliasCuID2 = @id
UNION ALL
-- Recursive step
SELECT a.AliasCuID,
a.AliasCuID2,
r.[Level] + 1 AS [Level]
FROM CustomerAlias a
INNER JOIN Results r ON a.AliasCuID = r.AliasCuID2 )
INSERT INTO @tmp
SELECT * FROM Results;
WITH Results3 (AliasCuID, AliasCuID2, [Level]) AS (
SELECT AliasCuID,
AliasCuID2,
0 as [Level]
FROM CustomerAlias
WHERE AliasCuID = @id OR AliasCuID2 = @id
UNION ALL
-- Recursive step
SELECT a.AliasCuID,
a.AliasCuID2,
r.[Level] + 1 AS [Level]
FROM CustomerAlias a
INNER JOIN Results3 r ON a.AliasCuID2 = r.AliasCuID )
INSERT INTO @tmp
SELECT * FROM Results3;
SELECT DISTINCT a1 AS id FROM @tmp
UNION ALL
SELECT DISTINCT a2 AS id FROM @tmp
ORDER BY id
请注意,这是一个简化的查询,只提供相关ID列表。
---
id
---
5
5
7
10
但是,仍然无法拉入ID 1和22。
答案 0 :(得分:0)
这不是一个容易解决的问题,除非你对搜索的深度有一些了解(https://stackoverflow.com/a/7569520/1803682) - 你看起来不是这样 - 并且采用强力方法。
假设您不知道编写存储过程所需的深度。我采用这种方法来解决几乎相同的问题:https://dba.stackexchange.com/questions/7147/find-highest-level-of-a-hierarchical-field-with-vs-without-ctes/7161#7161
<强>更新强> 如果你不关心如何创建别名的链 - 我会递归地运行一个脚本,使它们都引用一个(主?)记录。然后你可以很容易地进行搜索,它会很快 - 如果你关心别名是如何遍历的话,不是解决方案。
答案 1 :(得分:0)
我为SQL Server 2012创建了一个SQL Fiddle。如果您可以访问它,请告诉我。
我的想法是,你想要分别以递归的方式继续检查左右分支。如果关系在左右之间反弹,这种逻辑可能会崩溃。您可以设置第三个CTE来引用前两个,但是从左到右,从右到左加入,但是没有人有时间。
代码也在下面。
CREATE TABLE CustomerAlias
(
AliasCuID INT,
AliasCuID2 INT
)
GO
INSERT INTO CustomerAlias
SELECT 1,5
UNION SELECT 1, 7
UNION SELECT 5, 7
UNION SELECT 10, 5
UNION SELECT 22, 1
GO
DECLARE @Value INT
SET @Value = 7
; WITH LeftAlias AS
(
SELECT AliasCuID
, AliasCuID2
FROM CustomerAlias
WHERE AliasCuID2 = @Value
UNION ALL
SELECT a.AliasCuID
, a.AliasCuID2
FROM CustomerAlias a
JOIN LeftAlias b
ON a.AliasCuID = b.AliasCuID2
)
, RightAlias AS
(
SELECT AliasCuID
, AliasCuID2
FROM CustomerAlias
WHERE AliasCuID = @Value
UNION ALL
SELECT a.AliasCuID
, a.AliasCuID2
FROM CustomerAlias a
JOIN LeftAlias b
ON a.AliasCuID2 = b.AliasCuID
)
SELECT DISTINCT A
FROM
(
SELECT A = AliasCuID
FROM LeftAlias
UNION ALL
SELECT A = AliasCuID2
FROM LeftAlias
UNION ALL
SELECT A = AliasCuID
FROM RightAlias
UNION ALL
SELECT A = AliasCuID2
FROM RightAlias
) s
ORDER BY A