查找重复项的最低 ID 并根据这些 ID 更新表

Finding lowest Ids of duplicates and updating tables according to these Ids

问题

我有一个 sql 数据库,其中有一个 table 标签,其中许多标签的名称是重复的。

这样的陈述
SELECT     *  
FROM       HashTag  
ORDER BY   Name

returns 类似

Id   |  Name
1947 |  test
1950 |  sample
1962 |  test
1963 |  sample
1986 |  test
2014 |  example

我只想保留每个名称的 ID 最低的主题标签('test' 为 1947,'sample' 为 1950)并用此 ID 更新其他 table,替换较高的 ID(例如:更新主题标签 'test';最低的 ID = 1947,较高的 ID = 1962、1986)。这些 sql 语句截至目前已手动更新,如下所示:

UPDATE             HashTaggedActivity
SET [HashTag_id]   = 1947
WHERE HashTag_id   in (1962, 1986)

Update             HashTaggedGroup
SET [HashTag_id]   = 1947
WHERE HashTag_id   in (1962, 1986)

DELETE             ht
FROM               HashTag ht
WHERE              ht.Id in (1962, 1986)

在此之后,我必须为 HashTag 'sample' 执行此操作,这是一个容易出错且乏味的过程。标签 'example' 不是重复的,不应导致更新其他 table。

有什么方法可以编写 sql 语句来针对 table HashTag 中每次出现的重复名称执行此操作?

到目前为止我尝试了什么

我想我必须合并一条语句来获取按 Id 排序的重复计数

select ht.Id, ht.Name, htc.dupeCount
from HashTag ht
inner join (
    SELECT ht.Name, COUNT(*) AS dupeCount
    FROM HashTag ht
    GROUP BY ht.Name
    HAVING COUNT(*) > 1
) htc on ht.Name = htc.Name
ORDER BY Id

这给出了

Id   |  Name    | dupeCount
1947 |  test    | 3
1950 |  sample  | 2
1962 |  test    | 3
1963 |  sample  | 2
1986 |  test    | 3
2014 |  example | 1

根据 dupeCount 使用我的 UPDATE 和 DELETE 语句,但我不确定该怎么做 ;-)

在此先致谢并致以最诚挚的问候,

迈克尔

前两个更新语句首先根据hashtag_id获取名称(最里面的select),然后获取hashtag中共享相同名称的所有id中的最小值(下一个select) 然后相应地更新 hashtag_id。 在这种情况下,它还会使用 hashtag_id 1947 和 1950 更新记录 - 但新值将与旧值相同。

update HashTaggedGroup
 set hashtag_id = 
    (select min(id) 
     from hashtag h1 
     where (
        select name 
        from hashtag h2 
        where h2.id=HashTaggedGroup.hashtag_id)=h1.name);


update HashTaggedActivity
 set hashtag_id = 
    (select min(id) 
     from hashtag h1 
     where (
        select name 
        from hashtag h2 
        where h2.id=HashTaggedActivity.hashtag_id)=h1.name);

下面的删除将适用于Mysql和SQLServer,它可能需要针对其他数据库进行调整(尽管想法保持不变)。如果您确定来自 hashtag 的所有 id 都存在于 HashTaggedActivity 中,则可以使查询更简单。

delete h1 from hashtag as h1 
    inner join hashtag as h2 on 
              h1.name = h2.name and 
              h1.id > h2.id;

SQLFiddle for the above

我会使用 window 函数:

with ht as (
      select ht.*, min(id) over (partition by name) as minid
      from hashtag ht
     )
update hta
    set hashtag_id = ht.minid
    from HashTaggedActivity hta join
         ht
         on hta.hashtag_id = ht.id
    where ht.minid <> hta.hashtag_id;

然后以类似的方式进行删除:

with ht as (
      select ht.*, min(id) over (partition by name) as minid
      from hashtag ht
     )
delete from ht
    where ht.minid <> id;