按组依次找出缺口

时间:2019-10-03 06:35:39

标签: oracle

我有一张桌子,其中有不同的城市和价值观。我想按城市查找差距,所以有表格:

City    Value
Helsinki 1
Helsinki 2
Helsinki 5
Kuopio   4
Kuopio   5
Joensuu  1
Joensuu  2
Joensuu  3

我想知道城市之间的差距在哪里

 City     Value
 Helsinki 3
 Helsinki 4
 Kuopio   1
 Kuopio   2
 Kuopio   3
 Joensuu  4
 Joensuu  5

我知道我可以使用

select  rownum from dual connect by level<= 6 minus select value from table

但我不知道如何按组进行操作。

3 个答案:

答案 0 :(得分:2)

您可以使用分区外部联接,该联接比使用自联接和CROSS JOIN更有效:

Oracle设置

CREATE TABLE table_name ( City, Value ) AS
SELECT 'Helsinki', 1 FROM DUAL UNION ALL
SELECT 'Helsinki', 2 FROM DUAL UNION ALL
SELECT 'Helsinki', 5 FROM DUAL UNION ALL
SELECT 'Kuopio',   4 FROM DUAL UNION ALL
SELECT 'Kuopio',   5 FROM DUAL UNION ALL
SELECT 'Joensuu',  1 FROM DUAL UNION ALL
SELECT 'Joensuu',  2 FROM DUAL UNION ALL
SELECT 'Joensuu',  3 FROM DUAL

查询

SELECT city,
       v.value
FROM   ( SELECT LEVEL AS value
         FROM   DUAL
         CONNECT BY LEVEL <= ( SELECT MAX( value ) FROM table_name )
                             -- or just 5 if you want a static value
       ) v
       LEFT OUTER JOIN table_name t
       PARTITION BY ( t.City )
       ON ( v.value = t.value )
WHERE  t.value IS NULL

输出

CITY     | VALUE
:------- | ----:
Helsinki |     3
Helsinki |     4
Joensuu  |     4
Joensuu  |     5
Kuopio   |     1
Kuopio   |     2
Kuopio   |     3

db <>提琴here

答案 1 :(得分:1)

您可以CROSS JOIN列出具有可能值(1到5)的不同城市,然后使用LEFT JOIN反模式来识别缺少的值:

SELECT c.city, v.value
FROM 
    (SELECT DISTINCT city FROM mytable) c
    CROSS JOIN (SELECT rownum value FROM DUAL CONNECT BY level<= 5) v
    LEFT JOIN mytable t ON t.city = c.city AND t.value = v.value
WHERE t.city IS NULL
ORDER BY c.city, v.value

Demo on DB Fiddle

CITY     | VALUE
:------- | ----:
Helsinki |     3
Helsinki |     4
Joensuu  |     4
Joensuu  |     5
Kuopio   |     1
Kuopio   |     2
Kuopio   |     3

注意:生成值列表的另一种方法是从表中可用的不同值开始(而不是生成固定的数字列表)(这意味着表中所有可能的值都可用):

CROSS JOIN (SELECT DISTINCT values FROM mytable) v

答案 2 :(得分:1)

您可以使用MINUS运算符实现此目标-您的原始想法

SQL> with city as (
  2  select 'Helsinki' as name, 1 as value from dual union all
  3  select 'Helsinki' as name, 2 as value from dual union all
  4  select 'Helsinki' as name, 5 as value from dual union all
  5  select 'Kuopio' as name, 4 as value from dual union all
  6  select 'Kuopio' as name, 5 as value from dual union all
  7  select 'Joensuu' as name, 1 as value from dual union all
  8  select 'Joensuu' as name, 2 as value from dual union all
  9  select 'Joensuu' as name, 3 as value from dual
 10  )
 11  SELECT NAME, LVL
 12  FROM (SELECT DISTINCT NAME FROM CITY)
 13  JOIN (SELECT LEVEL AS LVL FROM DUAL
 14          CONNECT BY LEVEL <= 5) ON ( 1 = 1 )
 15  MINUS
 16  SELECT NAME, VALUE
 17    FROM CITY
 18  ORDER BY 1, 2;

NAME            LVL
-------- ----------
Helsinki          3
Helsinki          4
Joensuu           4
Joensuu           5
Kuopio            1
Kuopio            2
Kuopio            3

7 rows selected.

SQL>

干杯!