专栏首页汪宇杰博客SQL Server 合并多对多表的数据

SQL Server 合并多对多表的数据

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

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

就像这样:

我需要做的是把“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。

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

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条:

这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)

发现结果是正确的:

然后就可以从关联表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

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

本文分享自微信公众号 - 汪宇杰博客(ediwangblog),作者:汪宇杰

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • .NET Core 读写Windows注册表

    是的,你没看错!这完全有可能!即使 .NET Core 被设计为跨平台,但这并不意味着无法使用特定于平台的API。以 Windows 注册表为例,尽管.NET ...

    Edi Wang
  • 迁移 Azure Application Insights 到 .NET Core 3.0

    .NET Core 3.0 即将在本月的.NET Conf大会上发布正式版,在这之前包括我在内的不少朋友已经迫不及待使用预览版迁移了自己的应用,并爆得体无完肤。...

    Edi Wang
  • 解决Azure DevOps部署到Azure后.NET Core网站无法启动的问题

    最近我遭遇了一个奇怪的问题。使用Azure DevOps配置CI/CD管线,自动部署到Azure App Service以后,.NET Core的网站竟然会启动...

    Edi Wang
  • Gtest简单使用

    顾翔老师开发的bugreport2script开源了,希望大家多提建议。文件在https://github.com/xianggu625/bug2testscr...

    小老鼠
  • Mysql 分区介绍(八) —— 子分区

    分区也被称为复合分区在分区表中每个分区的进一步划分。子分区也必须是hash分区/key分区

    aox.lei
  • 图像地点场景类型识别(PlaceCNN)实践

      从图像中判断图像场景所处的地点类型,是图像理解的一种常见任务。本质上场景类别标注数据足够的情况下,它可以属于图像分类的一种,因此直接利用现有成熟的网络架构如...

    sparkexpert
  • 简单易懂的Springboot介绍

    Springboot使您可以轻松地创建独立的、生产级的基于Spring的应用程序,您可以“直接运行”,启动应用程序都需要非常少的 Spring配置。 这是...

    雪地二货
  • GTX1080 安装 cuda 8.0 + cuDNN5.1

    ubuntu下按ctrl+alt+f1~f6出现黑屏现象的解决方法 sudo apt-get install bumblebee bumblebee-nv...

    用户1148525
  • 为什么只有少数人能学会算法?

    现在很多人学习编程学的还是很开心,随着学习的深入慢慢的开始怀疑人生,怀疑自己是不是真的适合学习编程,总之一系列的不合适纷纷的涌入自己的大脑,作为一个程序员如何正...

    程序员互动联盟
  • 【业界】神经模拟再突破,NEST算法可以100%模拟人脑

    AiTechYun 编辑:nanan ? 科学家们一直试图找到将大脑处理能力带到计算机上的方法。创建能够模拟人脑的算法,以及神经元如何工作是实现这一梦想的关键。...

    AiTechYun

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动