SQL - 删除两列之间的重复值

Posted

技术标签:

【中文标题】SQL - 删除两列之间的重复值【英文标题】:SQL - Remove Duplicate value between two columns 【发布时间】:2021-08-07 04:51:23 【问题描述】:

我正在寻找一种简单的方法来删除不需要的重复值。

Dupe 是对另一列的引用的一部分,而不是在列本身内,但我要从中删除重复值的列与其他值是多重分隔的。

这是一个示例表:

ID,Thing
Dog,Cat;Dog;Bird
Snake,Horse;Fish;Snake
Car,Car;Bus;Bike

如您所见,Dog,Snake,Car 是我需要从 Thing 列中删除的值。

输出:

ID,Thing
Dog,Cat;Bird
Snake,Horse;Fish
Car,Bus;Bike

有没有办法在多分隔字段中匹配并提取完全匹配?

我正在使用 SQL Server MGMT 工作室。谢谢。

【问题讨论】:

其实我觉得你可以无视我下面的答案。我刚刚重读了你的问题。我很困惑。这比我想象的要复杂一些。我想如果我要解决这个问题,我会用 C# 来做。有很多事情需要跟踪。 分号是记录分隔符吗? 我有点困惑。你的表有多少列?你能正确格式化你的样本数据吗? 修复你的数据模型! 提问时,您需要提供minimal reproducible example: (1) DDL 和样本数据填充,即 CREATE 表和 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上面#1 中的样本数据。 (4) 您的 SQL Server 版本 (SELECT @@version;)。 【参考方案1】:
WITH CTE AS
(
      SELECT ID, Thing, ROW_NUMBER() OVER (PARTITION BY Thing) AS rn
)

DELETE
FROM CTE
WHERE rn > 1

我相信这会做到。首先通过运行查询的 CTE 部分进行测试,这样您就可以看到 rn 是什么。

【讨论】:

【参考方案2】:

您的问题和示例数据不是很清楚。我认为您想要的是从第一列中的第二列中删除任何内容,在这种情况下您可以尝试使用replace

select Id, 
  replace(replace(thing,id,''),';;',';')
from table

在列中存储多值元素绝不是一个好主意,并且与关系数据模型存在利益冲突;它几乎总是在某些时候引起问题。

【讨论】:

这可能无法正常处理 'Dog''Catfish;Dogfish;Lungfish' 可能是的,我敢肯定,如果 OP 重新审视他的问题并增加一些清晰度,它可以很容易地改进。【参考方案3】:

您可以做的是将前导和尾随 ; 连接到 Thing 的值,然后将 ID 的值替换为空字符串。 然后删除前导和尾随;

如果你的SQL Server版本是2017+,可以使用函数TRIM():

SELECT Id, 
       TRIM(';' FROM REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) Thing
from tablename;

对于以前的版本,请使用SUBSTRING():

SELECT Id, 
       SUBSTRING(
         REPLACE(';' + Thing + ';', ';' + ID + ';', ';'),
         2,
         LEN(REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) - 2
       ) Thing
from tablename;

如果要更新表格:

UPDATE tablename
SET Thing = TRIM(';' FROM REPLACE(';' + Thing + ';', ';' + ID + ';', ';'));

或:

UPDATE tablename
SET Thing = SUBSTRING(
              REPLACE(';' + Thing + ';', ';' + ID + ';', ';'),
              2,
              LEN(REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) - 2
            );

请参阅demo。

【讨论】:

【参考方案4】:

我真的不明白“多分隔”对于字符串的含义。在您的上下文中,它似乎表明您可能有不同类型的分隔符。这绝对意味着您的数据模型非常糟糕。如果您想从things 列中删除id,那么我的第一个建议是修复分隔符。

在 SQL Server 中,您可以使用:

select t.*,
       (select string_agg(s.value, ';')
        from string_split(replace(t.things, ',', ';'), ';') s
        where s.value <> t.id
       ) as new_things
from t;

如果分隔符具有某种内在含义(我是否提到过您应该修复数据模型?),那么您可以使用更暴力的方法。这是一种方法:

select t.*,
       (case when things = id then ''
             when things like concat(id, '[,;]%')
             then stuff(things, 1, len(id) + 1, '')
             when things like concat('%[,;]', id)
             then left(things, len(things) - len(id) - 1)
             when things like concat('%[,;]', id, '[,;]%')
             then stuff(things, patindex(concat('%[,;]', id, '[,;]%'), things), len(id) + 1, '')
             else things
       end)
from t;

Here 是一个 dbfiddle。

【讨论】:

【参考方案5】:

你的问题很好。我使用简单的案例陈述来得到答案。 CHARINDEX 帮助在 Id 列中找到值的位置,然后确定值在 id 中的位置,并根据位置将字符串替换为所需的值。

 --Preparing the table
 SELECT *
  INTO t
 FROM (VALUES 
         ('Dog', 'Cat;Dog;Bird'),
         ('Snake', 'Horse;Fish;Snake'),
         ('Car', 'Car;Bus;Bike')
 ) v(id, things)


 --Query
SELECT id
    ,CASE   WHEN CHARINDEX(reverse(id), reverse(things), 1)  =  1 THEN  REPLACE(things,';'+id   ,'') 
            WHEN CHARINDEX(id, things, 1)  < LEN(things) AND CHARINDEX(id, things, 1) > 1      THEN   REPLACE(things, id +';'   ,'')  
            WHEN CHARINDEX(id, things, 1) = 1 THEN REPLACE(things, id +';'  ,'') 
            ELSE 'End' 
        END as [things]          
 FROM t

【讨论】:

@JohnnySemicolon 看看答案,如果需要任何帮助,请回复我。

以上是关于SQL - 删除两列之间的重复值的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server:如何对两列/条件进行重复数据删除?

pandas:删除两列中具有相同索引的行中的重复值

如何删除R中两列中具有相同值但ID不同的行[重复]

excel中两列都有重复值,怎样筛选出两列唯一值?

基于R中的两列删除重复项[重复]

如何根据两列删除所有重复行?