oracle 选择非唯一组合

tcbh2hod  于 2023-05-06  发布在  Oracle
关注(0)|答案(6)|浏览(214)

我有下面的数据

dep, arr
uk, usa
usa, uk
china,aus
aus,china
brazil,uk

我如何从上述数据中得到唯一和非唯一的组合
唯一组合(departure to arrival and arrival to departure both are present)

dep, arr
uk, usa
usa, uk
china,aus
aus,china

非唯一组合,其中仅存在departure to arrival or arrival to departure,反之亦然

brazil,uk

使用此sql查询,但不确定如何针对特定于非唯一

Select          
           dep, arr,  count(*) over (partition by least(dep, arr), greatest(dep, arr) order by dep) rnk
From flights

有什么建议吗?

yhqotfr8

yhqotfr81#

您可以使用not exists()来确保出发不可用作到达,到达不可用作出发:
查询

select dep,arr from tab1 a
  where not exists
(
 select 1 from tab1 b where a.dep=b.arr and a.arr=b.dep
)

输出:
| DEP|ARR|
| --------------|--------------|
| 巴西|英国|
fiddle

iyzzxitl

iyzzxitl2#

简单子查询怎么样?
样本数据:

SQL> select * from flights;

DEP    ARR
------ -----
uk     usa
usa    uk
china  aus
aus    china
brazil uk

这就是你所谓的“独特组合”:

SQL> select dep, arr
  2  from flights
  3  where dep||'~'||arr in (select arr||'~'||dep from flights);

DEP    ARR
------ -----
usa    uk
uk     usa
aus    china
china  aus

这就是所谓的“非唯一组合”:

SQL> select dep, arr
  2  from flights
  3  where dep||'~'||arr not in (select arr||'~'||dep from flights);

DEP    ARR
------ -----
brazil uk

SQL>

分隔符设置为~字符,假定它不包含在deparr列值中。如果是,那么用不存在的东西替换它(可以是 * 任何 * 其他字符)。

zc0qhyus

zc0qhyus3#

您可以使用greatest/least作为group by表达式的简单聚合来计算包含排列的2元素元组的出现次数。

with sample(dep, arr) as (
  select 'uk', 'usa' from dual union all
  select 'usa', 'uk' from dual union all
  select 'china', 'aus' from dual union all
  select 'aus', 'china' from dual union all
  select 'brazil', 'uk' from dual
)
select
  greatest(dep, arr) as loc1,
  least(dep, arr) as loc2,
  case count(*)
    when 2
    then 'two way'
    else 'one way'
  end as type_
from sample
group by
  greatest(dep, arr),
  least(dep, arr)

它为您的示例数据返回
| LOC1|LOC2|类型_|
| --------------|--------------|--------------|
| 美国|英国|双向|
| 中国|奥斯|双向|
| 英国|巴西|单程|
fiddle
count(*) = N放在having子句中,以仅返回所需的组合类别。

omvjsjqw

omvjsjqw4#

一个连接就可以了

CREATE TABLE tab1
    ("dep" varchar2(6), "arr" varchar2(5))
;
INSERT ALL 
    INTO tab1 ("dep", "arr")
         VALUES ('uk', 'usa')
    INTO tab1 ("dep", "arr")
         VALUES ('usa', 'uk')
    INTO tab1 ("dep", "arr")
         VALUES ('china', 'aus')
    INTO tab1 ("dep", "arr")
         VALUES ('aus', 'china')
    INTO tab1 ("dep", "arr")
         VALUES ('brazil', 'uk')
SELECT * FROM dual
;
5 rows affected
SELECT t1."dep", t1."arr" FROM tab1 t1 JOIN tab1 t2 ON t1."dep" =  t2."arr"  and t2."dep" = t1."arr"
深度arr
美国英国
英国美国
奥斯中国
中国奥斯

fiddle

7gcisfzg

7gcisfzg5#

你几乎就在那里了,你想删除解析函数中的ORDER BY子句(所以你在整个窗口上计数),然后过滤外部查询:

