MySQL: выполнение операции на разных строках в зависимости от условия? - PullRequest
1 голос
/ 30 августа 2011

Скажем, у меня есть запрос, который возвращает следующий результат:

| 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 и вычтенное значение.

Например:

| 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, поэтому, может быть, я упускаю что-то простое.

Спасибо.

Ответы [ 3 ]

2 голосов
/ 30 августа 2011
 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    |
0 голосов
/ 30 августа 2011

Может быть, вы можете сделать что-то вроде этого:

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 val, 0 as diff from
   select val
      from table
      order by i desc
      limit 1
0 голосов
/ 30 августа 2011

Вам нужна хранимая процедура с курсором на вашей таблице.Это должно быть хорошей отправной точкой.

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...