MySQL:根据条件对不同行执行操作?

发布于 2024-12-02 07:12:06 字数 1622 浏览 1 评论 0原文

假设我有一个返回以下结果的查询:

| val   |  type  | i |
----------------------
| 59    |   1    | 1 |
| 40    |   2    | 2 |
| 12    |   1    | 3 |
| 3     |   2    | 4 |
| 24    |   1    | 5 |
| 30    |   1    | 6 |
| 98    |   2    | 7 |
| 45    |   2    | 8 |
| 46    |   1    | 9 |

val = an arbitrary number
type = 1 or 2
i = auto increment column, just for reference

我想执行以下减法:

A - B

A:  Value of row of type '2'
B:  Value of row above A of type '1' if it exists, but without crossing a row of type '2'

我真的希望这是有意义的..

一些示例:

Row i=2 is of type 2.  So the first row above it of type 1 is i=1.  
So the subtraction will be:  40 - 59 = -19 

Row i=7 is of type 2.  So the first row above it of type 1 is i=6
So the subtraction will be: 98 - 30 = 68

Row i=8 is of type 2.  But if we go above we cross a value of type 2.
So the subtraction should return 0, or be ignored, whichever is simplest.

最后结果应该返回一列值,其中 type=1 和减去的 value 。

例如:

| val | diff |
--------------
| 59  | -19  |
| 12  | -9   |
| 24  | 0    |  ***
| 30  | 68   |
| 46  | 0    |  ***

*** Return diff=0 if the subtraction was never made for this row.

我有一个查询来获取我的初始表。我知道如何进行减法(在实际情况下 val 是一个日期,但在这个例子中我保持简单)。

我唯一不知道如何做的是根据 MySQL 中的不同行执行逻辑。例如,如何根据某些条件找到最近的行,然后引用该行对其执行某些操作?是否有一种方法可以引用当前的“i”并对 (i 处的行) 减去 (i-1 处的行) 或类似的操作进行减法。

我已经在这上面花了很多时间了,我正要放弃并用 php 来代替,并承受性能损失。作为最后的手段,我在这里问是否有办法直接在 mysql 中完成所有这些操作?

我不需要完整的解决方案,因为这是相当复杂的要求,但我会接受您可以给我的任何建议或指示。我不是 MySQL 方面最好的人,所以也许我错过了一些简单的东西。

谢谢。

Say I have a query which returns the following result:

| val   |  type  | i |
----------------------
| 59    |   1    | 1 |
| 40    |   2    | 2 |
| 12    |   1    | 3 |
| 3     |   2    | 4 |
| 24    |   1    | 5 |
| 30    |   1    | 6 |
| 98    |   2    | 7 |
| 45    |   2    | 8 |
| 46    |   1    | 9 |

val = an arbitrary number
type = 1 or 2
i = auto increment column, just for reference

I want to perform the following subtraction:

A - B

A:  Value of row of type '2'
B:  Value of row above A of type '1' if it exists, but without crossing a row of type '2'

I really hope that made sense..

Some examples:

Row i=2 is of type 2.  So the first row above it of type 1 is i=1.  
So the subtraction will be:  40 - 59 = -19 

Row i=7 is of type 2.  So the first row above it of type 1 is i=6
So the subtraction will be: 98 - 30 = 68

Row i=8 is of type 2.  But if we go above we cross a value of type 2.
So the subtraction should return 0, or be ignored, whichever is simplest.

In the end the result should return a column of values where type=1 and the subtracted value .

Eg:

| val | diff |
--------------
| 59  | -19  |
| 12  | -9   |
| 24  | 0    |  ***
| 30  | 68   |
| 46  | 0    |  ***

*** Return diff=0 if the subtraction was never made for this row.