SELECT dep, arr
FROM   (
  SELECT dep,
         arr,
         COUNT(*) OVER (PARTITION BY LEAST(dep, arr), GREATEST(dep, arr)) AS cnt
  FROM   flights
)
WHERE  cnt = 1;

其中,对于样本数据:

CREATE TABLE flights(dep, arr) AS
SELECT 'uk',     'usa'   FROM DUAL UNION ALL
SELECT 'usa',    'uk'    FROM DUAL UNION ALL
SELECT 'china',  'aus'   FROM DUAL UNION ALL
SELECT 'aus',    'china' FROM DUAL UNION ALL
SELECT 'brazil', 'uk'    FROM DUAL;

输出:
| DEP|ARR|
| --------------|--------------|
| 巴西|英国|
如果您可以在每个方向上有多个航班,则计算每个组合中DISTINCT起飞或到达的数量:

SELECT dep, arr
FROM   (
  SELECT dep,
         arr,
         COUNT(DISTINCT dep) OVER (PARTITION BY LEAST(dep, arr), GREATEST(dep, arr))
           AS cnt
  FROM   flights
)
WHERE  cnt = 1;

输出:
| DEP|ARR|
| --------------|--------------|
| 巴西|英国|
以及:

SELECT dep, arr
FROM   (
  SELECT dep,
         arr,
         COUNT(DISTINCT dep) OVER (PARTITION BY LEAST(dep, arr), GREATEST(dep, arr))
           AS cnt
  FROM   flights
)
WHERE  cnt = 2;

输出:
| DEP|ARR|
| --------------|--------------|
| 奥斯|中国|
| 中国|奥斯|
| 英国|美国|
| 美国|英国|
并且,如果要显示所有行和方向:

SELECT dep,
       arr,
       CASE COUNT(DISTINCT dep)
              OVER (PARTITION BY LEAST(dep, arr), GREATEST(dep, arr))
       WHEN 1
       THEN 'one-way'
       ELSE 'two-way'
       END AS direction
FROM   flights;

输出:
| DEP|ARR|方向|
| --------------|--------------|--------------|
| 奥斯|中国|双向的|
| 中国|奥斯|双向的|
| 巴西|英国|单向的|
| 英国|美国|双向的|
| 美国|英国|双向的|
fiddle

ltqd579y

ltqd579y6#

@Littlefoot的回答可能会产生误报和漏报;例如,如果你有arrdepa-bcb-ca,那么当在一个方向上匹配时,字符串连接将给予a-b-cfiddle
您可以使用IN和多个术语执行类似的测试,它不会出现误报,因为它没有使用字符串连接来合并术语。
获取双向航班:

SELECT dep, arr
FROM   flights
WHERE  (dep, arr) IN ( SELECT arr, dep FROM flights );

对于样本数据,输出:
| DEP|ARR|
| --------------|--------------|
| 美国|英国|
| 英国|美国|
| 奥斯|中国|
| 中国|奥斯|
获取单程航班:

SELECT dep, arr
FROM   flights
WHERE  (dep, arr) NOT IN ( SELECT arr, dep FROM flights );

其输出:
| DEP|ARR|
| --------------|--------------|
| 巴西|英国|
如果你想获取所有航班并标记它们,那么使用CASE表达式:

SELECT dep,
       arr,
       CASE
       WHEN (dep, arr) IN ( SELECT arr, dep FROM flights )
       THEN 'two-way'
       ELSE 'one-way'
       END as direction
FROM   flights;

其输出:
| DEP|ARR|方向|
| --------------|--------------|--------------|
| 英国|美国|双向的|
| 美国|英国|双向的|
| 中国|奥斯|双向的|
| 奥斯|中国|双向的|
| 巴西|英国|单向的|
但是,这种方法需要查询表两次,一次是主查询,一次是IN过滤器,因此效率不如使用the COUNT analytic function(即使查询看起来稍微复杂一些)。
fiddle

相关问题