删除 SQL 中其他行的子集行
Remove subset rows of other rows in SQL
下面这个 table 包括 ID
和五个指标列:x1
, ..., x5
:
我需要根据这个逻辑删除重复项:
对于每个 ID
,我们查看 x1
、...、x5
的值,然后删除其他行的子集。例如,对于 ID=1,第 3 行是第 2 行的子集,因此我们删除第 3 行。此外,第 4 行不是第 2 行的子集,因此我们保留它。
这是 table 的预期最终视图:
首先将 5 列的所有值连接起来,这样您就可以得到一个二进制字符串,例如“100101”,它可以转换为以 10 为基数的数字,例如别名 value
,函数 CONV()
.
假设 table 中没有重复的行,正如您在评论中提到的那样,行 #X 应被视为另一行的子集 #Y if bitwise OR
两行的 value
之间的结果 returns #Y 的 value
:
SELECT t1.*
FROM tablename t1
WHERE NOT EXISTS (
SELECT *
FROM tablename t2
WHERE t2.ID = t1.ID
AND (t1.x1, t1.x2, t1.x3, t1.x4, t1.x5) <>
(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5)
AND CONV(CONCAT(t1.x1, t1.x2, t1.x3, t1.x4, t1.x5), 2, 10) |
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10) =
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10)
);
或者,对于 MySql 8.0+:
WITH cte AS (
SELECT *, CONV(CONCAT(x1, x2, x3, x4, x5), 2, 10) value
FROM tablename
)
SELECT t1.ID, t1.x1, t1.x2, t1.x3, t1.x4, t1.x5
FROM cte t1
WHERE NOT EXISTS (
SELECT *
FROM cte t2
WHERE t2.ID = t1.ID
AND t2.value <> t1.value
AND t1.value | t2.value = t2.value
);
如果要删除子集行,请像这样使用 table 的自联接:
DELETE t1
FROM tablename t1 INNER JOIN tablename t2
ON t2.ID = t1.ID
AND (t1.x1, t1.x2, t1.x3, t1.x4, t1.x5) <>
(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5)
AND CONV(CONCAT(t1.x1, t1.x2, t1.x3, t1.x4, t1.x5), 2, 10) |
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10) =
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10);
参见demo。
下面这个 table 包括 ID
和五个指标列:x1
, ..., x5
:
我需要根据这个逻辑删除重复项:
对于每个 ID
,我们查看 x1
、...、x5
的值,然后删除其他行的子集。例如,对于 ID=1,第 3 行是第 2 行的子集,因此我们删除第 3 行。此外,第 4 行不是第 2 行的子集,因此我们保留它。
这是 table 的预期最终视图:
首先将 5 列的所有值连接起来,这样您就可以得到一个二进制字符串,例如“100101”,它可以转换为以 10 为基数的数字,例如别名 value
,函数 CONV()
.
假设 table 中没有重复的行,正如您在评论中提到的那样,行 #X 应被视为另一行的子集 #Y if bitwise OR
两行的 value
之间的结果 returns #Y 的 value
:
SELECT t1.*
FROM tablename t1
WHERE NOT EXISTS (
SELECT *
FROM tablename t2
WHERE t2.ID = t1.ID
AND (t1.x1, t1.x2, t1.x3, t1.x4, t1.x5) <>
(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5)
AND CONV(CONCAT(t1.x1, t1.x2, t1.x3, t1.x4, t1.x5), 2, 10) |
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10) =
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10)
);
或者,对于 MySql 8.0+:
WITH cte AS (
SELECT *, CONV(CONCAT(x1, x2, x3, x4, x5), 2, 10) value
FROM tablename
)
SELECT t1.ID, t1.x1, t1.x2, t1.x3, t1.x4, t1.x5
FROM cte t1
WHERE NOT EXISTS (
SELECT *
FROM cte t2
WHERE t2.ID = t1.ID
AND t2.value <> t1.value
AND t1.value | t2.value = t2.value
);
如果要删除子集行,请像这样使用 table 的自联接:
DELETE t1
FROM tablename t1 INNER JOIN tablename t2
ON t2.ID = t1.ID
AND (t1.x1, t1.x2, t1.x3, t1.x4, t1.x5) <>
(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5)
AND CONV(CONCAT(t1.x1, t1.x2, t1.x3, t1.x4, t1.x5), 2, 10) |
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10) =
CONV(CONCAT(t2.x1, t2.x2, t2.x3, t2.x4, t2.x5), 2, 10);
参见demo。