循环遍历表的每个记录并对所有其他记录执行计算

时间:2015-01-01 20:17:51

标签: mysql sql

我想在我的表NO_TOP_RATING

中计算working的值

NO_TOP_RATING的计算方法是:

  • 对于每一行,获取该记录的ANNDATS_CONVERTED之前的所有其他行,并且与该记录具有相同的ESTIMID
  • 从中找到最低IRECCD值。
  • 然后,计算相同ANALYST的{​​{1}}与所计算的最低IRECCD相匹配的次数。

注意:这应该省略正在计算的当前行(因此要查找行ID 1的值,不要在计算中使用此行)以及IRECCD所在的任何记录应该完全忽略空白。

ANALYST

working

所以 - 在为记录#1 计算 | ID | ANALYST | ESTIMID | ANNDATS_CONVERTED | IRECCD | NO_TOP_RATING | --------------------------------------------------------------------------------- | 1 | DAVE | Brokerage000 | 1998-07-01 | 2 | | | 2 | DAVE | Brokerage000 | 1998-06-28 | 2 | | | 3 | DAVE | Brokerage000 | 1998-07-02 | 4 | | | 4 | DAVE | Brokerage000 | 1998-07-04 | 3 | | | 5 | SAM | Brokerage000 | 1998-06-14 | 1 | | | 6 | SAM | Brokerage000 | 1998-06-28 | 4 | | | 7 | | Brokerage000 | 1998-06-28 | 1 | | | 8 | DAVE | Brokerage111 | 1998-06-28 | 5 | | 时:

  • 记录#1 包含在计算中,因为我想从计算中省略它
  • 记录#7 根本不会 包含在计算中,因为NO_TOP_RATING为空白
  • 记录#8 包含在计算中,因为ANALYST与记录#1不同

预期结果:

ESTIMID

working

这是我到目前为止的MySQL:

| ID | ANALYST |   ESTIMID    | ANNDATS_CONVERTED |   IRECCD    | NO_TOP_RATING |
---------------------------------------------------------------------------------
| 1  |  DAVE   | Brokerage000 |    1998-07-01     |     2       |       0       |
| 2  |  DAVE   | Brokerage000 |    1998-06-28     |     2       |       0       |
| 3  |  DAVE   | Brokerage000 |    1998-07-02     |     4       |       0       |
| 4  |  DAVE   | Brokerage000 |    1998-07-04     |     3       |       0       |
| 5  |  SAM    | Brokerage000 |    1998-06-14     |     1       |       0       |
| 6  |  SAM    | Brokerage000 |    1998-06-28     |     4       |       1       |
| 7  |         | Brokerage000 |    1998-06-28     |     1       |               |
| 8  |  DAVE   | Brokerage111 |    1998-06-28     |     5       |       0       |

这适用于PHP,循环遍历每条记录并评估每条记录的所有其他记录。这涉及循环并在大型数据库上花费很长时间。我试图用MySQL实现相同的结果。

1 个答案:

答案 0 :(得分:2)

我采取了一些措施来解决这个问题。我做的第一件事是写一个JOIN,它得到了我需要的所有行。我在几个条件下加入了这个表:

  • estimid匹配
  • id值不一样
  • 两个表中的分析师列都不为空
  • 一张桌子的anndats_converted在另一张桌子的前一年内。

为了测试,我从两个表中选择了id以确保我得到了正确的配对:

SELECT w.id, wo.id
FROM working w
JOIN working wo 
    ON w.estimid = wo.estimid
    AND w.id != wo.id
    AND w.analyst IS NOT NULL
    AND wo.analyst IS NOT NULL
    AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
ORDER BY w.id;

简短的结果集显示以下配对:

| id | id |
+----+----+
| 1  | 2  |
| 1  | 5  |
| 1  | 6  |
| 2  | 5  |
| 2  | 6  |

这似乎符合您的要求。对于id#1,排除第1行(因为正在计算)第3行和第4行不在正确的日期范围内,第7行为空,第8行是不同的estimid。

然后,我使用聚合函数通过第一个表分组来计算最小ireccd:

SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
FROM working w
JOIN working wo 
    ON w.estimid = wo.estimid
    AND w.id != wo.id
    AND w.analyst IS NOT NULL
    AND wo.analyst IS NOT NULL
    AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
GROUP BY w.id;

下一部分也很棘手,所以我将分两步解释。我使用原始表加入了上述查询,其中唯一的条件是分析师列匹配。这样做是在某种程度上创造了笛卡尔积。查询看起来像这样:

SELECT *
FROM working w
LEFT JOIN(
    SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
    FROM working w
    LEFT JOIN working wo 
        ON w.estimid = wo.estimid
        AND w.id != wo.id
        AND w.analyst IS NOT NULL
        AND wo.analyst IS NOT NULL
        AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
    GROUP BY w.id) temp ON temp.analyst = w.analyst;

我看到每个人都有可能的配对,如下:

| id | analyst | ireccd | id | analyst | min_ireccd |
+----+---------+--------+----+---------+------------+
| 1  |  DAVE   |    2   | 8  |  DAVE   |      null  |
| 1  |  DAVE   |    2   | 4  |  DAVE   |      1     |
| 1  |  DAVE   |    2   | 1  |  DAVE   |      1     |
| 1  |  DAVE   |    2   | 2  |  DAVE   |      1     |
| 1  |  DAVE   |    2   | 3  |  DAVE   |      1     |

请注意,将第一个DAVE与表格中DAVE的所有其他行进行比较。 另请注意我更改了上面的内部查询以包含外部联接,以便考虑所有行。如果没有要计算的内容,min_ireccd将为空。

我做的最后一件事是使用该结果集,并计算ireccd与min_ireccd匹配的次数。我按id分组,所以在上面的示例集中,它从不匹配,因此计数将为0.这是最终查询。它将空值(第7行)保留为null,因为这是您的预期结果显示的内容:

SELECT w.*, SUM(w.ireccd = temp.min_ireccd) AS NO_TOP_RATING
FROM working w
LEFT JOIN(
    SELECT w.id, w.analyst, MIN(wo.ireccd) AS min_ireccd
    FROM working w
    LEFT JOIN working wo 
        ON w.estimid = wo.estimid
        AND w.id != wo.id
        AND w.analyst IS NOT NULL
        AND wo.analyst IS NOT NULL
        AND wo.anndats_converted BETWEEN DATE_SUB(w.anndats_converted, INTERVAL 1 YEAR) AND w.anndats_converted
    GROUP BY w.id) temp ON temp.analyst = w.analyst
GROUP BY w.id;

这些是我得到的结果: enter image description here