【问题标题】:Loop through each record of a table and preform calculations on all other records循环遍历表的每条记录并对所有其他记录执行计算
【发布时间】:2015-01-05 05:45:45
【问题描述】:

我想在我的表working 中计算NO_TOP_RATING 的值

NO_TOP_RATING 的计算由:

  • 对于每一行,从该记录的ANNDATS_CONVERTED 获取属于上一年的所有其他行,并且与该记录具有相同的ESTIMID
  • 从中找出最低的IRECCD 值。
  • 然后,计算相同ANALYSTIRECCD 与计算出的最低IRECCD 匹配的次数。

注意:这应该忽略正在计算的当前行(因此要找到行 id 1 的值,请不要在计算中使用该行)以及 ANALYST 为空白的任何记录完全被忽略。

working:

    | 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 计算 NO_TOP_RATING 时:

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

预期结果:

working:

| 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       |

这是我目前拥有的 MySQL:

    UPDATE `working`

SET `working`.`NO_TOP_RATING` = 


(
    SELECT COUNT(`ID`) FROM  (SELECT `ID`,`IRECCD`,`ESTIMID` FROM `working`) AS BB 

    WHERE

    `IRECCD` =                                  


            (
                SELECT COUNT(`ID`) FROM  (SELECT `ID`,`IRECCD`,`ESTIMID`, `ANALYST` FROM `working`) AS ZZ 
                WHERE

                `IRECCD` =
                            -- this calculates the LOWEST number with same `ESTIMID`
                            (

                                SELECT MIN(`IRECCD`)
                                FROM (SELECT `ID`,`IRECCD`,`ANNDATS_CONVERTED`,`ESTIMID` FROM `working`) AS CC 

                                WHERE
                                `ANNDATS_CONVERTED` >= DATE_SUB(`ANNDATS_CONVERTED`,INTERVAL 1 YEAR)
                                AND
                                `working`.`ESTIMID` = BB.`ESTIMID`

                            )
                            -- END this calculates the LOWEST number with same `ESTIMID`

                AND
                `working`.`ANALYST` = ZZ.`ANALYST`
            )




)
WHERE `working`.`ANALYST` != ''

这是在 PHP 中工作的,循环遍历每个记录并评估每个记录的所有其他记录。这涉及循环并在大型数据库上花费很长时间。我正在尝试使用 MySQL 实现相同的结果。

【问题讨论】:

  • 您能否编辑您的问题以包含您共享的示例数据的预期结果?
  • 还是有些混乱。例如,您想要在日期之后 还是 日期之前一年内的行?因此,在计算第 1 行的值时,是否应该包括第 2 行,因为它发生在第 1 行之前?
  • 谢谢@McAdam331。合格年份应 >= -1 年过去 ANNDATS_CONVERTED。所以一年前,直到ANNDATS_CONVERTED。是 - 将包括第 2 行,因为它等于或大于 1 年前。
  • 是的@McAdam331 我将编辑问题以显示预期结果。谢谢您的帮助。问候。
  • 谢谢。我有一个查询的想法,但我想确保答案是正确的。

标签: mysql sql


【解决方案1】:

我采取了几个步骤来解决这个问题。我做的第一件事是写了一个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 行)保留为空,因为这是您预期的结果:

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;

这些是我得到的结果:

【讨论】:

  • 感谢@McAdam331 您的回答。我一定会彻底解决这个问题。我真的很感谢你的时间:)
  • @Kreeverp 有什么进展吗?
  • 当我看到您的结果表为第 5 条记录生成“1”而不是为第 6 条记录生成“1”时,我有点不知所措。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-27
  • 1970-01-01
  • 2020-01-13
  • 1970-01-01
  • 2013-02-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多