SQL查找重复字段(无唯一ID)解决方法
我试图使用vendor表和vendor\u address表中的几个字段从数据库中查找重复的供应商。问题是,我做的内部连接越多,查询丢失的潜在结果就越少。虽然我没有重复的供应商ID,但我正在寻找类似的潜在供应商 以下是我目前的疑问:SQL查找重复字段(无唯一ID)解决方法,sql,database,oracle,inner-join,Sql,Database,Oracle,Inner Join,我试图使用vendor表和vendor\u address表中的几个字段从数据库中查找重复的供应商。问题是,我做的内部连接越多,查询丢失的潜在结果就越少。虽然我没有重复的供应商ID,但我正在寻找类似的潜在供应商 以下是我目前的疑问: SELECT o.vendor_id ,o.vndr_name_shrt_user ,O.COUNTRY ,O.VENDOR_NAME_SHORT ,B.POSTAL ,B.ADDRESS1 ,SAME
SELECT
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,SAME_ADDRESS_NB
,SAME_POSTAL_NB
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
FROM VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
INNER JOIN (
SELECT vndr_name_shrt_user, COUNT(*) AS SAME_USER_NUM
FROM VENDOR
WHERE COUNTRY = 'CANADA'
AND VENDOR_STATUS = 'A'
GROUP BY vndr_name_shrt_user
HAVING COUNT(*) > 1
) oc on o.vndr_name_shrt_user = oc.vndr_name_shrt_user
INNER JOIN ( SELECT VENDOR_NAME_SHORT, COUNT(*) AS SAME_SHORT_NAME
FROM VENDOR
WHERE COUNTRY = 'CANADA'
AND VENDOR_STATUS = 'A'
GROUP BY VENDOR_NAME_SHORT
HAVING COUNT(*) > 1
) oc on o.VENDOR_NAME_SHORT = oc.VENDOR_NAME_SHORT
INNER JOIN (SELECT POSTAL, COUNT(*) AS SAME_POSTAL_NB
FROM vendor_addr
WHERE COUNTRY = 'CANADA'
AND COUNTRY ='CANADA'
AND POSTAL != ' '
GROUP BY POSTAL
HAVING COUNT(*) > 1
) oc on b.POSTAL = oc.POSTAL
INNER JOIN (SELECT ADDRESS1, COUNT(*) AS SAME_ADDRESS_NB
FROM ps_vendor_addr
WHERE COUNTRY = 'CANADA'
AND COUNTRY ='CANADA'
AND ADDRESS1 != ' '
GROUP BY ADDRESS1
HAVING COUNT(*) > 1
) oc on b.ADDRESS1 = oc.ADDRESS1
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA';
似乎您的连接有点有趣,原因不止一个。首先,你有内部连接,这将消除所有,但那些有所有的重复迹象-这是你不想要的东西。此外,您似乎在所有派生表上都有相同的别名oc——这不会在这里出现,而且您也不会走得太远 与其这样做,我建议您对每个复制符号重复基本查询,如下所示(我删除了相同的地址和邮政地址字段,您将看到原因): 对于这些重复符号中的每一个,您将向上面显示的省略号添加一个嵌套查询,如下所示-使用vndr_name_shrt_user中的重复项显示的示例:
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'SAME_USER_NUM' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.vndr_name_shrt_user in
(
SELECT
vndr_name_shrt_user
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY vndr_name_shrt_user
HAVING COUNT(*) > 1
)
您可以将所有这些查询合并在一起,然后查看所有重复的查询
作为旁注,您在最后三个派生表中检查了两次country='canada'
更新:显示多个重复标志
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'SAME_USER_NUM' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.vndr_name_shrt_user in
(
SELECT
vndr_name_shrt_user
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY vndr_name_shrt_user
HAVING COUNT(*) > 1
)
UNION ALL
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'VENDOR_NAME_SHORT' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.VENDOR_NAME_SHORT in
(
SELECT
VENDOR_NAME_SHORT
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY VENDOR_NAME_SHORT
HAVING COUNT(*) > 1
)
似乎您的连接有点有趣,原因不止一个。首先,你有内部连接,这将消除所有,但那些有所有的重复迹象-这是你不想要的东西。此外,您似乎在所有派生表上都有相同的别名oc——这不会在这里出现,而且您也不会走得太远
与其这样做,我建议您对每个复制符号重复基本查询,如下所示(我删除了相同的地址和邮政地址字段,您将看到原因):
对于这些重复符号中的每一个,您将向上面显示的省略号添加一个嵌套查询,如下所示-使用vndr_name_shrt_user中的重复项显示的示例:
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'SAME_USER_NUM' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.vndr_name_shrt_user in
(
SELECT
vndr_name_shrt_user
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY vndr_name_shrt_user
HAVING COUNT(*) > 1
)
您可以将所有这些查询合并在一起,然后查看所有重复的查询
作为旁注,您在最后三个派生表中检查了两次country='canada'
更新:显示多个重复标志
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'SAME_USER_NUM' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.vndr_name_shrt_user in
(
SELECT
vndr_name_shrt_user
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY vndr_name_shrt_user
HAVING COUNT(*) > 1
)
UNION ALL
select
o.vendor_id
,o.vndr_name_shrt_user
,O.COUNTRY
,O.VENDOR_NAME_SHORT
,B.POSTAL
,B.ADDRESS1
,OC.SAME_SHORT_NAME
,oc.SAME_USER_NUM
,'VENDOR_NAME_SHORT' as duplicateFlag
from VENDOR o
JOIN vendor_addr B ON o.VENDOR_ID = B.VENDOR_ID
WHERE O.COUNTRY ='CANADA'
AND B.COUNTY = 'CANADA'
AND o.VENDOR_NAME_SHORT in
(
SELECT
VENDOR_NAME_SHORT
FROM VENDOR
WHERE COUNTRY = o.country
AND VENDOR_STATUS = 'A'
GROUP BY VENDOR_NAME_SHORT
HAVING COUNT(*) > 1
)
让我们来看看一些有趣的数据,这些数据在不同的属性上具有链接副本:
CREATE TABLE data ( ID, A, B, C ) AS
SELECT 1, 1, 1, 1 FROM DUAL UNION ALL -- Related to #2 on column A
SELECT 2, 1, 2, 2 FROM DUAL UNION ALL -- Related to #1 on column A, #3 on B & C, #5 on C
SELECT 3, 2, 2, 2 FROM DUAL UNION ALL -- Related to #2 on columns B & C, #5 on C
SELECT 4, 3, 3, 3 FROM DUAL UNION ALL -- Related to #5 on column A
SELECT 5, 3, 4, 2 FROM DUAL UNION ALL -- Related to #2 and #3 on column C, #4 on A
SELECT 6, 5, 5, 5 FROM DUAL; -- Unrelated
现在,我们可以使用分析函数(无任何联接)获得一些关系:
其中:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 2
4 3 3 3 4
5 3 4 2 2
6 5 5 5 6
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
1 1 1 1 4
2 1 2 2 4
3 2 2 2 4
4 3 3 3 4
5 3 4 2 4
6 5 5 5 6
但这并不能说明4和5有关,5和2有关,然后是1
这可以通过分层查询找到:
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM data
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
但这将产生许多重复的行(因为它不知道从何处开始层次结构,因此将依次选择每一行作为根)-相反,当ID
和duplicate\u的值相同时,您可以使用第一个查询为层次结构查询提供一个起点:
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM (
SELECT d.*,
LEAST(
FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
) AS duplicate_of
FROM data d
)
START WITH id = duplicate_of
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
其中:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 2
4 3 3 3 4
5 3 4 2 2
6 5 5 5 6
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
1 1 1 1 4
2 1 2 2 4
3 2 2 2 4
4 3 3 3 4
5 3 4 2 4
6 5 5 5 6
仍然有一些行被复制,因为在搜索中出现了局部极小值a#4。。。可通过简单的分组将其删除
:
SELECT id, a, b, c,
MIN( duplicate_of ) AS duplicate_of
FROM (
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM (
SELECT d.*,
LEAST(
FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
) AS duplicate_of
FROM data d
)
START WITH id = duplicate_of
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c )
)
GROUP BY id, a, b, c;
它给出了输出:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
6 5 5 5 6
让我们来看看一些有趣的数据,这些数据在不同的属性上具有链接副本:
CREATE TABLE data ( ID, A, B, C ) AS
SELECT 1, 1, 1, 1 FROM DUAL UNION ALL -- Related to #2 on column A
SELECT 2, 1, 2, 2 FROM DUAL UNION ALL -- Related to #1 on column A, #3 on B & C, #5 on C
SELECT 3, 2, 2, 2 FROM DUAL UNION ALL -- Related to #2 on columns B & C, #5 on C
SELECT 4, 3, 3, 3 FROM DUAL UNION ALL -- Related to #5 on column A
SELECT 5, 3, 4, 2 FROM DUAL UNION ALL -- Related to #2 and #3 on column C, #4 on A
SELECT 6, 5, 5, 5 FROM DUAL; -- Unrelated
现在,我们可以使用分析函数(无任何联接)获得一些关系:
其中:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 2
4 3 3 3 4
5 3 4 2 2
6 5 5 5 6
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
1 1 1 1 4
2 1 2 2 4
3 2 2 2 4
4 3 3 3 4
5 3 4 2 4
6 5 5 5 6
但这并不能说明4和5有关,5和2有关,然后是1
这可以通过分层查询找到:
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM data
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
但这将产生许多重复的行(因为它不知道从何处开始层次结构,因此将依次选择每一行作为根)-相反,当ID
和duplicate\u的值相同时,您可以使用第一个查询为层次结构查询提供一个起点:
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM (
SELECT d.*,
LEAST(
FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
) AS duplicate_of
FROM data d
)
START WITH id = duplicate_of
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c );
其中:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 2
4 3 3 3 4
5 3 4 2 2
6 5 5 5 6
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
1 1 1 1 4
2 1 2 2 4
3 2 2 2 4
4 3 3 3 4
5 3 4 2 4
6 5 5 5 6
仍然有一些行被复制,因为在搜索中出现了局部极小值a#4。。。可通过简单的分组将其删除
:
SELECT id, a, b, c,
MIN( duplicate_of ) AS duplicate_of
FROM (
SELECT id, a, b, c,
CONNECT_BY_ROOT( id ) AS duplicate_of
FROM (
SELECT d.*,
LEAST(
FIRST_VALUE( id ) OVER ( PARTITION BY a ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY b ORDER BY id ),
FIRST_VALUE( id ) OVER ( PARTITION BY c ORDER BY id )
) AS duplicate_of
FROM data d
)
START WITH id = duplicate_of
CONNECT BY NOCYCLE ( PRIOR a = a OR PRIOR b = b OR PRIOR c = c )
)
GROUP BY id, a, b, c;
它给出了输出:
ID A B C DUPLICATE_OF
-- - - - ------------
1 1 1 1 1
2 1 2 2 1
3 2 2 2 1
4 3 3 3 1
5 3 4 2 1
6 5 5 5 6
你为什么要加入?对于不希望丢失数据的位置,请使用左外部联接。请提供一个包含表的DDL语句和一些示例数据的DML语句以及该数据的预期输出。谢谢您,Tough先生。为什么要进行内部联接?对于您不希望丢失数据的位置,请使用左外部联接。请提供一个包含表的DDL语句和一些示例数据的DML语句以及该数据的预期输出。谢谢您,先生,Tough只有一个重复的标志使重复标志的查询完全打开,不是吗?或者我创建了与duplicateFlag2?您可以将不同的重复标志放在最后一列-我将用一个示例更新查询如果我删除OC.SAME_SHORT_NAME,OC.SAME_USER_NUM,因为我在原始查询中创建了它们+我得到了太多的错误结果,多亏了btwYes,我也会删除这些字段——因为现在您将拥有潜在重复的供应商的ID,以及怀疑重复的字段。你如何确定你在这个列表上得到了误报?我在误报atm上阅读抱歉,我仍然得到了错误,嵌套的select和union ALL的行太多只有一个重复的标志使查询完全打开重复的标志,不是吗?或者我创建了与duplicateFlag2相同的用户数?你会放置不同的重复项标记为最后一列-我将用一个示例更新查询如果我删除OC.SAME_SHORT_NAME,OC.SAME_USER_NUM,因为我在原始查询中创建了它们+我得到了太多错误结果,多亏了很多btwYes,我还将删除这些字段-因为现在您将拥有ven的ID