【问题标题】:Using CTE to update multiple columns in table and loop on all rows in table使用 CTE 更新表中的多个列并循环表中的所有行
【发布时间】:2018-01-24 17:00:54
【问题描述】:

我是一个 SQL 新手,我正在尝试对表中的所有行使用 CTE,以使用分层信息更新每行中的多个列。我在网上阅读了很多例子,但没有一个能准确描述我需要什么,所以我希望有人能帮助我。

我有一个研究样本表存储在货架->货架->盒子的层次结构中,其中货架是最高级别,盒子是最低级别,样本在盒子下方。架子、架子和箱子也在此表中作为单独的行。所有项目都有一个名为“名称”的字段来识别它们。它们都通过 ID 和 parent_ID 连接。有点像管理结构。

‌‌‌我需要为样本填充每一行中的所有级别值。它比我在网上找到的经理-雇员示例更复杂,它需要存储 CTE 返回的值,而不是像我找到的示例所示的那样简单地执行 SELECT 来显示它们。

要在所有行上运行 CTE,‌‌我尝试将整个 CTE 嵌套在 WHILE 循环中,但它只循环单个值而不是所有行。

下面是我目前正在努力返回一个样本值的层次结构的代码; 'tempspec' 是示例表:

DECLARE @TID float;
SET @TID = 39059;
WITH cte AS
(
   SELECT ID,
    Parent_Id,
    Name,
    Study_ID,
          Loc_Box,
          Loc_Shelf,
          Loc_Rack,
    Loc_Type
     FROM tempspec
    WHERE ID = @TID and Study_ID = 'XXX'
    UNION all
   SELECT tempspec.Id,
          tempspec.Parent_Id,
          tempspec.Name,
    tempspec.Study_ID,
          tempspec.Loc_Box,
          tempspec.Loc_Shelf,
          tempspec.Loc_Rack,
    tempspec.Loc_Type
     FROM tempspec
     JOIN cte on tempspec.Id = cte.Parent_Id
)
SELECT E1.name, E1.ID, E1.Parent_ID,E1.Loc_Type,ISNULL(E2.name,'TOP')
FROM cte E1
LEFT JOIN cte E2
ON E1.parent_id = E2.ID;

但是如果我尝试用 UPDATE 替换 SELECT,它会运行并说表中的所有行都已更新,但没有存储任何内容:

UPDATE E1
SET E1.Loc_Box = E2.Loc_Box,
 E1.Loc_Rack = E2.Loc_Rack,
 E1.Loc_Shelf = E2.Loc_Shelf
FROM tempspec E1
LEFT JOIN cte E2
ON E1.parent_id = E2.ID;

‌ 如果我尝试在这个 WHILE 循环中嵌套 CTE('P' 表示样本行,所以我只是为它们遍历树),我无法将 ID 分配给@TID,或者当我尝试过其他它永远循环的方式:

WHILE EXISTS(SELECT * FROM tempspec WHERE Loc_Type = 'P')
BEGIN
SET @TID = ID;

我做错了什么?我尝试了各种格式,但似乎没有任何效果。提前感谢您的帮助!‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌

以下是请求的测试数据。我想用样本父行中的名称值填充 Shelf、Rack 和 Box(type='P'):

DROP TABLE dbo.TEST_DATA;
CREATE TABLE dbo.TEST_DATA (int ID, int Parent_Id,varchar(30) Name, varchar(10) Type,varchar(30) Shelf,varchar(30) Rack,varchar(30) Box)
INSERT INTO TEST_DATA (39702,   1664,   0228MBDNAERA1,  'P','','','');
INSERT INTO TEST_DATA (39703,   1664,   0230MBDNAERA1,  'P','','','');
INSERT INTO TEST_DATA (39704,   1664,   0231MBDNAERA1,  'P','','','');
INSERT INTO TEST_DATA (39726,   1744,   0228MBDNAERA2,  'P','','','');
INSERT INTO TEST_DATA (39727,   1744,   0230MBDNAERA2,  'P','','','');
INSERT INTO TEST_DATA (39728,   1744,   0231MBDNAERA2,  'P','','','');
INSERT INTO TEST_DATA (39764,   1752,   0228MBDNAERA3,  'P','','','');
INSERT INTO TEST_DATA (39766,   1752,   0230MBDNAERA3,  'P','','','');
INSERT INTO TEST_DATA (39768,   1752,   0231MBDNAERA3,  'P','','','');
INSERT INTO TEST_DATA (1744,    1652,   MBDNAERA2 - 3,  'B','','','');
INSERT INTO TEST_DATA (1752,    1732,   MBDNAERA3 - 3,  'B','','','');
INSERT INTO TEST_DATA (1664,    1652,   MBDNAERA1 - 3,  'B','','','');
INSERT INTO TEST_DATA (1732,    1617,   Rack R, 'R','','','');
INSERT INTO TEST_DATA (1652,    1617,   Rack Q, 'R','','','');
INSERT INTO TEST_DATA (1617,    2,  Shelf 4,    'S','','','');
INSERT INTO TEST_DATA (2,   NULL,   Freezer,    'F','','','');

