Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 表自连接问题-需要所需的输出_Sql_Common Table Expression_Recursive Query - Fatal编程技术网

Sql 表自连接问题-需要所需的输出

Sql 表自连接问题-需要所需的输出,sql,common-table-expression,recursive-query,Sql,Common Table Expression,Recursive Query,我有一张结构如下的表格: OLD_ID New_ID Month_Number ------ ------ ------------ A 1 A B 2 B C 3 C D 4 我需要一个ID为“A”的表输出,如下所示: New_ID Oldest_Id Latest_ID ------ ---------

我有一张结构如下的表格:

OLD_ID    New_ID    Month_Number
------    ------    ------------
          A         1
A         B         2
B         C         3
C         D         4
我需要一个ID为“A”的表输出,如下所示:

New_ID      Oldest_Id     Latest_ID
------      ---------     ---------
A            A             D
B            A             D
C            A             D
D            A             D
使用月号可以找到最早的\u Id和最新的\u Id


请注意,我是SQL新手。

这个答案假设Microsoft SQL Server,但通过对语法的调整,这可以适用于任何DB类型,只要它具有临时表、行计数和用户定义变量,后者只是为了安全起见,以免出现循环。该答案还假设源表是可示例的,[New_ID]列包含所有ID,并且只有当相应的[Month_Number]值合适时,才应考虑较旧/较新的ID,例如,对于较旧的ID,LTE较新ID的[Month_Number]

基本上,我设想的是创建两个临时表:第一个表列出每个[ID]以及[ID]的第一个[Old_ID],第二个表列出最后一个[New_ID]的相同内容:

ID1和ID2中的记录设置为首先引用它们自己。然后,对于循环中的每个过程,id的值将在下一步更新(如果可用)。当没有其他事情要做时,迭代停止

以下是每个过程中发生的情况:

通过1: *旧:B->A;C->B;D->C 新增:A->B;B->C;C->D 通过2: 旧:C->A;D->B 新增:A->C;B->D 通过3: 旧:D->A 新:A->D 通过4: 无需采取更多行动 @cutoff变量只是为了防止在ID“A”引用旧ID“B”和ID“B”引用旧ID“A”时永远循环


这不是一个非常有效的方法,通过一些实践,您可能会做得更好:例如,将两个旧动作/新动作结合在一起,但我将把这留给您:

请用您正在使用的数据库标记您的问题。
-- Create temporary tables and declare cutoff variable
DECLARE @cutoff TINYINT;
SET @cutoff = 0;

CREATE TABLE #ID1 (
    [ID] CHAR(1) NOT NULL
    ,[Oldest_ID] CHAR(1) NOT NULL
    ,[Month_Number] TINYINT NOT NULL
    );
CREATE TABLE #ID2 (
    [ID] CHAR(1) NOT NULL
    ,[Latest_ID] CHAR(1) NOT NULL
    ,[Month_Number] TINYINT NOT NULL
    );

-- Initialise temporary tables
INSERT INTO #ID1 ([ID],[Oldest_ID],[Month_Number])
SELECT [New_ID],[New_ID],[Month_Number]
FROM #ExampleTable;

INSERT INTO #ID2 ([ID],[Latest_ID],[Month_Number])
SELECT [ID],[ID],[Month_Number]
FROM #ID1;

-- Fetch oldest IDs first
WHILE(@@ROWCOUNT != 0 AND @cutoff <= 100)
BEGIN

    SET @cutoff = @cutoff + 1;
    UPDATE oldies
    SET oldies.[Oldest_ID] = d.[OLD_ID]
        ,oldies.[Month_Number] = d.[Month_Number]
    FROM #ID1 AS oldies
    JOIN #ExampleTable d
        ON oldies.[Oldest_ID] = d.[New_ID]
    WHERE d.[Month_Number] <= oldies.[Month_Number]
        AND d.[OLD_ID] IS NOT NULL;

END;

-- Now the... "newies"
WHILE(@@ROWCOUNT != 0 AND @cutoff <= 100)
BEGIN

    SET @cutoff = @cutoff + 1;
    UPDATE newies
    SET newies.[Latest_ID] = d.[New_ID]
        ,newies.[Month_Number] = d.[Month_Number]
    FROM #ID2 AS newies
    JOIN #ExampleTable d
        ON newies.[Latest_ID] = d.[OLD_ID]
    WHERE d.[Month_Number] >= newies.[Month_Number];

END;

-- Finally, do as you wish with #ID1 and #ID2
SELECT d.[New_ID] AS [ID]
    ,f1.[Oldest_ID]
    ,f2.[Latest_ID]
FROM #ExampleTable AS d
JOIN #ID1 AS f1 ON d.[New_ID] = f1.[ID]
JOIN #ID2 AS f2 ON d.[New_ID] = f2.[ID]
;