在Oracle表中查找重复和缺失(空)值

时间:2018-06-27 13:24:20

标签: sql oracle join

我正在寻找表中的错误,并且希望报告重复项和缺失值。我不确定执行此操作的最佳方法,并且正在寻求实现此目标的更好方法的建议。这是在Oracle 12c中。

这似乎达到了预期的效果:

SELECT a.id, 
       a.mainfield, 
       a.location, 
       b.counter 
FROM   maintable a 
       INNER JOIN (
                    SELECT mainfield, 
                            Count(*) counter 
                    FROM   maintable 
                    GROUP  BY mainfield 
                    HAVING Count(mainfield) > 1 OR mainfield IS NULL
                  ) b ON a.mainfield = b.mainfield OR
                  ( a.mainfield IS NULL AND b.mainfield IS NULL ) 
ORDER  BY a.mainfield; 

这可以正常工作,并为我提供ID,可能为空的MAINFIELD,位置和重复MAINFIELD值或空MAINFIELD值的计数。

我可以使用更简单或更有效的方法吗?我不得不承认我的SQL技能非常生锈。

示例数据可能有帮助,也可能没有帮助,但是ID是主键,是数字,不能为空。其他字段都是NVARCHAR2并且可为空。这些都没有索引。这是输出的样子。有些记录是完全错误的。有些是明显的错别字。有些似乎是测试数据。

ID      MAINFIELD   LOCATION                            COUNTER
------- ---------   ---------------------------------   -------
16626   206000650   9A OLIVER ST CENTRAL STATION        2
18805   206000650   3 SWIFT CT CENTRAL STATION          2
22409   940000170   2 MARKET ST NEWARK DE               2
22003   940000170   1 MARKET ST NEWARK NJ               2
29533   970000030   95 MILL RD ANDOVER                  2
20256   970000030   12 RAILROAD AVE                     2
29018   978900050   44 BROAD STREET                     2
28432   978900050   WASHINGTON ST AND HAMILTON AVE      2
21831   980700050   BROADWAY NEWTOWN                    2
24147   980700050   MAIN STREET LEVITTOWN               2
26418                                                   3
26738               TEST DATA                           3
26755                                                   3

最后三行的MAINFIELD为空,并且有三条这样的记录(其中两行的位置也为空)。

在对以上数据进行了一些了解之后,我意识到我可能会考虑使用NVL来消除部分条件,例如这样(假设我选择的值在主字段中不是有效值):

SELECT a.id, 
       a.mainfield, 
       a.location, 
       b.counter 
FROM   maintable a 
       INNER JOIN (
                    SELECT mainfield, 
                            Count(*) counter 
                    FROM   maintable 
                    GROUP  BY mainfield 
                    HAVING Count(mainfield) > 1 OR mainfield IS NULL
                  ) b ON NVL(a.mainfield,'***NULL***') = NVL(b.mainfield.'***NULL***') 
ORDER  BY a.mainfield; 

这执行起来更快,并且似乎产生了预期的结果。我一直在尝试其他替代方案,但都没有成功,因此这可能是最好的替代方案。

我放弃的另一种选择可能适用于稍微不同的情况(但对我而言效果最差)是

SELECT  id, 
        mainfield, 
        location,
        COUNT (id) OVER (PARTITION BY mainfield) counter
FROM    maintable a
WHERE   mainfield IS NULL
OR      EXISTS(SELECT 1 from maintable b
            WHERE mainfield = a.mainfield AND ROWID <> a.ROWID)
ORDER BY a.mainfield;

我真的很喜欢将其组合在一起的方式,并希望它会有所帮助。我们并不是在说它运行了好几天,但是我试图在Oracle中重新学习使用SQL / DS进行编码时曾经具有的技能。

如果以上任何一项给任何人提供了更好的选择的想法,我将不胜感激。 (例如,是否有一种方法可以在WHERE子句中引用计数器[PARTITION BY主字段上的COUNT(标识)?)

再次感谢。

1 个答案:

答案 0 :(得分:1)

这似乎是Balazs Papp在dba.stackexchange.com板上提供的可读性,可靠性和效率之间的良好折衷: https://dba.stackexchange.com/a/210998/154392

SELECT * FROM (
SELECT  id, 
        mainfield, 
        location,
        COUNT (id) OVER (PARTITION BY mainfield) counter
FROM    maintable a
) where counter > 1 or mainfield IS NULL
ORDER BY mainfield;

这是原始帖子的最后一个替代方案的简化。就我所知,它似乎没有比我原来的替代方法低效率,但对我来说,它更具可读性。