一个样本的示例数据层次结构以及我试图获取的结果行(抱歉格式错误):

ID       Parent_Id  Name            Type    Shelf   Rack    Box
39702   1664    0228MBDNAERA1   'P'         
1664    1652    MBDNAERA1 - 3   'B'         
1652    1617    Rack Q          'R'         
1617    2   Shelf 4         'S'         
2           NULL    Freezer         'F'         

ID       Parent_Id  Name            Type    Shelf   Rack    Box
39702   1664    0228MBDNAERA1   'P' Shelf 4 Rack Q  MBDNAERA1 - 3

【问题讨论】:

  • 您能否添加一个示例,说明您的表与示例数据的外观,然后您当前从示例数据中获得了什么结果,以及您试图获得什么结果?
  • 您是要更新每一行以从其父行复制值,还是要将根(祖先)行的值一直向下推入整个层次结构?在第一种情况下,您根本不需要递归 CTE,而在第二种情况下,您需要在递归 CTE 结果中添加额外的列来传递根值。
  • David - 是的,我想更新包含来自其父级的样本的每一行(我不需要更新架子/机架/盒子行,它们只是为了建立层次结构)。因此,对于样本 A,我希望它的架子/架子/盒子值与相应架子/架子/盒子行的层次结构中的值匹配。那有意义吗?我认为列出 UNION ALL - SELECT 语句中的所有列会拉下所有必要的字段。
  • 选项卡 - 刚刚添加了示例数据。
  • 我刚刚意识到我分配了错误的值 - 'Loc_*' 必须设置为层次结构中每个级别的 'Name' 的值。如何获取 Name 的所有值并将它们分配给单个示例行?

标签: sql sql-server tsql common-table-expression sql-server-2016


【解决方案1】:

试一试:

DECLARE @TEST_DATA as TABLE  (ID int , Parent_Id int ,Name varchar(30) , Type varchar(10)  )
INSERT @TEST_DATA VALUES (39702,   1664,   '0228MBDNAERA1',  'P');
INSERT @TEST_DATA VALUES (39703,   1664,   '0230MBDNAERA1',  'P');
INSERT @TEST_DATA VALUES (39704,   1664,   '0231MBDNAERA1',  'P');
INSERT @TEST_DATA VALUES (39726,   1744,   '0228MBDNAERA2',  'P');
INSERT @TEST_DATA VALUES (39727,   1744,   '0230MBDNAERA2',  'P');
INSERT @TEST_DATA VALUES (39728,   1744,   '0231MBDNAERA2',  'P');
INSERT @TEST_DATA VALUES (39764,   1752,   '0228MBDNAERA3',  'P');
INSERT @TEST_DATA VALUES (39766,   1752,   '0230MBDNAERA3',  'P');
INSERT @TEST_DATA VALUES (39768,   1752,   '0231MBDNAERA3',  'P');
INSERT @TEST_DATA VALUES (1744,    1652,   'MBDNAERA2 - 3',  'B');
INSERT @TEST_DATA VALUES (1752,    1732,   'MBDNAERA3 - 3',  'B');
INSERT @TEST_DATA VALUES (1664,    1652,   'MBDNAERA1 - 3',  'B');
INSERT @TEST_DATA VALUES (1732,    1617,   'Rack R', 'R');
INSERT @TEST_DATA VALUES (1652,    1617,   'Rack Q', 'R');
INSERT @TEST_DATA VALUES (1617,    2,  'Shelf 4',    'S');
INSERT @TEST_DATA VALUES (2,   NULL,   'Freezer',    'F');

-- SELECT 
;with 
cte_product as (
Select *  from @TEST_DATA where Type = 'P'),
cte_box as (
Select *  from @TEST_DATA where Type = 'B'),
cte_shelf as (
Select *  from @TEST_DATA where Type = 'S'),
cte_rack as (
Select *  from @TEST_DATA where Type = 'R')
Select * from
cte_product p 
left join cte_box b
on
p.Parent_Id = b.ID
inner join cte_rack r
on
b.Parent_Id = r.ID
inner join cte_shelf s
on
r.Parent_Id = s.ID

结果

