我有一个主表,其中数据从外部源加载。主表的表结构 - PROD_MAIN是
PROD_ROW_ID | PROD_VALUE | PROD_TYPE | PROD_DATE
数据从主表加载到另外两个表中。这两个表是:
PROD, PROD_ENT
使用以下条件连接PROD和PROD_ENT表。
PROD.PROD_ROW_ID = PROD_ENT.PROD_PAR_ID
每天将数据从PROD_MAIN插入到这两个表PROD和PROD_ENT表中。由于一些数据库问题,许多记录错过了加载到PROD和PROD_ENT表中。
所以,我需要检查3个月的遗失记录,即11月19日至2月19日;没有加载到PROD和PROD_ENT表中。 所有这些表都有大约2亿条记录。
所以,我写了下面的查询来得到结果。然而它给我零记录。你能帮忙吗?
SELECT /*+ PARALLEL (PROD_MAIN,15) */ MH.*
FROM PROD PMN,
PROD_ENT PCH,
PROD_MAIN MH
WHERE PMN.PROD_ROW_ID = PCH.PROD_PAR_ID
AND MH.PROD_ROW_ID(+) = PMN.PROD_ROW_ID
AND MH.PROD_VALUE(+) = PCH.PROD_VALUE
AND MH.PROD_TYPE(+) = PMN.PROD_TYPE
AND MH.PROD_DATE (+) = PCH.PROD_DATE
AND MH.PROD_ROW_ID IS NULL
AND MH.PROD_VALUE IS NULL
AND MH.PROD_TYPE IS NULL
AND MH.PROD_DATE IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
*****编辑代码*****
以防万一 1.如果我需要获取PROD_MAIN表中的PRESENT记录而不是PROD中的PRESENT记录。 2.如果我需要获取PROD_MAIN中的PRESENT记录 表和NOT PRESENT分别在PROD_ENT表中,我是否需要编写如下所示的联合查询,还是有其他简单方法可以这样做?
SELECT MH.*
FROM PROD_MAIN AS MH
LEFT JOIN PROD AS PMN
ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID
AND PMN.PROD_TYPE = MH.PROD_TYPE)
LEFT JOIN PROD_ENT AS PCH
ON (PCH.PROD_PAR_ID = PMN.PROD_ROW_ID
AND PCH.PROD_DATE = MH.PROD_DATE
AND PCH.PROD_VALUE = MH.PROD_VALUE)
WHERE PMN.PROD_ROW_ID IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
UNION
SELECT MH.*
FROM PROD_MAIN AS MH
LEFT JOIN PROD AS PMN
ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID
AND PMN.PROD_TYPE = MH.PROD_TYPE)
LEFT JOIN PROD_ENT AS PCH
ON (PCH.PROD_PAR_ID = PMN.PROD_ROW_ID
AND PCH.PROD_DATE = MH.PROD_DATE
AND PCH.PROD_VALUE = MH.PROD_VALUE)
WHERE PCH.PROD_PAR_ID IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
答案 0 :(得分:1)
看起来你的逻辑是有缺陷的。您说数据是从PROD_MAIN加载到其他表中的。因此,您需要查找该表中的行,但不要查找PROD和PROD_ENT中的行。
但是,您的反连接正在过滤PROD_MAIN列。这两个过滤器永远不会两个都是真的:
MH.PROD_DATE IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
同样,如果您在PROD和PROD_ENT中查找不存在的行,则此连接条件永远不会为真:
PMN.PROD_ROW_ID = PCH.PROD_PAR_ID
几乎可以肯定,您需要检查PROD和PROD_ENT中的连接列是否为空。我正在使用ANSI 92语法,因为它使外连接更容易理解。
SELECT /*+ PARALLEL (PROD_MAIN,15) */ MH.*
FROM PROD_MAIN MH
left outer join PROD PMN
on MH.PROD_ROW_ID = PMN.PROD_ROW_ID
and MH.PROD_TYPE = PMN.PROD_TYPE
left outer join PROD_ENT PCH
on MH.PROD_ROW_ID = PCH.PROD_PAR_ID
and MH.PROD_VALUE = PCH.PROD_VALUE
and MH.PROD_DATE = PCH.PROD_DATE
where MH.PROD_DATE BETWEEN date '2015-11-19' AND date '2016-02-19'
AND PCH.PROD_PAR_ID IS NULL
AND PMN.PROD_ROW_ID IS NULL
不确定join子句中是否所有这些列都是必需的:我只是复制了你的连接逻辑。
“我又有一个小场景......我可以写一个像主要问题中更新的联合查询吗?”
您编写查询的方式将产生结果,但您将无法区分这三个类别(在PROD中,但在PROD_ENT中,PROD_ENT中没有,而PROD_ENT中没有)。这将是您稍微修改查询所需的有用信息:
SELECT 'PROD' as tgt_table, MH.*
FROM PROD_MAIN AS MH
LEFT JOIN PROD AS PMN
ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID
AND PMN.PROD_TYPE = MH.PROD_TYPE)
WHERE PMN.PROD_ROW_ID IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
UNION ALL
SELECT 'PROD_ENT' as tgt_table, MH.*
FROM PROD_MAIN AS MH
LEFT JOIN PROD AS PMN
ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID
AND PMN.PROD_TYPE = MH.PROD_TYPE)
LEFT JOIN PROD_ENT AS PCH
ON (PCH.PROD_PAR_ID = PMN.PROD_ROW_ID
AND PCH.PROD_DATE = MH.PROD_DATE
AND PCH.PROD_VALUE = MH.PROD_VALUE)
WHERE PCH.PROD_PAR_ID IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
使用UNION ALL而不是UNION来避免不必要的排序。
您在PROD_ENT上的外部加入版本与我的版本不同。您的版本加入PCH.PROD_PAR_ID = PMN.PROD_ROW_ID,因此它会为PROD_ENT记录提供误报,这些记录实际存在但在PROD中缺少所有者记录。如果这种情况永远不会发生,那么这并不重要,但是当您在加载过程中似乎正在调查淤泥时,您可能应该尽可能精确。
答案 1 :(得分:0)
我需要获取那些在PROD_MAIN表中是PRESENT并且在PROD和PROD_ENT表中不存在的记录
尝试:
SELECT PROD_ROW_ID -- DELETE -- To realy delete remove 'SELECT PROD_ROW_ID -- '
FROM PROD_MAIN
WHERE PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016' AND
(PROD_ROW_ID NOT IN (SELECT PROD_PAR_ID FROM PROD_ENT)
AND -- or OR if the record should be deleted if not present in one of the two tables
PROD_ROW_ID NOT IN (SELECT PROD_ROW_ID FROM PROD))
请注意,我猜测......_ ID列是所有三个表中的主键
答案 2 :(得分:0)
你必须使用左连接 -
SELECT MH.*
FROM PROD_MAIN AS MH
LEFT JOIN PROD AS PMN
ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID
AND PMN.PROD_TYPE = MH.PROD_TYPE)
LEFT JOIN PROD_ENT AS PCH
ON (PCH.PROD_PAR_ID = PMN.PROD_ROW_ID
AND PCH.PROD_DATE = MH.PROD_DATE
AND PCH.PROD_VALUE = MH.PROD_VALUE)
WHERE PMN.PROD_ROW_ID IS NULL OR PCH.PROD_PAR_ID IS NULL
AND MH.PROD_DATE BETWEEN '19-NOV-2015' AND '19-FEB-2016'
请注意,以下行是分隔PROD_MAIN中但不在PROD或PROD_ENT中的条目的关键
WHERE PMN.PROD_ROW_ID IS NULL OR PCH.PROD_PAR_ID IS NULL
通过使用左连接,您首先考虑左表中的所有行,即PROD_MAIN,然后您还通过比较PROD_ROW_ID(忽略PROD_TYPE
来获取与右表相匹配的行,即PROD。简单)。
LEFT JOIN PROD AS PMN ON (PMN.PROD_ROW_ID = MH.PROD_ROW_ID)
如果PROD_MAIN中存在PROD_ROW_ID(再次忽略PROD_TYPE)但该PROD中没有PROD,那么PROD的所有列都将包含null。因此,在WHERE
子句中,您只需检查右表中的任何列为空
WHERE PMN.PROD_ROW_ID IS NULL