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 - 删除两列之间的重复值的主要内容,如果未能解决你的问题,请参考以下文章