ID          Parent_Id   Name                           Type       ID          Parent_Id   Name                           Type       ID          Parent_Id   Name                           Type       ID          Parent_Id   Name                           Type
----------- ----------- ------------------------------ ---------- ----------- ----------- ------------------------------ ---------- ----------- ----------- ------------------------------ ---------- ----------- ----------- ------------------------------ ----------
39726       1744        0228MBDNAERA2                  P          1744        1652        MBDNAERA2 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S
39727       1744        0230MBDNAERA2                  P          1744        1652        MBDNAERA2 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S
39728       1744        0231MBDNAERA2                  P          1744        1652        MBDNAERA2 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S
39764       1752        0228MBDNAERA3                  P          1752        1732        MBDNAERA3 - 3                  B          1732        1617        Rack R                         R          1617        2           Shelf 4                        S
39766       1752        0230MBDNAERA3                  P          1752        1732        MBDNAERA3 - 3                  B          1732        1617        Rack R                         R          1617        2           Shelf 4                        S
39768       1752        0231MBDNAERA3                  P          1752        1732        MBDNAERA3 - 3                  B          1732        1617        Rack R                         R          1617        2           Shelf 4                        S
39702       1664        0228MBDNAERA1                  P          1664        1652        MBDNAERA1 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S
39703       1664        0230MBDNAERA1                  P          1664        1652        MBDNAERA1 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S
39704       1664        0231MBDNAERA1                  P          1664        1652        MBDNAERA1 - 3                  B          1652        1617        Rack Q                         R          1617        2           Shelf 4                        S

--UPDATE TABLE 

;with 
cte_product as (
Select *  from @TEST_DATA where Type = 'P'),
cte_box as (
Select *  from @TEST_DATA where Type = 'B'),
cte_shelf as (
Select *  from @TEST_DATA where Type = 'S'),
cte_rack as (
Select *  from @TEST_DATA where Type = 'R')
UPDATE D 
SET
     Shelf = S.name
    ,Rack = r.Name
    ,Box = b.Name
FROM 
    @TEST_DATA d
        Inner join 
        cte_product p 
        left join cte_box b
        on
        p.Parent_Id = b.ID
        inner join cte_rack r
        on
        b.Parent_Id = r.ID
        inner join cte_shelf s
        on
        r.Parent_Id = s.ID
On
    d.ID = p.ID


select * from @TEST_DATA

结果

 ID          Parent_Id   Name                           Type       Shelf                          Rack                           Box
----------- ----------- ------------------------------ ---------- ------------------------------ ------------------------------ ------------------------------
39702       1664        0228MBDNAERA1                  P          Shelf 4                        Rack Q                         MBDNAERA1 - 3
39703       1664        0230MBDNAERA1                  P          Shelf 4                        Rack Q                         MBDNAERA1 - 3
39704       1664        0231MBDNAERA1                  P          Shelf 4                        Rack Q                         MBDNAERA1 - 3
39726       1744        0228MBDNAERA2                  P          Shelf 4                        Rack Q                         MBDNAERA2 - 3
39727       1744        0230MBDNAERA2                  P          Shelf 4                        Rack Q                         MBDNAERA2 - 3
39728       1744        0231MBDNAERA2                  P          Shelf 4                        Rack Q                         MBDNAERA2 - 3
39764       1752        0228MBDNAERA3                  P          Shelf 4                        Rack R                         MBDNAERA3 - 3
39766       1752        0230MBDNAERA3                  P          Shelf 4                        Rack R                         MBDNAERA3 - 3
39768       1752        0231MBDNAERA3                  P          Shelf 4                        Rack R                         MBDNAERA3 - 3
1744        1652        MBDNAERA2 - 3                  B                                                                        
1752        1732        MBDNAERA3 - 3                  B                                                                        
1664        1652        MBDNAERA1 - 3                  B                                                                        
1732        1617        Rack R                         R                                                                        
1652        1617        Rack Q                         R                                                                        
1617        2           Shelf 4                        S                                                                        
2           NULL        Freezer                        F                                                                        

【讨论】:

  • 我只尝试在 CTE 之后执行一次 UPDATE,其中我将更新该特定样本行的货架、机架和盒子值。可以这样做吗?
  • OUTPUT 显示 Loc_* 列中没有保存任何内容。
  • 如果您没有针对 ID 进行不同的研究,这是预期结果。
  • 我刚刚意识到我分配了错误的值 - 'Loc_*' 必须设置为层次结构中每个级别的 'Name' 的值。如何获取 Name 的所有值并将它们分配给单个示例行?
  • 不,我希望 ID = 样本 ID 的行将树的所有级别向下填充到样本(架子、架子和行)。我不关心包含架子、机架和行的 ID 的行......它们可以填充或不填充。我只希望示例路径完整。我很快就会发布一个例子......
猜你喜欢
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-30
  • 1970-01-01
相关资源
最近更新 更多