如何去掉实际上是"duplicates"几乎相同的行,实际上只有部分列数据被切换?

How to get rid of almost identicall rows that are in fact "duplicates", and in fact, only some columns data are switched?

我在保存文件信息的数据库上工作。数据分布在几个 table 中,数据来自 File table,其中包含 file_id 在其他 table 中有相关数据,例如 [=19] =]、directoryhashes 等。我目前的目标是能够根据收集的早期文件哈希数据找到重复文件。附加目标是能够同时跨两个数据库进行查询,因此查询结果还将包括指示源数据库的值,在此查询中,这些值是虚拟​​的,并以 org_dbfnd_db 的形式出现在结果中占位符,正如我猜想的那样,它们的存在对解决我的问题很重要,所以我确实提到了它们的存在。

SELECT
    A.file_id org_file_id,
    B.file_id fnd_file_id,
    AF.directory_id org_dir_id,
    BF.directory_id fnd_dir_id,
    AD.disk_id org_disk,
    BD.disk_id fnd_disk,
    1 org_db,
    1 fnd_db
FROM fhash A, file AF, file BF, directory AD, directory BD
INNER JOIN fhash B ON B.data = A.data
WHERE
    A.file_id <> B.file_id AND
    A.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) AND
    B.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) AND
    A.file_id = AF._id AND
    B.file_id = BF._id AND
    AF.directory_id = AD._id AND
    BF.directory_id = BD._id AND
ORDER BY org_file_id


| org_file_id | fnd_file_id | org_dir_id | fnd_dir_id | org_disk | fnd_disk | org_db | fnd_db |
===============================================================================================
| 97          | 118         | 5          | 8          | 2        | 3        | 1      | 1      |
| 106         | 147         | 8          | 9          | 3        | 3        | 1      | 1      |
| 106         | 175         | 8          | 10         | 3        | 3        | 1      | 1      |
| 107         | 148         | 8          | 9          | 3        | 3        | 1      | 1      |
| 107         | 176         | 8          | 10         | 3        | 3        | 1      | 1      |
| 108         | 149         | 8          | 9          | 3        | 3        | 1      | 1      |
| 108         | 177         | 8          | 10         | 3        | 3        | 1      | 1      |
| 110         | 151         | 8          | 9          | 3        | 3        | 1      | 1      |
| 110         | 179         | 8          | 10         | 3        | 3        | 1      | 1      |
...
| 118         | 97          | 8          | 5          | 3        | 2        | 1      | 1      |
| 147         | 106         | 9          | 8          | 3        | 3        | 1      | 1      |
| 148         | 107         | 9          | 8          | 3        | 3        | 1      | 1      |
| 149         | 108         | 9          | 8          | 3        | 3        | 1      | 1      |
| 151         | 110         | 9          | 8          | 3        | 3        | 1      | 1      |
| 175         | 106         | 10         | 8          | 3        | 3        | 1      | 1      |
| 176         | 107         | 10         | 8          | 3        | 3        | 1      | 1      |
| 177         | 108         | 10         | 8          | 3        | 3        | 1      | 1      |
| 179         | 110         | 10         | 8          | 3        | 3        | 1      | 1      |

我得到的结果相当不错,可以在进一步处理后使用,但我得到的是我想要的两倍。对于每一行都有一个镜像,在 table 中更进一步,其中实际上接下来的四对列中的每一对都是较早行的副本,数据在相应列之间切换。

我想知道的是,我是否以及如何在不进行进一步处理的情况下直接从查询中获得正确的结果。

如果我只有两列并且没有磁盘、目录和数据库等其他因素,则修复会像更改一样简单

    A.file_id <> B.file_id AND

    A.file_id < B.file_id AND

另外这些行

    A.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) AND
    B.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) AND

只是示例,根据搜索条件的不同,它们会发生变化,这些也可能类似于

    A.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id = 0)) AND
    B.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id = 0)) AND

    A.file_id IN (SELECT _id FROM file WHERE directory_id IN ([query gets ids of dir  subdirs])) AND
    B.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) AND

或以其他方式。除了进一步修改以使其跨两个数据库工作之外,其余查询几乎保持不变。

对于此示例数据,我认为使用:

GROUP BY MIN(org_file_id, fnd_file_id), MAX(org_file_id, fnd_file_id)

其中 MIN() and MAX() 是 SQLite 的标量函数,将消除重复项:

SELECT A.file_id org_file_id,
       B.file_id fnd_file_id,
       AF.directory_id org_dir_id,
       BF.directory_id fnd_dir_id,
       AD.disk_id org_disk,
       BD.disk_id fnd_disk,
       1 org_db,
       1 fnd_db
FROM fhash A
INNER JOIN file AF ON A.file_id = AF._id
INNER JOIN directory AD ON AF.directory_id = AD._id
INNER JOIN fhash B ON B.data = A.data
INNER JOIN file BF ON B.file_id = BF._id
INNER JOIN directory BD ON BF.directory_id = BD._id
WHERE A.file_id <> B.file_id 
  AND A.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0)) 
  AND B.file_id IN (SELECT _id FROM file WHERE directory_id IN (SELECT _id FROM directory WHERE disk_id <> 0))
GROUP BY MIN(org_file_id, fnd_file_id), MAX(org_file_id, fnd_file_id)
ORDER BY org_file_id;

我也改为使用 ON 子句进行适当的显式连接。

查看简化版 demo