首页 > 解决方案 > MySQL - 从两列中选择不同的值

问题描述

我有一个具有以下结构的表:

IdM|IdS
-------
 1 | 2
 1 | 3
 1 | 4
 2 | 1
 2 | 3
 2 | 4
 3 | 1
 3 | 2
 3 | 3
 3 | 4

我怎么能在这个表上做一个 select 语句,它将返回这个表的一些行,在每一行中,一个特定的 id 只出现一个,在它指定的列上无关紧要?

对于上述结果集,我想要一个返回的查询:

-------
 1 | 2
 3 | 4
-------

再举一个例子,如果您要省略原始数据集中的第一行:

IdM|IdS
-------
 1 | 3
 1 | 4
 2 | 1
 2 | 3
 2 | 4
 3 | 1
 3 | 2
 3 | 3
 3 | 4

结果集应该是:

-------
 1 | 3
 2 | 4
-------

标签: mysqlsqlselectmariadbrecursive-query

解决方案


这实际上是一个有趣的问题。如果我正确地跟随你,你想要遍历数据集并且只保留两个值以前从未见过的行。您可以使用递归查询:

with recursive 
    data as (
        select idm, ids, row_number() over(order by idm, ids) rn 
        from mytable 
        where idm <> ids
    ),
    cte as (
        select idm, ids, rn, 1 as to_keep , concat(idm, ',', ids) visited from data where rn = 1
        union all
        select d.idm, d.ids, d.rn,
            (not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited)),
            case when (not find_in_set(d.idm, c.visited) and not find_in_set(d.ids, c.visited))
                then concat_ws(',', c.visited, d.idm, d.ids)
                else c.visited
            end
        from cte c
        inner join data d on d.rn = c.rn + 1
    )
select idm, ids from cte where to_keep

第一个 CTE 枚举按两列排序的行。然后递归查询遍历结果集,检查两个值是否都是新的,并相应地设置列的标志。保留标记的数字以用于在以下迭代中进行过滤。

DB Fiddle 上的演示

请注意,根据您的要求,并非所有值都可能出现在结果集中。考虑以下数据集:

 idm   ids
+-----+---
 1     2
 1     3
 1     4

您的逻辑只会返回第一行。


推荐阅读