2011-08-30 91 views
1

說我有哪些返回以下結果查詢:MySQL:根據條件對不同行執行操作?

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

最後結果t應該返回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中根據不同的行執行邏輯。例如,如何根據某些條件找到最近的行,然後引用該行對其執行某些操作?有沒有可能的方式來引用當前的'我',並做一個subrtaction(行i)minus(行i-1)或類似的東西。

我已經花了很多時間在這個上,我只是要放棄,並在PHP中做,而不是性能打擊。作爲最後一招,我在這裏問是否有辦法直接在mysql中執行所有這些操作?

我不需要一個完整的解決方案,因爲這是非常複雜的要求,但我會採取任何形式的建議或指針,你可以給我。我不是MySQL最好的,所以也許我錯過了一些簡單的東西。

謝謝。

回答

2
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

當沒有人幫助你時,它總是更好:)。儘管如此,謝謝你,這是完美的。現在我只需要研究它直到對我有意義。 – nebs

0

你需要的是一個存儲過程,在你的表上有一個cursor。這應該是一個很好的起點。

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; 
+0

謝謝你的提示,將檢查了這一點。 – nebs

0

也許你可以做這樣的事情:

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