如何计算具有递归关系的表中唯一对的数量?

时间:2019-02-16 05:42:08

标签: sql oracle

给出下表(people_table):

PersonId  CoupleId  
-------------------
   1        2  
   2        1  
   3        (null)  
   4        5  
   5        4  

通过编写与此类似的查询

Select count(?) from people_table

我希望2作为计数结果

7 个答案:

答案 0 :(得分:4)

valgrind

希望有帮助!

答案 1 :(得分:2)

逻辑

  
      
  • 使用内部联接+联接表的PersonId =表的CoupleId和联接表的CoupleId =表的PersonId
  •   
  • 因为内部联接将获得双行,所以必须count(1) / 2才能获得计数。
  •   

架构(Oracle v11g)

CREATE TABLE T
    ("PersonId" int, "CoupleId" int)
INSERT ALL 
    INTO T ("PersonId", "CoupleId")
         VALUES (1, 2)
    INTO T ("PersonId", "CoupleId")
         VALUES (2, 1)
    INTO T ("PersonId", "CoupleId")
         VALUES (3, null)
    INTO T ("PersonId", "CoupleId")
         VALUES (4, 5)
    INTO T ("PersonId", "CoupleId")
         VALUES (5, 4)
SELECT * FROM dual

不允许PersonId和CoupleId重复版本

select count(1) / 2 cnt  from T T1
inner join T  T2 on T1."PersonId" = T2."CoupleId" and T1."CoupleId" = T2."PersonId"

cnt
---
2

允许PersonId和CoupleId重复版本

with cte as (
    select distinct * from T
)
select count(1) / 2 cnt  from CTE T1
inner join CTE T2 on T1."PersonId" = T2."CoupleId" and T1."CoupleId" = T2."PersonId"

cnt
---
2

View on db<>fiddle

答案 2 :(得分:2)

您可以将least()greatest()函数应用于personidcoupleid
group by,最后计算行数:

select count(*) counter from (
  select least(personId, coupleId), greatest(personId, coupleId)  
  from people_table
  where personId is not null and coupleId is not null
  group by least(personId, coupleId), greatest(personId, coupleId)
)

请参见demo

答案 3 :(得分:1)

以下将是使用联接的查询-

 with table1 as ( 
select 1 as PersonId , 2 as CoupleId from dual
union 
select 2 as PersonId , 1  as CoupleId from dual
union
select 3 as PersonId , null as CoupleId from dual 
union 
select 4 as PersonId , 5 as CoupleId from dual
union
select 5 as PersonId , 4 as CoupleId from dual)
select count(*) from table1 t1 inner join table1 t2 on t1.personId=t2.coupleid and t1.coupleId=t2.personId
where t1.personId>t1.coupleId;

答案 4 :(得分:1)

您可以先对列进行“规范化”,以获取较低的值,然后应用distinct来删除重复项:

SELECT Count(*)
FROM 
 (
   SELECT DISTINCT Least(PersonID, CoupleID) AS a, Greatest(PersonID, CoupleID) AS b
   FROM nodupes
   WHERE PersonID IS NOT NULL 
     AND CoupleID IS NOT NULL
 ) dt

答案 5 :(得分:1)

我认为最简单的方法是:

select count(*)
from people_table
where PersonId < CoupleId  ;

为什么这样做?好吧,一对夫妇中的两个人有不同的ID。其中一个必须比另一个小,这就是其中之一。

这也会滤除NULL值。

注意:这假设您的数据格式正确-也就是说,一对夫妇中的两个人都在表中作为单独的行。

答案 6 :(得分:0)

首先,在PersonId和CoupleId列中对具有相同值的对进行计数,然后删除所有小于2的行,然后对结果集中的行进行计数。

with
  table1 as ( 
    select 1 as PersonId, 2 as CoupleId from dual union all
    select 2, 1 from dual union all select 3, null from dual union all
    select 4, 5 from dual union all select 5, 4 from dual union all
    select 4, 5 from dual union all select 2, 1 from dual
  )
select count(*) as qnt
from (
  select count(*) as qnt
  from table1
  group by case when PersonId < CoupleId then PersonId else CoupleId end,
           case when PersonId < CoupleId then CoupleId else PersonId end
  having count(*) > 1
);

输出:

       QNT
----------
         2

使用db<>fiddle在线进行测试。