【问题标题】:Insert rows into a self referential table with autoincrement使用自动增量将行插入到自引用表中
【发布时间】:2020-10-12 03:31:11
【问题描述】:

我想将 B 插入 A 并得到 C :

A :                                    B :
+----+-----------+-------+------+      +-------+--------------+------+
| id | id_parent | value | name |      | value | value_parent | name |
+----+-----------+-------+------+      +-------+--------------+------+
| 1  | NULL      | 11    | a    |      | 21    | 22           | x    |
| 2  | 1         | 12    | b    |      | 22    | 12           | y    |
| 3  | 1         | 13    | c    |      | 23    | 21           | z    |
+----+-----------+-------+------+      +-------+--------------+------+

C : 
+----+-----------+-------+------+
| id | id_parent | value | name |
+----+-----------+-------+------+
| 1  | NULL      | 11    | a    | 
| 2  | 1         | 12    | b    |
| 3  | 1         | 13    | c    |
| 4  | 2         | 22    | y    |
| 5  | 4         | 21    | x    |
| 6  | 5         | 23    | z    |
+----+-----------+-------+------|

[编辑:唯一的限制是在两个值列中都不能重复,并且“value_parent”必须是存在于 A 或 B 的值列中的值]

我现在看到的解决方案似乎效率很低。

我可以对 B 中的行进行分组,以便第 1 组包含其父值在 A 中的行,第 2 组包含其父值在第 1 组中的行,依此类推。然后我可以依次插入组 n 并使用从插入中获得的 id 更新组 n+1,直到我插入所有内容。

+-------+-----------+------+
| value | id_parent | name |
+-------+-----------+------+

STEP 1
Group 1
| 22    | 2         | y    |  // find the associated id_parent and insert this group
Group 2
| 21    | NULL      | x    |
Group 3
| 23    | NULL      | z    |

STEP 2
Group 1
| 22    | 2         | y    |
Group 2
| 21    | 4         | x    |  // update this group and insert it
Group 3
| 23    | NULL      | z    |

STEP 3
Group 1 
| 22    | 2         | y    |
Group 2
| 21    | 4         | x    |
Group 3
| 23    | 5         | z    |  // update this group and insert it
+-------+-----------+------+

我想知道是否存在更直接的东西,因为我在互联网上找不到任何东西。如果有用,我正在使用 T-SQL。

【问题讨论】:

    标签: sql tsql sql-insert self-reference


    【解决方案1】:

    表A 是微不足道的。处理B:

    select new_id, coalesce(id_parent, new_id - 1) as parent_id,
           value_parent as value, name
    from (select b.*, a.id as id_parent,
                 aa.max_id + row_number() over (order by (case when a.id is not null then 1 else 2 end), b.value) as new_id
          from b cross join
               (select max(id) as max-id from a) aa left join
               a
               on b.value_parent = a.value
         ) b;
    

    【讨论】:

    • 小错字,这是 order by 中的 b.value,而不是 b.id
    • 其实如果我没记错的话,这个答案只在特定情况下有效。给定一个值为 v1 的元素及其值为 v2 的父元素,如果 v1 > v2,或者如果 B 中有一个元素的父元素的值为 v3,使得 v1
    • @aymericfraise 。 . .这回答了您提出的问题。除非我遗漏了什么,否则似乎没有为其余的“b”记录定义父母。
    【解决方案2】:

    鉴于 id_parent 可以为空,我找到了一个分两步工作的解决方案:

    首先,将 B 中的所有行添加到 A 中,并将 id_parent 设置为 null。然后,使用正确的 id_parent 更新所有插入的行。

    insert into A
    select null,value,name from B
    
    update A
    set
        id_parent = T.id_parent
    from (
        select 
              A.id
            , Ap.id as id_parent
        from B
        inner join A on A.value = B.value
        inner join A Ap on Ap.value = B.value_parent
    ) as T
    where A.id = T.id
    

    【讨论】:

      猜你喜欢
      • 2023-03-30
      • 2015-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多