sql server数据一对多合并_SQL Server 合并多对多表的数据

点击上方蓝字关注“汪宇杰博客”

fe44c6574c670c8254bb4583b41707c9.png

今天还是发一篇老文。介绍当时我合并博客文章数据时遇到的一个问题和解决方法。我不擅长SQL,如果大家有更好的方法,欢迎在评论里留言讨论。

最近在整理博客的数据,需要做一个操作就是合并文章的分类。我的博客中文章和分类是多对多的关系。即一篇文章可以属于多个分类,一个分类可以包含多篇文章。这是一个很典型的多对多关系,我用的是一个多对多的表,做联合主键关联这些数据。

就像这样:

cad75e65b4658ceb089392b9eac3ca69.png 35d86218cf887e8792b74a33db05d8b6.png

我需要做的是把“DotNetBeginner”这个分类的文章移到“CSharpAndDotNet”分类里去。但是因为原先在“DotNetBeginner”里的文章有些也是属于“CSharpAndDotNet”的,所以直接Update关联表的话,会产生重复的联合主键,就会爆

直观一点看,写个SQL语句查询出原分类(DotNetBeginner)和目标分类(CSharpAndDotNet)中的数据:

DECLARE @SourceCatId     AS UNIQUEIDENTIFIER,

        @TargetCatId     AS UNIQUEIDENTIFIER

SET @SourceCatId = '678A4011-40E0-4F75-BC23-1FFC25B72D4A'

SET @TargetCatId = 'D58043FF-B3CB-43DA-9067-522D76D21BE3'

SELECT p.Title,

       c.Name

FROM   PostCategory         AS pc

       INNER JOIN Post      AS p

            ON  p.Id = pc.PostId

       INNER JOIN Category  AS c

            ON  c.Id = pc.CategoryId

WHERE  pc.CategoryId IN (@SourceCatId, @TargetCatId)

结果如下图:

《C#字符和ASCII码互转》这篇如果直接update分类到CSharpAndDotNet就会爆,因为PostCategory表中已经有一条这样的记录了。但是像《上海轨道交通……》那篇就可以直接update。

2083d4c43705327756b0c312a168f1d4.png

解决这个问题的思路分两步:

1. 删除如《C#字符和ASCII码互转》这种的会爆破联合主键的记录

2. 更新关联表,把旧分类的ID改成新分类

那么首先我们要知道有哪些记录是符合被删除的条件的,把这些文章的ID找出来,用一个group by having就可以爆出来:

SELECT pc.PostId

FROM   PostCategory AS pc

WHERE  pc.CategoryId IN (@SourceCatId, @TargetCatId)

GROUP BY

       pc.PostId

HAVING COUNT(*) >= 2

结果有10条:

2d34470b7a8e43c2fbbcc13f7d5c3af6.png

这10篇文章同时属于DotNetBeginnerCSharpAndDotNet和其他分类。

为了直观的显示和之后删除操作方便,定义一个表变量叫temp,然后验证一下是哪些文章:

DECLARE @Temp TABLE (PostId UNIQUEIDENTIFIER)

INSERT INTO @Temp

  (

    PostId

  )(

       SELECT pc.PostId

       FROM   PostCategory AS pc

       WHERE  pc.CategoryId IN (@SourceCatId, @TargetCatId)

       GROUP BY

              pc.PostId

       HAVING COUNT(*) >= 2

   )

------------------------------------------------------------------------------

SELECT --pc.PostId

       p.Title,

       --pc.CategoryId,

       c.Name

FROM   PostCategory         AS pc

       INNER JOIN Post      AS p

            ON  p.Id = pc.PostId

       INNER JOIN Category  AS c

            ON  c.Id = pc.CategoryId

WHERE  pc.PostId IN (SELECT t.PostId

                     FROM   @Temp t)

发现结果是正确的:

e7d88ba7c49039cbc7b21a4f0371434f.png

然后就可以从关联表PostCategory中删除所有文章ID(PostId)在@Temp表中,且CategoryId对应DotNetBeginner的记录。然后用update语句完成文章分类的合并。

-- Step 1. Delete records that will fuck up the primary key

DELETE 

FROM   PostCategory

WHERE  CategoryId = @SourceCatId

       AND PostId IN (SELECT t.PostId

                      FROM   @Temp t)

-- Step 2. Update old key to new key

UPDATE PostCategory

SET    CategoryId     = @TargetCatId

WHERE  CategoryId     = @SourceCatId

最后验证一下,数据已经成功合并了。

ac2f230e861a6f70acb0a2ef0e3916b4.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值