在SQL

时间:2017-09-05 10:23:46

标签: sql database

我有桌子

   ID   MIN_ID
   1    1
   2    1
   3    1
   4    4
   5    1
   6    5
   7    6
   8    4

我需要第三列FINAL_ID,如果ID = MIN_ID则返回MIN_ID,否则它将在表中递归查找,直到找到ID = MIN_ID的行。结果应该是

   ID   MIN_ID  FINAL_ID
   1    1       1
   2    1       1
   3    1       1
   4    4       4
   5    1       1
   6    5       1        // 5 have the MIN_ID of 1
   7    6       1       // 6 have the MIN_ID of 1 and 5 have the MIN_ID of 1.
   8    4       4       // 8 goes to 4, 4 goes to 4. Done.

问题是如何在SQL中没有任何过程语言的情况下获得此结果。任何DBMS示例都适合(MySQL,PostgreSQL,DB2,SQL Server,Oracle)

例如执行它的php代码:

<?php

$table = [
    ['ID' => '1', 'MIN_ID' => '1'],
    ['ID' => '2', 'MIN_ID' => '1'],
    ['ID' => '3', 'MIN_ID' => '1'],
    ['ID' => '4', 'MIN_ID' => '4'],
    ['ID' => '5', 'MIN_ID' => '1'],
    ['ID' => '6', 'MIN_ID' => '5'],
    ['ID' => '7', 'MIN_ID' => '6'],
];


for ($x = 0; $x < count($table); $x++) {
    $table[$x]['FINAL_ID'] = calculate_final_id($table, $table[$x]);
}

print_r($table);


function calculate_final_id($table, $row)
{

    if ($row['ID'] == $row['MIN_ID']) {
        return $row['ID'];
    }

    $next_row = search($table, $row['MIN_ID']);

    return calculate_final_id($table, $next_row);
}

function search($table, $id)
{
    for ($x = 0; $x < count($table); $x++) {
        if ($table[$x]['ID'] == $id) {
            return $table[$x];
        }
    }
}

3 个答案:

答案 0 :(得分:2)

SQL Server示例。建立在ID的订单

CREATE TABLE myTable
    (ID int, MIN_ID int);

INSERT INTO myTable
    (ID, MIN_ID)
VALUES
    (1, 1),
    (2, 1),
    (3, 1),
    (4, 4),
    (5, 1),
    (6, 5),
    (7, 6)
;
WITH rc AS (
    SELECT ID, MIN_ID as FinalId
    FROM myTable
    UNION ALL
    SELECT rc.ID, t.MIN_ID   
    FROM rc 
    JOIN myTable t ON rc.FinalId = t.ID AND t.ID != t.MIN_ID
)
SELECT ID, min(FinalId) FinalId
FROM rc
GROUP BY ID;

答案 1 :(得分:1)

这应该有效(表变量的SQL Server语法):

declare @t table (ID int not null, MIN_ID int not null)
insert into @t(ID,MIN_ID) values
(1,1),
(2,1),
(3,1),
(4,4),
(5,1),
(6,5),
(7,6)

;With Search as (
    select
        ID,MIN_ID,MIN_ID as FINAL_ID,0 as Depth
    from @t
    union all
    select
        s.ID,s.MIN_ID,t.MIN_ID,Depth+1
    from
        Search s
            inner join
        @t t
            on
                s.FINAL_ID = t.ID
    where
        s.FINAL_ID != t.MIN_ID
), Ordered as (
    select *,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Depth desc) as rn
    from Search
)
select *
from Ordered
where rn = 1

基本上,如果可以,我们会继续重新计算FINAL_ID并跟踪我们搜索的深度 - 然后为每个ID值选择最深的结果。

结果:

ID          MIN_ID      FINAL_ID    Depth       rn
----------- ----------- ----------- ----------- --------------------
1           1           1           0           1
2           1           1           0           1
3           1           1           0           1
4           4           4           0           1
5           1           1           0           1
6           5           1           1           1
7           6           1           2           1

(递归CTE(Search)和窗口函数(ROW_NUMBER)是应该在任何现代SQL数据库上工作的标准SQL)

答案 2 :(得分:0)

根据我的意见,我认为您想使用CASE声明。

SELECT ID, MIN_ID, CASE WHEN ID = MIN_ID THEN MIN_ID ELSE 1 END AS FINAL_ID
FROM yourtable

输出:

ID  MIN_ID  FINAL_ID
1   1       1
2   1       1
3   1       1
4   4       4
5   1       1
6   5       1
7   6       1

SQL小提琴:http://sqlfiddle.com/#!9/c208d8/1/0