I have the query for getting my initial table. I know how to do the subtraction (in the real case val is a date, but I'm keeping it simple for this example).

The only thing I have no idea how to do is perform logic based on different rows in MySQL. For example how can I find the nearest row based on some condition and then reference that row to perform some operation on it? Is there perhaps a way to reference the current 'i' and do an subrtaction on (row at i) minus (row at i-1) or something similar.

I've spent many hours on this already and I'm just about to give up and do it in php instead and take the performance hit. As a last resort I'm asking here if there's a way to do all this in mysql directly?

I don't need a full solution as this is pretty complex requirement but I will take any sort of advice or pointers you can give me. I'm not the best at MySQL so maybe I'm missing something simple.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

述情 2024-12-09 07:12:06
 SELECT t1.val AS val, IFNULL( t2.val, t1.val ) - t1.val AS diff FROM my_table AS t1
 LEFT JOIN my_table AS t2 ON( t2.type = 2 AND t2.i = t1.i + 1 )
 WHERE t1.type = 1 ORDER BY t1.i;

对您的数据进行测试,结果:

| val | diff |
--------------
| 59  | -19  |
| 12  | -9   |
| 24  | 0    |
| 30  | 68   |
| 46  | 0    |
 SELECT t1.val AS val, IFNULL( t2.val, t1.val ) - t1.val AS diff FROM my_table AS t1
 LEFT JOIN my_table AS t2 ON( t2.type = 2 AND t2.i = t1.i + 1 )
 WHERE t1.type = 1 ORDER BY t1.i;

Tested on your data, result:

| val | diff |
--------------
| 59  | -19  |
| 12  | -9   |
| 24  | 0    |
| 30  | 68   |
| 46  | 0    |
长安忆 2024-12-09 07:12:06

您需要的是一个存储过程,其表上有一个 光标 。这应该是一个很好的起点。

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE val, type, prev_val, prev_type INT;
  DECLARE cur1 CURSOR FOR SELECT val, type, i from your_table;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  OPEN cur1;

  read_loop: LOOP
    FETCH cur1 INTO val, tpye, i;
    IF done THEN
      LEAVE read_loop;
    END IF;

    -- your logic goes here, sorry, not sure I understood correctly, but roughly here it goes
    IF type = 2 THEN
      IF prev_type is not null and prev_type = 1 THEN
        INSERT INTO result_table VALUES (prev_val, val - prev_val);
      END IF;
    END IF;
    SET prev_val = val;
    SET prev_type = type;
  END LOOP;

  CLOSE cur1;
END;

What you need is a stored procedure with a cursor on your table. This should be a good starting pont.

CREATE PROCEDURE curdemo()
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE val, type, prev_val, prev_type INT;
  DECLARE cur1 CURSOR FOR SELECT val, type, i from your_table;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  OPEN cur1;

  read_loop: LOOP
    FETCH cur1 INTO val, tpye, i;
    IF done THEN
      LEAVE read_loop;
    END IF;

    -- your logic goes here, sorry, not sure I understood correctly, but roughly here it goes
    IF type = 2 THEN
      IF prev_type is not null and prev_type = 1 THEN
        INSERT INTO result_table VALUES (prev_val, val - prev_val);
      END IF;
    END IF;
    SET prev_val = val;
    SET prev_type = type;
  END LOOP;

  CLOSE cur1;
END;
落花浅忆 2024-12-09 07:12:06

也许你可以做这样的事情:

select t1.val, (t1.val - t2.val) as diff
     from table as t1, table as t2
     where t1.i = t2.i + 1 
       and t1.type = 1
       and t2.type = 2

要选择零,你可以做这样的黑客:

select t1.val, (t1.val - t2.val)*(t2.type - t1.type) as diff
     from table as t1, table as t2
     where t1.i = t2.i + 1 
       and t1.type = 1

当有一个时得到最后一个零,加入:

select val, 0 as diff from
   select val
      from table
      order by i desc
      limit 1

Maybe you can do something like this:

select t1.val, (t1.val - t2.val) as diff
     from table as t1, table as t2
     where t1.i = t2.i + 1 
       and t1.type = 1
       and t2.type = 2

to select with zeros you can do a hack like this:

select t1.val, (t1.val - t2.val)*(t2.type - t1.type) as diff
     from table as t1, table as t2
     where t1.i = t2.i + 1 
       and t1.type = 1

to get the last zero when there is one, join with:

select val, 0 as diff from
   select val
      from table
      order by i desc
      limit 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文