【问题标题】:Matching each row of one table with one row of another table将一个表的每一行与另一个表的一行匹配
【发布时间】:2011-08-15 19:01:02
【问题描述】:

我有一张桌子:

TABLE_A
-----------  
Sc Cl Pr Br
-----------
1  1  1  NULL
2  1  1  NULL
1  2  2  NULL
2  2  2  NULL 

(Sc, Cl, Pr) 是候选键

为了将值分配给字段 Br(认为这是理所当然的,它不能更改)我将这些行插入到一个 TABLE_B 中,其中包含 3 个字段(Br、Cl、Pr),字段 Br 自动递增(为了让事情更简单,假设TABLE_B 为空,TABLE_A 仅包含上述行)。所以我做了类似的事情

INSERT INTO TABLE_B (Cl, Pr) SELECT Cl, Pr FROM TABLE_A

现在我想以这样的方式将自动生成的 TABLE_B.Br 分配给 TABLE_A.Br

TABLE_B.Cl = TABLE_A.Cl AND TABLE_B.Pr = TABLE_A.Pr

对于每两行 TABLE_A t1, t2 的 AND

t1.Cl = t2.Cl AND t1.Pr = t2.Pr  AND t1.Sc <> t2.Sc => t1.Br <> t2.Br

PS 1:我希望这不会太混乱:(

PS 2:我找到的唯一快速简便的解决方案是在 TABLE_B (Sc) 中添加一个字段,然后在表之间进行简单的连接就可以完成这项工作。但添加列不是一种选择。

【问题讨论】:

  • 这可能太混乱了......也许它会有助于查看完成后生成的表数据是什么?
  • 您使用哪个版本的 SQL-Server?
  • 看看这里。 stackoverflow.com/questions/5830229/…。另一个人问了几乎相同的问题。我真的很想知道为什么这些桌子的设计是这样的。根本没有任何意义。
  • @Mikael:谢谢。它闻起来像家庭作业。对于一个狡猾的老师教的科目。
  • @ypercube,不幸的是,这不是功课,而是真实情况,是以前糟糕的设计和拒绝更改数据库架构的结果。这只是尽可能精确地指定实际问题的抽象版本。

标签: sql sql-server


【解决方案1】:

如果您只有两个 Sc 值,请尝试以下两个语句:

Update TABLE_A a set br = ( select min( br ) // select lowest br values 
                             from TABLE_B b
                            where a.cl = b.cl
                              and a.pr = b.pr )
 where a.sc = ( select min( sc )             // updating lower sc values
                  from TABLE_A c
                 where a.cl = c.cl
                   and a.pr = c.pr )

Update TABLE_A a set br = ( select max( br ) // select highest br values
                              from TABLE_B b
                             where a.cl = b.cl
                               and a.pr = b.pr )
 where a.sc = ( select max( sc )
                  from TABLE_A c
                 where a.cl = c.cl
                   and a.pr = c.pr )         // update highest sc values

【讨论】:

  • Nope Sc 可以有多个值。 TABLE_A 是更复杂表的抽象示例。我在想的是使用一个临时表来保存 Cl 和 Pr 上的连接结果,然后找到一种方法来消除额外的行,或者使用 where 子句即时消除这些额外的行,但想不到任何方式都可以做到这一点。
【解决方案2】:

这似乎更像是一个难题而不是一个问题。您不能删除列Br 并再次将其添加为自动递增的列吗?

无论如何,这是使用ROW_NUMBER()PARTITION 的解决方案:

UPDATE A
SET A.Br = B.Br
FROM
    ( SELECT Cl
           , Pr
           , ROW_NUMBER() 
               OVER(PARTITION BY Cl, Pr ORDER BY Sc)
             AS rowNo
           , Br
      FROM TABLE_A
    ) AS A
  JOIN
    ( SELECT Cl
           , Pr
           , ROW_NUMBER()
               OVER(PARTITION BY Cl, Pr ORDER BY Br)
             AS rowNo
           , Br
      FROM TABLE_B
    ) AS B
    ON  A.Cl = B.Cl
    AND A.Pr = B.Pr
    AND A.rowNo = B.rowNo;

再想一想,你真的不需要TABLE_B。您可以使用以下命令为字段 Br 分配自动值:

UPDATE A
SET A.Br = A.rowNo
FROM
    ( SELECT ROW_NUMBER() 
               OVER(ORDER BY Cl, Pr, Sc)
             AS rowNo
           , Br
      FROM TABLE_A
    ) AS A;

【讨论】:

  • 总而言之,PARTITION BY 是我正在寻找的,以便创建第三个字段“rowNo”,以便 (Cl,Pr,rowNow) 是唯一的。第二种解决方案仅适用于 (Sc, Cl, Pr) 是唯一的(在定义的问题中)但在实际问题中 TABLE_A 是对 Sc, Cl, Pr 进行不同选择的结果,其中 Br 为 NULL 重复(在多次插入新值后)
【解决方案3】:

如果您使用 SQL Server 2008,您可以使用 mergeoutput

declare @T table(Sc int, Cl int, Pr int, Br int);

merge TABLE_B as T
using TABLE_A as S
on 1=0
when not matched then
  insert(Cl, Pr) values(S.Cl, S.Br)
output S.Sc, S.Cl, S.Pr, inserted.Br into @T;

update A
  set Br = T.Br 
from TABLE_A as A 
  inner join @T as T
    on A.Sc = T.Sc and
       A.Cl = T.Cl and
       A.Pr = T.Pr;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 1970-01-01
    • 2020-09-30
    • 1970-01-01
    相关资源
    最近更新 更多