按两列分组,OR逻辑忽略空值(Oracle)

kqlmhetl  于 2023-10-16  发布在  Oracle
关注(0)|答案(4)|浏览(99)

我有一个包含两个ID值的表。密钥是ID组合,其中一个ID可以为空,但不能同时为空。比较键时忽略空值。就像这样:

ID1  ID2   TIMESTAMP
___________________________
A    1     2023-09-01 11:00
A    null  2023-09-01 10:00
B    null  2023-09-01 09:00
null 1     2023-09-01 08:00 
B    2     2023-09-01 07:00

根据数据模型,ID 1不应与最多一个ID 2匹配(因此情况A 1、B 1是不可能的)。我需要按 * 键 * 计数行,即。第1,2,4行和第3,5行应该被视为相同,group by应该产生类似的结果:

ID1 ID2 COUNT
_____________
A    1    3
B    2    2

用SQL可以做到这一点吗?Oracle 19c的

dtcbnfnu

dtcbnfnu1#

您可以使用相关子查询:

SELECT id1,
       id2,
       ( SELECT COUNT(*)
         FROM   table_name c
         WHERE  ( c.id1 = t.id1 AND c.id2 = t.id2 )
         OR     ( c.id1 = t.id1 AND c.id2 IS NULL )
         OR     ( c.id1 IS NULL AND c.id2 = t.id2 )
       ) AS cnt
FROM   table_name t
WHERE  id1 IS NOT NULL
AND    id2 IS NOT NULL;

其中,对于样本数据:

CREATE TABLE table_name (ID1, ID2, TIMESTAMP) AS
SELECT 'A',  1,     DATE '2023-09-01' + INTERVAL '11:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'A',  null,  DATE '2023-09-01' + INTERVAL '10:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'B',  null,  DATE '2023-09-01' + INTERVAL '09:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT null, 1,     DATE '2023-09-01' + INTERVAL '08:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'B',  2,     DATE '2023-09-01' + INTERVAL '07:00' HOUR TO MINUTE FROM DUAL;

输出:
| ID1| ID2| CNT|
| --|--|--|
| 一| 1 | 3 |
| B| 2 | 2 |
fiddle

jobtbby3

jobtbby32#

您正在查找ID1和ID2都不为空的组。在这些组中,您希望计算与任一ID匹配的所有行。为此使用相关子查询。

select
  id1, id2,
  (
    select count(*)
    from mytable all_matches
    where all_matches.id1 = mytable.id1
       or all_matches.id2 = mytable.id2
  ) as total
from mytable
where id1 is not null and id2 is not null;

演示:https://dbfiddle.uk/UQcmFgGC

4dc9hkyq

4dc9hkyq3#

最后,我以下面的查询结束:

with subquery as (
    select * from (
    select COALESCE(id1, LAG(id1) OVER (PARTITION BY id2 order by id1)) as id1, 
           COALESCE(id2, LAG(id2) OVER (PARTITION BY id1 order by id2)) as id2,
    count(*) count 
    from T group by id1, id2 order by id1, id2
    )
)
select id1, id2, sum(count) from subquery group by id1, id2 order by id1, id2

感谢JonasMetzler的建议。

cbwuti44

cbwuti444#

注意:这回答了5th revision of the question,而不是后来的编辑。
在Oracle 12中,您可以使用MATCH_RECOGNIZE进行逐行模式匹配:

SELECT *
FROM   table_name
MATCH_RECOGNIZE (
  ORDER BY timestamp
  MEASURES
    id1_id2.id1 AS id1,
    id1_id2.id2 AS id2,
    COUNT(*) AS cnt
  PATTERN ( (null_id1* id1_id2 null_id1*) | (null_id2* id1_id2 null_id2*) )
  DEFINE
    id1_id2  AS id1 IS NOT NULL AND id2 IS NOT NULL,
    null_id1 AS id1 IS NULL,
    null_id2 AS id2 IS NULL
)

其中,对于样本数据:

CREATE TABLE table_name (ID1, ID2, TIMESTAMP) AS
SELECT 'A',  1,     DATE '2023-09-01' + INTERVAL '11:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'A',  null,  DATE '2023-09-01' + INTERVAL '10:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'B',  null,  DATE '2023-09-01' + INTERVAL '09:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT null, 1,     DATE '2023-09-01' + INTERVAL '08:00' HOUR TO MINUTE FROM DUAL UNION ALL
SELECT 'B',  2,     DATE '2023-09-01' + INTERVAL '07:00' HOUR TO MINUTE FROM DUAL;

输出:
| ID1| ID2| CNT|
| --|--|--|
| B| 2 | 2 |
| 一| 1 | 3 |
fiddle

相关问题