【问题标题】:SQL Find rows with missing columns based on another tableSQL 根据另一个表查找缺少列的行
【发布时间】:2021-05-22 01:58:36
【问题描述】:

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

给定一个租户表:

Tenant
1000
2000
3000

还有一个groups表,其中每一天对应一个新的group id,每个group有一对多租户,其中每个tenent对应一个subgroup id:

Date Group Tenant Subgroup
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

查找缺少租户的组:

Group Tenant
G2 3000
G3 1000
G4 2000
G4 3000

【问题讨论】:

    标签: sql postgresql oracle postgresql-11 oracle19c


    【解决方案1】:
    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', 'DD.MM.YYYY') AS date_col, 'G1' AS group_col, 2000 AS tenant, 'SG2' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('16.02.2021', 'DD.MM.YYYY') AS date_col, 'G1' AS group_col, 3000 AS tenant, 'SG3' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('17.02.2021', 'DD.MM.YYYY') AS date_col, 'G2' AS group_col, 1000 AS tenant, 'SG4' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('17.02.2021', 'DD.MM.YYYY') AS date_col, 'G2' AS group_col, 2000 AS tenant, 'SG5' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('18.02.2021', 'DD.MM.YYYY') AS date_col, 'G3' AS group_col, 2000 AS tenant, 'SG6' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('18.02.2021', 'DD.MM.YYYY') AS date_col, 'G3' AS group_col, 3000 AS tenant, 'SG7' AS subgroup FROM DUAL
            UNION ALL
            SELECT TO_DATE('19.02.2021', 'DD.MM.YYYY') AS date_col, 'G4' AS group_col, 1000 AS tenant, '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 否则您会将其调整到您的表中)。

    【讨论】:

      【解决方案2】:

      在 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
      

      【讨论】:

        【解决方案3】:

        我通过使用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;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-07
          • 2017-07-11
          • 2020-10-10
          • 2014-02-06
          • 1970-01-01
          • 1970-01-01
          • 2010-12-19
          • 2012-05-06
          相关资源
          最近更新 更多