【问题标题】:SELECTing "first" (as determined by ORDER BY) row FROM near-duplicate rows (as determined by GROUP BY, HAVING, COUNT) within SQLite在 SQLite 中从几乎重复的行(由 GROUP BY、HAVING、COUNT 确定)中选择“第一”行(由 ORDER BY 确定)
【发布时间】:2011-11-15 12:50:20
【问题描述】:

我有一个超出我能力范围的问题(我真的很高兴我是 Beta)涉及重复项(所以 GROUP BYHAVINGCOUNT),通过将解决方案保持在SQLite 附带的标准函数。我正在使用 Python 中的 sqlite3 模块。

示例表工作者,列:

* ID: integer, auto-incrementing
* ColA: integer
* ColB: varchar(20)
* UserType: varchar(20)
* LoadMe: Boolean   

(是的,SQLite 的数据类型是标称的)

我的数据表,Workers,一开始看起来像:

ID  ColA  ColB  UserType  LoadMe
1   1     a     Alpha     0
2   1     b     Beta      0
3   2     a     Alpha     0
4   2     a     Beta      0
5   2     b     Delta     0
6   2     b     Alpha     0
7   1     a     Delta     0
8   1     b     Epsilon   0 
9   1     c     Gamma     0
10  4     b     Delta     0
11  5     a     Alpha     0
12  5     a     Beta      0
13  5     b     Gamma     0
14  5     a     Alpha     0

为了在新工厂装载到卡车上,我想启用在 ColA 和 ColB 之间具有独特组合的所有工人。对于那些 ColA 和 ColB 的独特组合有多个工人的重复项(双胞胎、三胞胎等,可能通过 Bokanovsky 的过程),我想从每组重复项中只选择一个。为了使问题更难解决,我还希望能够根据 ORDER BY 的某种形式的 UserType 从每组重复项中选择一个。我可能希望选择用户类型为“Alpha”的第一个“副本”来解决一个非常聪明的问题,或者ORDER BY UserType DESC,我可以为最低级别的工人下达黑色束腰外衣的订单。

您可以看到 ID 9、10 和 13 具有 ColA 和 ColB 的唯一组合,并且最容易识别。但是,1-a、1-b、2-a、2-b 和 5-a 组合中存在重复项。

我目前的流程,就目前而言:

0) 每个人都有一个唯一的 ID 号。这是在出生时完成的。

1) SET 所有 Worker 到 LoadMe = 1。

UPDATE Workers
SET LoadMe = 1

2) 根据两列(GROUP BY ColA、ColB)中的相似性查找我的重复项:

SELECT Wk1.*
FROM Workers AS Wk1
INNER JOIN (
    SELECT ColA, ColB
    FROM Workers
    GROUP BY ColA, ColB
    HAVING COUNT(*) > 1
) AS Wk2
ON Wk1.ColA = Wk2.ColA
AND Wk1.ColB = Wk2.ColB
ORDER BY ColA, ColB

3) 将我所有的副本设置为 LoadMe = 0。

UPDATE Workers
SET LoadMe = 0
WHERE ID IN (
    SELECT Wk1.ID
    FROM Workers AS Wk1
    INNER JOIN (
        SELECT ColA, ColB
        FROM Workers
        GROUP BY ColA, ColB
        HAVING COUNT(*) > 1
    ) AS Wk2
    ON Wk1.ColA = Wk2.ColA
    AND Wk1.ColB = Wk2.ColB
)

4) 对于我的GROUP BYORDERed BY UserTypeSELECT 中的每组重复项,只有一个,即列表中的第一个,将 LoadMe SET 设置为 1。

这个表格看起来像:

ID  ColA  ColB  UserType  LoadMe
1   1     a     Alpha     1
2   1     b     Beta      1
3   2     a     Alpha     1
4   2     a     Beta      0
5   2     b     Delta     0
6   2     b     Alpha     1
7   1     a     Delta     0
8   1     b     Epsilon   0
9   1     c     Gamma     1
10  4     b     Delta     1
11  5     a     Alpha     1
12  5     a     Beta      0
13  5     b     Gamma     1
14  5     a     Alpha     0

ORDERed BY ColA、ColB、UserType,然后是 ID,并由 GROUP BY 列分开,(为了清楚起见,最后隔开)相同的数据可能如下所示:

ID  ColA  ColB  UserType  LoadMe
1   1     a     Alpha     1
7   1     a     Delta     0

2   1     b     Beta      1
8   1     b     Epsilon   0

9   1     c     Gamma     1

3   2     a     Alpha     1
4   2     a     Beta      0

6   2     b     Alpha     1
5   2     b     Delta     0

10  4     b     Delta     1

11  5     a     Alpha     1
14  5     a     Alpha     0
12  5     a     Beta      0

13  5     b     Gamma     1

我对最后一步感到困惑,觉得自己像个 Epsilon-minus 半白痴。我之前一直将重复项从数据库中提取到程序空间中并在 Python 中工作,但这种情况并不少见,我想更永久地解决这个问题。

【问题讨论】:

    标签: sqlite aggregate-functions


    【解决方案1】:

    我喜欢把这样的问题分解一下。第一步是识别唯一的 ColA、ColB 对:

    SELECT ColA,ColB FROM Workers GROUP BY ColA,ColB
    

    现在,对于这些对中的每一对,您都想找到最高优先级的记录。连接不起作用,因为您最终会为每个唯一对获得多条记录,但子查询将起作用:

    SELECT ColA,ColB,
        (SELECT id FROM Workers w1 
        WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
        ORDER BY UserType LIMIT 1) AS id
    FROM Workers w2 GROUP BY ColA,ColB;
    

    您可以更改子查询中的ORDER BY 子句来控制优先级。 LIMIT 1 确保每个子查询只有一条记录(否则 sqlite 将返回与 WHERE 子句匹配的最后一条记录,尽管我不确定是否保证)。

    此查询的结果是要使用ColA, ColB, id 加载的记录列表。我可能会直接从中工作并摆脱LoadMe,但如果你想保留它,你可以这样做:

    BEGIN TRANSACTION;
    UPDATE Workers SET LoadMe=0;
    UPDATE Workers SET LoadMe=1
    WHERE id IN (SELECT 
        (SELECT id FROM Workers w1 
        WHERE w1.ColA=w2.ColA AND w1.ColB=w2.ColB 
        ORDER BY UserType LIMIT 1) AS id
        FROM Workers w2 GROUP BY ColA,ColB);
    COMMIT;
    

    这会清除 LoadMe 标志,然后为我们最后一次查询返回的每条记录将其设置为 1。事务保证这一切都发生或失败作为一个步骤,并且永远不会让您的 LoadMe 字段处于不一致的状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-27
      • 2014-01-30
      相关资源
      最近更新 更多