SQL 根据另一个表查找缺少列的行

问题描述

我有一个场景,我需要使用一个有效元素表来查找另一个表中缺少这些元素的记录,以便我可以反过来修补它们。这有点棘手,因为缺少的列数据在“嵌套”列(例如,它在另一列中具有重复条目)。我觉得某种 LEFT OUTER JOIN 可能在这里起作用,但我不能完全理解。 FWIW,我的基准是 Oracle 19c,但我最终也需要支持 Postgres 11+。问题总结为:

给定租户表:

租户
1000
2000
3000

还有一个组表,其中每一天对应一个新的组id,每个组有一对多的租户,其中每个租户对应一个子组id:

日期 租户 子组
2021-02-16 G1 1000 SG1
2021-02-16 G1 2000 SG2
2021-02-16 G1 3000 SG3
2021-02-17 G2 1000 SG4
2021-02-17 G2 2000 SG5
2021-02-18 G3 2000 SG6
2021-02-18 G3 3000 SG7
2021-02-19 G4 1000 SG8

查找缺少租户的组:

租户
G2 3000
G3 1000
G4 2000
G4 3000

解决方法

WITH
   tab1 AS
      ( SELECT TO_DATE('16.02.2021','DD.MM.YYYY') AS date_col,'G1' AS group_col,1000 AS tenant,'SG1' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('16.02.2021',2000 AS tenant,'SG2' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('16.02.2021',3000 AS tenant,'SG3' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('17.02.2021','G2' AS group_col,'SG4' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('17.02.2021','SG5' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('18.02.2021','G3' AS group_col,'SG6' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('18.02.2021','SG7' AS subgroup FROM DUAL
        UNION ALL
        SELECT TO_DATE('19.02.2021','G4' AS group_col,'SG8' AS subgroup FROM DUAL
      ),tab2 AS
      ( SELECT 1000 AS tenant FROM DUAL
        UNION ALL
        SELECT 2000 AS tenant FROM DUAL
        UNION ALL
        SELECT 3000 AS tenant FROM DUAL
      )
SELECT *
  FROM ( SELECT t1.group_col,t2.tenant
           FROM ( SELECT DISTINCT group_col FROM tab1) t1
           CROSS JOIN tab2 t2
       ) x
 WHERE NOT EXISTS ( SELECT *
                      FROM tab1
                     WHERE tab1.group_col = x.group_col
                       AND tab1.tenant = x.tenant
                  )
  ORDER BY group_col,tenant;

结果:

GR     TENANT
-- ----------
G2       3000
G3       1000
G4       2000
G4       3000

该查询也适用于 Postgres(然后删除 FROM DUAL,否则您将使其适应您的表格)。

,

在 Oracle 中,您可以使用 partitioned outer join 来填充缺失的行,然后您可以仅选择这些行

select g.group_col,t.tenant
  from groups g partition by (group_col)
 right outer join tenants t on t.tenant = g.tenant
 where g.tenant is null
,

我通过使用 cross join 生成所有行然后删除存在的行来解决这个问题。以下是标准 SQL,适用于 Oracle 和 Postgres:

select g.group_id,t.tenant
from tenants t cross join
     (select distinct group_id from groups) g left join
     groups g2
     using (tenant,group_id)
where g2.tenant is null;

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...