需要查询才能选择直接和间接的customerID别名

时间:2013-09-03 21:27:28

标签: sql database tsql

我需要一个查询,它将从任一列返回所有相关的别名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。

2 个答案:

答案 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